1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* AFS silly rename handling
4 * Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 * - Derived from NFS's sillyrename.
9 #include <linux/kernel.h>
11 #include <linux/namei.h>
12 #include <linux/fsnotify.h>
16 * Actually perform the silly rename step.
18 static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
19 struct dentry *old, struct dentry *new,
22 struct afs_fs_cursor fc;
23 struct afs_status_cb *scb;
24 int ret = -ERESTARTSYS;
26 _enter("%pd,%pd", old, new);
28 scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
32 trace_afs_silly_rename(vnode, false);
33 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
34 afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
36 while (afs_select_fileserver(&fc)) {
37 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
38 afs_fs_rename(&fc, old->d_name.name,
39 dvnode, new->d_name.name,
43 afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
44 &dir_data_version, scb);
45 ret = afs_end_vnode_operation(&fc);
49 spin_lock(&old->d_lock);
50 old->d_flags |= DCACHE_NFSFS_RENAMED;
51 spin_unlock(&old->d_lock);
52 if (dvnode->silly_key != key) {
53 key_put(dvnode->silly_key);
54 dvnode->silly_key = key_get(key);
57 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
58 afs_edit_dir_remove(dvnode, &old->d_name,
59 afs_edit_dir_for_silly_0);
60 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
61 afs_edit_dir_add(dvnode, &new->d_name,
62 &vnode->fid, afs_edit_dir_for_silly_1);
64 /* vfs_unlink and the like do not issue this when a file is
65 * sillyrenamed, so do it here.
67 fsnotify_nameremove(old, 0);
76 * afs_sillyrename - Perform a silly-rename of a dentry
78 * AFS is stateless and the server doesn't know when the client is holding a
79 * file open. To prevent application problems when a file is unlinked while
80 * it's still open, the client performs a "silly-rename". That is, it renames
81 * the file to a hidden file in the same directory, and only performs the
82 * unlink once the last reference to it is put.
84 * The final cleanup is done during dentry_iput.
86 int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
87 struct dentry *dentry, struct key *key)
89 static unsigned int sillycounter;
90 struct dentry *sdentry = NULL;
91 unsigned char silly[16];
96 /* We don't allow a dentry to be silly-renamed twice. */
97 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
107 /* Create a silly name. Note that the ".__afs" prefix is
108 * understood by the salvager and must not be changed.
110 slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
111 sdentry = lookup_one_len(silly, dentry->d_parent, slen);
113 /* N.B. Better to return EBUSY here ... it could be dangerous
114 * to delete the file while it's in use.
118 } while (!d_is_negative(sdentry));
120 ihold(&vnode->vfs_inode);
122 ret = afs_do_silly_rename(dvnode, vnode, dentry, sdentry, key);
125 /* The rename succeeded. */
126 d_move(dentry, sdentry);
129 /* The result of the rename is unknown. Play it safe by forcing
136 iput(&vnode->vfs_inode);
139 _leave(" = %d", ret);
144 * Tell the server to remove a sillyrename file.
146 static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode,
147 struct dentry *dentry, struct key *key)
149 struct afs_fs_cursor fc;
150 struct afs_status_cb *scb;
151 int ret = -ERESTARTSYS;
155 scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
159 trace_afs_silly_rename(vnode, true);
160 if (afs_begin_vnode_operation(&fc, dvnode, key, false)) {
161 afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
163 while (afs_select_fileserver(&fc)) {
164 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
166 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
167 !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
168 yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
170 if (fc.ac.error != -ECONNABORTED ||
171 fc.ac.abort_code != RXGEN_OPCODE)
173 set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
176 afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]);
179 afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
180 &dir_data_version, &scb[0]);
181 ret = afs_end_vnode_operation(&fc);
183 drop_nlink(&vnode->vfs_inode);
184 if (vnode->vfs_inode.i_nlink == 0) {
185 set_bit(AFS_VNODE_DELETED, &vnode->flags);
186 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
190 test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
191 afs_edit_dir_remove(dvnode, &dentry->d_name,
192 afs_edit_dir_for_unlink);
196 _leave(" = %d", ret);
201 * Remove sillyrename file on iput.
203 int afs_silly_iput(struct dentry *dentry, struct inode *inode)
205 struct afs_vnode *dvnode = AFS_FS_I(d_inode(dentry->d_parent));
206 struct afs_vnode *vnode = AFS_FS_I(inode);
207 struct dentry *alias;
210 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
212 _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode);
214 down_read(&dvnode->rmdir_lock);
216 alias = d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq);
218 up_read(&dvnode->rmdir_lock);
222 if (!d_in_lookup(alias)) {
223 /* We raced with lookup... See if we need to transfer the
224 * sillyrename information to the aliased dentry.
227 spin_lock(&alias->d_lock);
228 if (d_really_is_positive(alias) &&
229 !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
230 alias->d_flags |= DCACHE_NFSFS_RENAMED;
233 spin_unlock(&alias->d_lock);
234 up_read(&dvnode->rmdir_lock);
239 /* Stop lock-release from complaining. */
240 spin_lock(&vnode->lock);
241 vnode->lock_state = AFS_VNODE_LOCK_DELETED;
242 trace_afs_flock_ev(vnode, NULL, afs_flock_silly_delete, 0);
243 spin_unlock(&vnode->lock);
245 afs_do_silly_unlink(dvnode, vnode, dentry, dvnode->silly_key);
246 up_read(&dvnode->rmdir_lock);
247 d_lookup_done(alias);