afs: Fix missing subdir edit when renamed between parent dirs
Subsystems (3)
David Howells
maintainerPATCH v2 1/1 afs: Fix missing subdir edit when renamed between parent dirs
When rename moves an AFS subdirectory between parent directories, the subdir also needs a bit of editing: the ".." entry needs updating to point to the new parent (though I don't make use of the info) and the DV needs incrementing by 1 to reflect the change of content. The server also sends a callback break notification on the subdirectory if we have one, but we can take care of recovering the promise next time we access the subdir.
This can be triggered by something like:
mount -t afs %example.com:xfstest.test20 /xfstest.test/
mkdir /xfstest.test/{aaa,bbb,aaa/ccc}
touch /xfstest.test/bbb/ccc/d
mv /xfstest.test/{aaa/ccc,bbb/ccc}
touch /xfstest.test/bbb/ccc/eWhen the pathwalk for the second touch hits "ccc", kafs spots that the DV is incorrect and downloads it again (so the fix is not critical).
Fix this, if the rename target is a directory and the old and new parents are different, by:
(1) Incrementing the DV number of the target locally.
(2) Editing the ".." entry in the target to refer to its new parent's vnode ID and uniquifier.
---
Changes
=======
ver #2)
- Improved the example test in the description.
- Removed some extraneous whitespace.
fs/afs/dir.c | 25 ++++++++++++ fs/afs/dir_edit.c | 91 ++++++++++++++++++++++++++++++++++++++++++++- fs/afs/internal.h | 2 include/trace/events/afs.h | 7 ++- 4 files changed, 122 insertions(+), 3 deletions(-)
fs/afs/dir.c +25 -0
@@ -12,6 +12,7 @@#include <linux/swap.h> #include <linux/ctype.h> #include <linux/sched.h> +#include <linux/iversion.h> #include <linux/task_io_accounting_ops.h> #include "internal.h" #include "afs_fs.h"
@@ -1823,6 +1824,8 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,static void afs_rename_success (struct afs_operation *op) { +struct afs_vnode *vnode =AFS_FS_I (d_inode (op->dentry)); +_enter ("op=%08x" , op->debug_id); op->ctime = op->file[0 ].scb.status.mtime_client;
@@ -1832,6 +1835,22 @@ static void afs_rename_success(struct afs_operation *op) op->ctime = op->file[1 ].scb.status.mtime_client;afs_vnode_commit_status (op, &op->file[1 ]); } + +/* If we're moving a subdir between dirs, we need to update +* its DV counter too as the ".." will be altered. +*/ +if (S_ISDIR (vnode->netfs.inode.i_mode) && + op->file[0 ].vnode != op->file[1 ].vnode) { +u64 new_dv; + +write_seqlock (&vnode->cb_lock); + + new_dv = vnode->status.data_version +1 ; + vnode->status.data_version = new_dv; +inode_set_iversion_raw (&vnode->netfs.inode, new_dv); + +write_sequnlock (&vnode->cb_lock); + } }static void afs_rename_edit_dir (struct afs_operation *op)
@@ -1873,6 +1892,12 @@ static void afs_rename_edit_dir(struct afs_operation *op) &vnode->fid, afs_edit_dir_for_rename_2); } +if (S_ISDIR (vnode->netfs.inode.i_mode) && + new_dvnode != orig_dvnode && +test_bit (AFS_VNODE_DIR_VALID , &vnode->flags)) +afs_edit_dir_update_dotdot (vnode, new_dvnode, + afs_edit_dir_for_rename_sub); + new_inode =d_inode (new_dentry);if (new_inode) {spin_lock (&new_inode->i_lock);
fs/afs/dir_edit.c +89 -2
102 lines not on this page · raw message
fs/afs/internal.h +2 -0
@@ -1073,6 +1073,8 @@ extern void afs_check_for_remote_deletion(struct afs_operation *);extern void afs_edit_dir_add (struct afs_vnode *,struct qstr *,struct afs_fid *,enum afs_edit_dir_reason );extern void afs_edit_dir_remove (struct afs_vnode *,struct qstr *,enum afs_edit_dir_reason ); +void afs_edit_dir_update_dotdot (struct afs_vnode *vnode,struct afs_vnode *new_dvnode, +enum afs_edit_dir_reason why);/* * dir_silly.c
include/trace/events/afs.h +6 -1
@@ -331,7 +331,11 @@ enum yfs_cm_operation { EM(afs_edit_dir_delete, "delete") \ EM(afs_edit_dir_delete_error, "d_err ") \ EM(afs_edit_dir_delete_inval, "d_invl") \ - E_(afs_edit_dir_delete_noent, "d_nent") + EM(afs_edit_dir_delete_noent, "d_nent") \ + EM(afs_edit_dir_update_dd, "u_ddot") \ + EM(afs_edit_dir_update_error, "u_fail") \ + EM(afs_edit_dir_update_inval, "u_invl") \ + E_(afs_edit_dir_update_nodd, "u_nodd")#define afs_edit_dir_reasons \ EM(afs_edit_dir_for_create, "Create") \
@@ -340,6 +344,7 @@ enum yfs_cm_operation { EM(afs_edit_dir_for_rename_0, "Renam0") \ EM(afs_edit_dir_for_rename_1, "Renam1") \ EM(afs_edit_dir_for_rename_2, "Renam2") \ + EM(afs_edit_dir_for_rename_sub, "RnmSub") \ EM(afs_edit_dir_for_rmdir, "RmDir ") \ EM(afs_edit_dir_for_silly_0, "S_Ren0") \EM (afs_edit_dir_for_silly_1,"S_Ren1" ) \
David Howells
maintainerQuoted 1 line · David Howells
cc David Howells <[email protected]>
That should, of course, be: