From 87ab27beb119d394766bd7c902ab71ec8c00f148 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 9 Aug 2017 14:54:30 -0700 Subject: [PATCH] scoutfs: add statfs network message The ->statfs method was still using the super_block in the super_info that was read during mount. This will get progressively more out of date. We add a network message to ask the server for the current fields that impact statfs. This is always racy and the fields are mostly nonsense, but we try our best. Signed-off-by: Zach Brown --- kmod/src/client.c | 9 +++++++++ kmod/src/client.h | 2 ++ kmod/src/format.h | 8 ++++++++ kmod/src/server.c | 34 ++++++++++++++++++++++++++++++++++ kmod/src/super.c | 26 ++++++++++++++++++-------- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/kmod/src/client.c b/kmod/src/client.c index 49293be1..628cca99 100644 --- a/kmod/src/client.c +++ b/kmod/src/client.c @@ -681,6 +681,15 @@ int scoutfs_client_get_manifest_root(struct super_block *sb, NULL, 0, root, sizeof(struct scoutfs_btree_root)); } +int scoutfs_client_statfs(struct super_block *sb, + struct scoutfs_net_statfs *nstatfs) +{ + struct client_info *client = SCOUTFS_SB(sb)->client_info; + + return client_request(client, SCOUTFS_NET_STATFS, NULL, 0, nstatfs, + sizeof(struct scoutfs_net_statfs)); +} + int scoutfs_client_setup(struct super_block *sb) { struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); diff --git a/kmod/src/client.h b/kmod/src/client.h index 59b7b151..71c8c4eb 100644 --- a/kmod/src/client.h +++ b/kmod/src/client.h @@ -10,6 +10,8 @@ int scoutfs_client_advance_seq(struct super_block *sb, u64 *seq); int scoutfs_client_get_last_seq(struct super_block *sb, u64 *seq); int scoutfs_client_get_manifest_root(struct super_block *sb, struct scoutfs_btree_root *root); +int scoutfs_client_statfs(struct super_block *sb, + struct scoutfs_net_statfs *nstatfs); int scoutfs_client_setup(struct super_block *sb); void scoutfs_client_destroy(struct super_block *sb); diff --git a/kmod/src/format.h b/kmod/src/format.h index 6c37816d..b532cccc 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -571,6 +571,13 @@ struct scoutfs_net_segnos { __le64 segnos[0]; } __packed; +struct scoutfs_net_statfs { + __le64 total_segs; /* total segments in device */ + __le64 next_ino; /* next unused inode number */ + __le64 bfree; /* total free small blocks */ + __u8 uuid[SCOUTFS_UUID_BYTES]; /* logical volume uuid */ +} __packed; + /* XXX eventually we'll have net compaction and will need agents to agree */ /* one upper segment and fanout lower segments */ @@ -589,6 +596,7 @@ enum { SCOUTFS_NET_ADVANCE_SEQ, SCOUTFS_NET_GET_LAST_SEQ, SCOUTFS_NET_GET_MANIFEST_ROOT, + SCOUTFS_NET_STATFS, SCOUTFS_NET_UNKNOWN, }; diff --git a/kmod/src/server.c b/kmod/src/server.c index c02a5d21..427a6463 100644 --- a/kmod/src/server.c +++ b/kmod/src/server.c @@ -581,6 +581,39 @@ static int process_get_manifest_root(struct server_connection *conn, u64 id, return send_reply(conn, id, type, ret, &root, sizeof(root)); } +/* + * Sample the super stats that the client wants for statfs by serializing + * with each component. + */ +static int process_statfs(struct server_connection *conn, u64 id, u8 type, + void *data, unsigned data_len) +{ + struct server_info *server = conn->server; + struct super_block *sb = server->sb; + struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); + struct scoutfs_super_block *super = &sbi->super; + struct scoutfs_net_statfs nstatfs; + int ret; + + if (data_len == 0) { + /* uuid and total_segs are constant, so far */ + memcpy(nstatfs.uuid, super->uuid, sizeof(nstatfs.uuid)); + nstatfs.total_segs = super->total_segs; + + spin_lock(&sbi->next_ino_lock); + nstatfs.next_ino = super->next_ino; + spin_unlock(&sbi->next_ino_lock); + + /* alloc locks the bfree calculation */ + nstatfs.bfree = cpu_to_le64(scoutfs_alloc_bfree(sb)); + ret = 0; + } else { + ret = -EINVAL; + } + + return send_reply(conn, id, type, ret, &nstatfs, sizeof(nstatfs)); +} + /* * Eventually we're going to have messages that control compaction. * Each client mount would have long-lived work that sends requests @@ -692,6 +725,7 @@ static void scoutfs_server_process_func(struct work_struct *work) [SCOUTFS_NET_ADVANCE_SEQ] = process_advance_seq, [SCOUTFS_NET_GET_LAST_SEQ] = process_get_last_seq, [SCOUTFS_NET_GET_MANIFEST_ROOT] = process_get_manifest_root, + [SCOUTFS_NET_STATFS] = process_statfs, }; struct scoutfs_net_header *nh = &req->nh; process_func_t func; diff --git a/kmod/src/super.c b/kmod/src/super.c index 5e0604da..34c0835a 100644 --- a/kmod/src/super.c +++ b/kmod/src/super.c @@ -44,6 +44,11 @@ static struct kset *scoutfs_kset; /* + * Ask the server for the current statfs fields. The message is very + * cheap so we're not worrying about spinning in statfs flooding the + * server with requests. We can add a cache and stale results if that + * becomes a problem. + * * We fake the number of free inodes value by assuming that we can fill * free blocks with a certain number of inodes. We then the number of * current inodes to that free count to determine the total possible @@ -55,20 +60,25 @@ static struct kset *scoutfs_kset; static int scoutfs_statfs(struct dentry *dentry, struct kstatfs *kst) { struct super_block *sb = dentry->d_inode->i_sb; - struct scoutfs_sb_info *sbi = SCOUTFS_SB(sb); - struct scoutfs_super_block *super = &sbi->super; - __le32 * __packed uuid = (void *)super->uuid; + struct scoutfs_net_statfs nstatfs; + __le32 * __packed uuid; + int ret; - kst->f_bfree = scoutfs_alloc_bfree(sb); + ret = scoutfs_client_statfs(sb, &nstatfs); + if (ret) + return ret; + + kst->f_bfree = le64_to_cpu(nstatfs.bfree); kst->f_type = SCOUTFS_SUPER_MAGIC; kst->f_bsize = SCOUTFS_BLOCK_SIZE; - kst->f_blocks = le64_to_cpu(super->total_segs) * SCOUTFS_SEGMENT_BLOCKS; + kst->f_blocks = le64_to_cpu(nstatfs.total_segs) * + SCOUTFS_SEGMENT_BLOCKS; kst->f_bavail = kst->f_bfree; - kst->f_ffree = kst->f_bfree * 17; - kst->f_files = kst->f_ffree + scoutfs_last_ino(sb); + kst->f_ffree = kst->f_bfree * 16; + kst->f_files = kst->f_ffree + le64_to_cpu(nstatfs.next_ino); - /* this fsid is constant.. the uuid is different */ + uuid = (void *)nstatfs.uuid; kst->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[1]); kst->f_fsid.val[1] = le32_to_cpu(uuid[2]) ^ le32_to_cpu(uuid[3]); kst->f_namelen = SCOUTFS_NAME_LEN;