diff options
author | David Howells <dhowells@redhat.com> | 2019-05-14 12:23:43 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-16 22:23:21 +0100 |
commit | b8359153252d4465cb74f8de6c50e8c6295cbe2e (patch) | |
tree | 5ec539b6936cde10dc725cbc90acff2220c0f814 | |
parent | a38a75581e6e2f783e7b8658e9ca5d4243279f55 (diff) |
afs: Pass pre-fetch server and volume break counts into afs_iget5_set()
Pass the server and volume break counts from before the status fetch
operation that queried the attributes of a file into afs_iget5_set() so
that the new vnode's break counters can be initialised appropriately.
This allows detection of a volume or server break that happened whilst we
were fetching the status or setting up the vnode.
Fixes: c435ee34551e ("afs: Overhaul the callback handling")
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/dir.c | 58 | ||||
-rw-r--r-- | fs/afs/inode.c | 51 | ||||
-rw-r--r-- | fs/afs/internal.h | 4 | ||||
-rw-r--r-- | fs/afs/super.c | 14 |
4 files changed, 78 insertions, 49 deletions
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index d1b3736a3bbd..9e42f6c75747 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -641,7 +641,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct afs_cb_interest *dcbi, *cbi = NULL; struct afs_super_info *as = dir->i_sb->s_fs_info; struct afs_status_cb *scb; - struct afs_iget_data data; + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_server *server; struct afs_vnode *dvnode = AFS_FS_I(dir); @@ -684,9 +684,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, goto out; /* Check to see if we already have an inode for the primary fid. */ - data.volume = dvnode->volume; - data.fid = cookie->fids[0]; - inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data); + iget_data.fid = cookie->fids[0]; + iget_data.volume = dvnode->volume; + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = 0; + inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, + afs_iget5_test, &iget_data); if (inode) goto out; @@ -713,6 +716,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, fc.ac.error = -ECONNABORTED; break; } + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = fc.cbi->server->cb_s_break; afs_fs_inline_bulk_status(&fc, afs_v2net(dvnode), cookie->fids, @@ -741,6 +746,8 @@ no_inline_bulk_status: inode = ERR_PTR(-ERESTARTSYS); if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { while (afs_select_fileserver(&fc)) { + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = fc.cbi->server->cb_s_break; scb = &cookie->statuses[0]; afs_fs_fetch_status(&fc, afs_v2net(dvnode), @@ -775,8 +782,8 @@ success: if (scb->status.abort_code != 0) continue; - ti = afs_iget(dir->i_sb, key, &cookie->fids[i], - scb, cbi, dvnode); + iget_data.fid = cookie->fids[i]; + ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); if (i == 0) { inode = ti; } else { @@ -1112,7 +1119,7 @@ void afs_d_release(struct dentry *dentry) */ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, struct dentry *new_dentry, - struct afs_fid *newfid, + struct afs_iget_data *new_data, struct afs_status_cb *new_scb) { struct afs_vnode *vnode; @@ -1122,7 +1129,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, return; inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key, - newfid, new_scb, fc->cbi, fc->vnode); + new_data, new_scb, fc->cbi, fc->vnode); if (IS_ERR(inode)) { /* ENOMEM or EINTR at a really inconvenient time - just abandon * the new directory on the server. @@ -1138,15 +1145,23 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, d_instantiate(new_dentry, inode); } +static void afs_prep_for_new_inode(struct afs_fs_cursor *fc, + struct afs_iget_data *iget_data) +{ + iget_data->volume = fc->vnode->volume; + iget_data->cb_v_break = fc->vnode->volume->cb_v_break; + iget_data->cb_s_break = fc->cbi->server->cb_s_break; +} + /* * create a directory on an AFS filesystem */ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { + struct afs_iget_data iget_data; struct afs_status_cb *scb; struct afs_fs_cursor fc; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1172,14 +1187,15 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_create(&fc, dentry->d_name.name, mode, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1189,7 +1205,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (ret == 0 && test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_create); key_put(key); @@ -1439,10 +1455,10 @@ error: static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1472,14 +1488,15 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_create(&fc, dentry->d_name.name, mode, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1488,7 +1505,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, } if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_create); kfree(scb); @@ -1595,10 +1612,10 @@ error: static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content) { + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1631,14 +1648,15 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_symlink(&fc, dentry->d_name.name, content, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1647,7 +1665,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, } if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_symlink); key_put(key); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index e1a523d2e378..b42d9d09669c 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -347,10 +347,10 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new, */ int afs_iget5_test(struct inode *inode, void *opaque) { - struct afs_iget_data *data = opaque; + struct afs_iget_data *iget_data = opaque; struct afs_vnode *vnode = AFS_FS_I(inode); - return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0; + return memcmp(&vnode->fid, &iget_data->fid, sizeof(iget_data->fid)) == 0; } /* @@ -368,17 +368,19 @@ static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque) */ static int afs_iget5_set(struct inode *inode, void *opaque) { - struct afs_iget_data *data = opaque; + struct afs_iget_data *iget_data = opaque; struct afs_vnode *vnode = AFS_FS_I(inode); - vnode->fid = data->fid; - vnode->volume = data->volume; + vnode->fid = iget_data->fid; + vnode->volume = iget_data->volume; + vnode->cb_v_break = iget_data->cb_v_break; + vnode->cb_s_break = iget_data->cb_s_break; /* YFS supports 96-bit vnode IDs, but Linux only supports * 64-bit inode numbers. */ - inode->i_ino = data->fid.vnode; - inode->i_generation = data->fid.unique; + inode->i_ino = iget_data->fid.vnode; + inode->i_generation = iget_data->fid.unique; return 0; } @@ -388,38 +390,42 @@ static int afs_iget5_set(struct inode *inode, void *opaque) */ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) { - struct afs_iget_data data; struct afs_super_info *as; struct afs_vnode *vnode; struct inode *inode; static atomic_t afs_autocell_ino; + struct afs_iget_data iget_data = { + .cb_v_break = 0, + .cb_s_break = 0, + }; + _enter(""); as = sb->s_fs_info; if (as->volume) { - data.volume = as->volume; - data.fid.vid = as->volume->vid; + iget_data.volume = as->volume; + iget_data.fid.vid = as->volume->vid; } if (root) { - data.fid.vnode = 1; - data.fid.unique = 1; + iget_data.fid.vnode = 1; + iget_data.fid.unique = 1; } else { - data.fid.vnode = atomic_inc_return(&afs_autocell_ino); - data.fid.unique = 0; + iget_data.fid.vnode = atomic_inc_return(&afs_autocell_ino); + iget_data.fid.unique = 0; } - inode = iget5_locked(sb, data.fid.vnode, + inode = iget5_locked(sb, iget_data.fid.vnode, afs_iget5_pseudo_dir_test, afs_iget5_set, - &data); + &iget_data); if (!inode) { _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", - inode, inode->i_ino, data.fid.vid, data.fid.vnode, - data.fid.unique); + inode, inode->i_ino, iget_data.fid.vid, iget_data.fid.vnode, + iget_data.fid.unique); vnode = AFS_FS_I(inode); @@ -490,23 +496,24 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) * inode retrieval */ struct inode *afs_iget(struct super_block *sb, struct key *key, - struct afs_fid *fid, struct afs_status_cb *scb, + struct afs_iget_data *iget_data, + struct afs_status_cb *scb, struct afs_cb_interest *cbi, struct afs_vnode *parent_vnode) { - struct afs_iget_data data = { .fid = *fid }; struct afs_super_info *as; struct afs_vnode *vnode; + struct afs_fid *fid = &iget_data->fid; struct inode *inode; int ret; _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); as = sb->s_fs_info; - data.volume = as->volume; + iget_data->volume = as->volume; inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, - &data); + iget_data); if (!inode) { _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f80ca638e70f..2073c1a3ab4b 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -66,6 +66,8 @@ struct afs_fs_context { struct afs_iget_data { struct afs_fid fid; struct afs_volume *volume; /* volume on which resides */ + unsigned int cb_v_break; /* Pre-fetch volume break count */ + unsigned int cb_s_break; /* Pre-fetch server break count */ }; enum afs_call_state { @@ -1023,7 +1025,7 @@ extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t extern int afs_iget5_test(struct inode *, void *); extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); extern struct inode *afs_iget(struct super_block *, struct key *, - struct afs_fid *, struct afs_status_cb *, + struct afs_iget_data *, struct afs_status_cb *, struct afs_cb_interest *, struct afs_vnode *); extern void afs_zap_data(struct afs_vnode *); diff --git a/fs/afs/super.c b/fs/afs/super.c index f76473ad7bbb..f18911e8d770 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -426,7 +426,7 @@ static int afs_set_super(struct super_block *sb, struct fs_context *fc) static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) { struct afs_super_info *as = AFS_FS_S(sb); - struct afs_fid fid; + struct afs_iget_data iget_data; struct inode *inode = NULL; int ret; @@ -451,11 +451,13 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) } else { sprintf(sb->s_id, "%llu", as->volume->vid); afs_activate_volume(as->volume); - fid.vid = as->volume->vid; - fid.vnode = 1; - fid.vnode_hi = 0; - fid.unique = 1; - inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); + iget_data.fid.vid = as->volume->vid; + iget_data.fid.vnode = 1; + iget_data.fid.vnode_hi = 0; + iget_data.fid.unique = 1; + iget_data.cb_v_break = as->volume->cb_v_break; + iget_data.cb_s_break = 0; + inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL); } if (IS_ERR(inode)) |