1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* AFS silly rename handling 3 * 4 * Copyright (C) 2019 Red Hat, Inc. All Rights Reserved. 5 * Written by David Howells (dhowells@redhat.com) 6 * - Derived from NFS's sillyrename. 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/fs.h> 11 #include <linux/namei.h> 12 #include <linux/fsnotify.h> 13 #include "internal.h" 14 15 static void afs_silly_rename_success(struct afs_operation *op) 16 { 17 _enter("op=%08x", op->debug_id); 18 19 afs_check_dir_conflict(op, &op->file[0]); 20 afs_vnode_commit_status(op, &op->file[0]); 21 } 22 23 static void afs_silly_rename_edit_dir(struct afs_operation *op) 24 { 25 struct afs_vnode_param *dvp = &op->file[0]; 26 struct afs_vnode *dvnode = dvp->vnode; 27 struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry)); 28 struct dentry *old = op->dentry; 29 struct dentry *new = op->dentry_2; 30 31 spin_lock(&old->d_lock); 32 old->d_flags |= DCACHE_NFSFS_RENAMED; 33 spin_unlock(&old->d_lock); 34 if (dvnode->silly_key != op->key) { 35 key_put(dvnode->silly_key); 36 dvnode->silly_key = key_get(op->key); 37 } 38 39 down_write(&dvnode->validate_lock); 40 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 41 dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) { 42 afs_edit_dir_remove(dvnode, &old->d_name, 43 afs_edit_dir_for_silly_0); 44 afs_edit_dir_add(dvnode, &new->d_name, 45 &vnode->fid, afs_edit_dir_for_silly_1); 46 } 47 up_write(&dvnode->validate_lock); 48 } 49 50 static const struct afs_operation_ops afs_silly_rename_operation = { 51 .issue_afs_rpc = afs_fs_rename, 52 .issue_yfs_rpc = yfs_fs_rename, 53 .success = afs_silly_rename_success, 54 .edit_dir = afs_silly_rename_edit_dir, 55 }; 56 57 /* 58 * Actually perform the silly rename step. 59 */ 60 static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode, 61 struct dentry *old, struct dentry *new, 62 struct key *key) 63 { 64 struct afs_operation *op; 65 66 _enter("%pd,%pd", old, new); 67 68 op = afs_alloc_operation(key, dvnode->volume); 69 if (IS_ERR(op)) 70 return PTR_ERR(op); 71 72 op->more_files = kvcalloc(2, sizeof(struct afs_vnode_param), GFP_KERNEL); 73 if (!op->more_files) { 74 afs_put_operation(op); 75 return -ENOMEM; 76 } 77 78 afs_op_set_vnode(op, 0, dvnode); 79 afs_op_set_vnode(op, 1, dvnode); 80 op->file[0].dv_delta = 1; 81 op->file[1].dv_delta = 1; 82 op->file[0].modification = true; 83 op->file[1].modification = true; 84 op->file[0].update_ctime = true; 85 op->file[1].update_ctime = true; 86 op->more_files[0].vnode = AFS_FS_I(d_inode(old)); 87 op->more_files[0].speculative = true; 88 op->more_files[1].vnode = AFS_FS_I(d_inode(new)); 89 op->more_files[1].speculative = true; 90 op->nr_files = 4; 91 92 op->dentry = old; 93 op->dentry_2 = new; 94 op->ops = &afs_silly_rename_operation; 95 96 trace_afs_silly_rename(vnode, false); 97 return afs_do_sync_operation(op); 98 } 99 100 /* 101 * Perform silly-rename of a dentry. 102 * 103 * AFS is stateless and the server doesn't know when the client is holding a 104 * file open. To prevent application problems when a file is unlinked while 105 * it's still open, the client performs a "silly-rename". That is, it renames 106 * the file to a hidden file in the same directory, and only performs the 107 * unlink once the last reference to it is put. 108 * 109 * The final cleanup is done during dentry_iput. 110 */ 111 int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode, 112 struct dentry *dentry, struct key *key) 113 { 114 static unsigned int sillycounter; 115 struct dentry *sdentry = NULL; 116 unsigned char silly[16]; 117 int ret = -EBUSY; 118 119 _enter(""); 120 121 /* We don't allow a dentry to be silly-renamed twice. */ 122 if (dentry->d_flags & DCACHE_NFSFS_RENAMED) 123 return -EBUSY; 124 125 sdentry = NULL; 126 do { 127 dput(sdentry); 128 sillycounter++; 129 130 /* Create a silly name. Note that the ".__afs" prefix is 131 * understood by the salvager and must not be changed. 132 */ 133 scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter); 134 sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent); 135 136 /* N.B. Better to return EBUSY here ... it could be dangerous 137 * to delete the file while it's in use. 138 */ 139 if (IS_ERR(sdentry)) 140 goto out; 141 } while (!d_is_negative(sdentry)); 142 143 ihold(&vnode->netfs.inode); 144 145 ret = afs_do_silly_rename(dvnode, vnode, dentry, sdentry, key); 146 switch (ret) { 147 case 0: 148 /* The rename succeeded. */ 149 set_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags); 150 d_move(dentry, sdentry); 151 break; 152 case -ERESTARTSYS: 153 /* The result of the rename is unknown. Play it safe by forcing 154 * a new lookup. 155 */ 156 d_drop(dentry); 157 d_drop(sdentry); 158 } 159 160 iput(&vnode->netfs.inode); 161 dput(sdentry); 162 out: 163 _leave(" = %d", ret); 164 return ret; 165 } 166 167 static void afs_silly_unlink_success(struct afs_operation *op) 168 { 169 _enter("op=%08x", op->debug_id); 170 afs_check_dir_conflict(op, &op->file[0]); 171 afs_vnode_commit_status(op, &op->file[0]); 172 afs_vnode_commit_status(op, &op->file[1]); 173 afs_update_dentry_version(op, &op->file[0], op->dentry); 174 } 175 176 static void afs_silly_unlink_edit_dir(struct afs_operation *op) 177 { 178 struct afs_vnode_param *dvp = &op->file[0]; 179 struct afs_vnode *dvnode = dvp->vnode; 180 181 _enter("op=%08x", op->debug_id); 182 down_write(&dvnode->validate_lock); 183 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && 184 dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) 185 afs_edit_dir_remove(dvnode, &op->dentry->d_name, 186 afs_edit_dir_for_unlink); 187 up_write(&dvnode->validate_lock); 188 } 189 190 static const struct afs_operation_ops afs_silly_unlink_operation = { 191 .issue_afs_rpc = afs_fs_remove_file, 192 .issue_yfs_rpc = yfs_fs_remove_file, 193 .success = afs_silly_unlink_success, 194 .aborted = afs_check_for_remote_deletion, 195 .edit_dir = afs_silly_unlink_edit_dir, 196 }; 197 198 /* 199 * Tell the server to remove a sillyrename file. 200 */ 201 static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode, 202 struct dentry *dentry, struct key *key) 203 { 204 struct afs_operation *op; 205 206 _enter(""); 207 208 op = afs_alloc_operation(NULL, dvnode->volume); 209 if (IS_ERR(op)) 210 return PTR_ERR(op); 211 212 afs_op_set_vnode(op, 0, dvnode); 213 afs_op_set_vnode(op, 1, vnode); 214 op->file[0].dv_delta = 1; 215 op->file[0].modification = true; 216 op->file[0].update_ctime = true; 217 op->file[1].op_unlinked = true; 218 op->file[1].update_ctime = true; 219 220 op->dentry = dentry; 221 op->ops = &afs_silly_unlink_operation; 222 223 trace_afs_silly_rename(vnode, true); 224 afs_begin_vnode_operation(op); 225 afs_wait_for_operation(op); 226 227 /* If there was a conflict with a third party, check the status of the 228 * unlinked vnode. 229 */ 230 if (op->cumul_error.error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) { 231 op->file[1].update_ctime = false; 232 op->fetch_status.which = 1; 233 op->ops = &afs_fetch_status_operation; 234 afs_begin_vnode_operation(op); 235 afs_wait_for_operation(op); 236 } 237 238 return afs_put_operation(op); 239 } 240 241 /* 242 * Remove sillyrename file on iput. 243 */ 244 int afs_silly_iput(struct dentry *dentry, struct inode *inode) 245 { 246 struct afs_vnode *dvnode = AFS_FS_I(d_inode(dentry->d_parent)); 247 struct afs_vnode *vnode = AFS_FS_I(inode); 248 struct dentry *alias; 249 int ret; 250 251 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 252 253 _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode); 254 255 down_read(&dvnode->rmdir_lock); 256 257 alias = d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq); 258 if (IS_ERR(alias)) { 259 up_read(&dvnode->rmdir_lock); 260 return 0; 261 } 262 263 if (!d_in_lookup(alias)) { 264 /* We raced with lookup... See if we need to transfer the 265 * sillyrename information to the aliased dentry. 266 */ 267 ret = 0; 268 spin_lock(&alias->d_lock); 269 if (d_really_is_positive(alias) && 270 !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { 271 alias->d_flags |= DCACHE_NFSFS_RENAMED; 272 ret = 1; 273 } 274 spin_unlock(&alias->d_lock); 275 up_read(&dvnode->rmdir_lock); 276 dput(alias); 277 return ret; 278 } 279 280 /* Stop lock-release from complaining. */ 281 spin_lock(&vnode->lock); 282 vnode->lock_state = AFS_VNODE_LOCK_DELETED; 283 trace_afs_flock_ev(vnode, NULL, afs_flock_silly_delete, 0); 284 spin_unlock(&vnode->lock); 285 286 afs_do_silly_unlink(dvnode, vnode, dentry, dvnode->silly_key); 287 up_read(&dvnode->rmdir_lock); 288 d_lookup_done(alias); 289 dput(alias); 290 return 1; 291 } 292