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 <zab@versity.com>
This commit is contained in:
Zach Brown
2017-08-11 10:43:35 -07:00
committed by Zach Brown
parent ba7bde30fc
commit 87ab27beb1
5 changed files with 71 additions and 8 deletions
+9
View File
@@ -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);
+2
View File
@@ -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);
+8
View File
@@ -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,
};
+34
View File
@@ -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;
+18 -8
View File
@@ -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;