Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* AFS silly rename handling
0003  *
0004  * Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  * - Derived from NFS's sillyrename.
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/fs.h>
0011 #include <linux/namei.h>
0012 #include <linux/fsnotify.h>
0013 #include "internal.h"
0014 
0015 static void afs_silly_rename_success(struct afs_operation *op)
0016 {
0017     _enter("op=%08x", op->debug_id);
0018 
0019     afs_check_dir_conflict(op, &op->file[0]);
0020     afs_vnode_commit_status(op, &op->file[0]);
0021 }
0022 
0023 static void afs_silly_rename_edit_dir(struct afs_operation *op)
0024 {
0025     struct afs_vnode_param *dvp = &op->file[0];
0026     struct afs_vnode *dvnode = dvp->vnode;
0027     struct afs_vnode *vnode = AFS_FS_I(d_inode(op->dentry));
0028     struct dentry *old = op->dentry;
0029     struct dentry *new = op->dentry_2;
0030 
0031     spin_lock(&old->d_lock);
0032     old->d_flags |= DCACHE_NFSFS_RENAMED;
0033     spin_unlock(&old->d_lock);
0034     if (dvnode->silly_key != op->key) {
0035         key_put(dvnode->silly_key);
0036         dvnode->silly_key = key_get(op->key);
0037     }
0038 
0039     down_write(&dvnode->validate_lock);
0040     if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
0041         dvnode->status.data_version == dvp->dv_before + dvp->dv_delta) {
0042         afs_edit_dir_remove(dvnode, &old->d_name,
0043                     afs_edit_dir_for_silly_0);
0044         afs_edit_dir_add(dvnode, &new->d_name,
0045                  &vnode->fid, afs_edit_dir_for_silly_1);
0046     }
0047     up_write(&dvnode->validate_lock);
0048 }
0049 
0050 static const struct afs_operation_ops afs_silly_rename_operation = {
0051     .issue_afs_rpc  = afs_fs_rename,
0052     .issue_yfs_rpc  = yfs_fs_rename,
0053     .success    = afs_silly_rename_success,
0054     .edit_dir   = afs_silly_rename_edit_dir,
0055 };
0056 
0057 /*
0058  * Actually perform the silly rename step.
0059  */
0060 static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
0061                    struct dentry *old, struct dentry *new,
0062                    struct key *key)
0063 {
0064     struct afs_operation *op;
0065 
0066     _enter("%pd,%pd", old, new);
0067 
0068     op = afs_alloc_operation(key, dvnode->volume);
0069     if (IS_ERR(op))
0070         return PTR_ERR(op);
0071 
0072     afs_op_set_vnode(op, 0, dvnode);
0073     afs_op_set_vnode(op, 1, dvnode);
0074     op->file[0].dv_delta = 1;
0075     op->file[1].dv_delta = 1;
0076     op->file[0].modification = true;
0077     op->file[1].modification = true;
0078     op->file[0].update_ctime = true;
0079     op->file[1].update_ctime = true;
0080 
0081     op->dentry      = old;
0082     op->dentry_2        = new;
0083     op->ops         = &afs_silly_rename_operation;
0084 
0085     trace_afs_silly_rename(vnode, false);
0086     return afs_do_sync_operation(op);
0087 }
0088 
0089 /*
0090  * Perform silly-rename of a dentry.
0091  *
0092  * AFS is stateless and the server doesn't know when the client is holding a
0093  * file open.  To prevent application problems when a file is unlinked while
0094  * it's still open, the client performs a "silly-rename".  That is, it renames
0095  * the file to a hidden file in the same directory, and only performs the
0096  * unlink once the last reference to it is put.
0097  *
0098  * The final cleanup is done during dentry_iput.
0099  */
0100 int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
0101             struct dentry *dentry, struct key *key)
0102 {
0103     static unsigned int sillycounter;
0104     struct dentry *sdentry = NULL;
0105     unsigned char silly[16];
0106     int ret = -EBUSY;
0107 
0108     _enter("");
0109 
0110     /* We don't allow a dentry to be silly-renamed twice. */
0111     if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
0112         return -EBUSY;
0113 
0114     sdentry = NULL;
0115     do {
0116         int slen;
0117 
0118         dput(sdentry);
0119         sillycounter++;
0120 
0121         /* Create a silly name.  Note that the ".__afs" prefix is
0122          * understood by the salvager and must not be changed.
0123          */
0124         slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
0125         sdentry = lookup_one_len(silly, dentry->d_parent, slen);
0126 
0127         /* N.B. Better to return EBUSY here ... it could be dangerous
0128          * to delete the file while it's in use.
0129          */
0130         if (IS_ERR(sdentry))
0131             goto out;
0132     } while (!d_is_negative(sdentry));
0133 
0134     ihold(&vnode->netfs.inode);
0135 
0136     ret = afs_do_silly_rename(dvnode, vnode, dentry, sdentry, key);
0137     switch (ret) {
0138     case 0:
0139         /* The rename succeeded. */
0140         set_bit(AFS_VNODE_SILLY_DELETED, &vnode->flags);
0141         d_move(dentry, sdentry);
0142         break;
0143     case -ERESTARTSYS:
0144         /* The result of the rename is unknown. Play it safe by forcing
0145          * a new lookup.
0146          */
0147         d_drop(dentry);
0148         d_drop(sdentry);
0149     }
0150 
0151     iput(&vnode->netfs.inode);
0152     dput(sdentry);
0153 out:
0154     _leave(" = %d", ret);
0155     return ret;
0156 }
0157 
0158 static void afs_silly_unlink_success(struct afs_operation *op)
0159 {
0160     _enter("op=%08x", op->debug_id);
0161     afs_check_dir_conflict(op, &op->file[0]);
0162     afs_vnode_commit_status(op, &op->file[0]);
0163     afs_vnode_commit_status(op, &op->file[1]);
0164     afs_update_dentry_version(op, &op->file[0], op->dentry);
0165 }
0166 
0167 static void afs_silly_unlink_edit_dir(struct afs_operation *op)
0168 {
0169     struct afs_vnode_param *dvp = &op->file[0];
0170     struct afs_vnode *dvnode = dvp->vnode;
0171 
0172     _enter("op=%08x", op->debug_id);
0173     down_write(&dvnode->validate_lock);
0174     if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) &&
0175         dvnode->status.data_version == dvp->dv_before + dvp->dv_delta)
0176         afs_edit_dir_remove(dvnode, &op->dentry->d_name,
0177                     afs_edit_dir_for_unlink);
0178     up_write(&dvnode->validate_lock);
0179 }
0180 
0181 static const struct afs_operation_ops afs_silly_unlink_operation = {
0182     .issue_afs_rpc  = afs_fs_remove_file,
0183     .issue_yfs_rpc  = yfs_fs_remove_file,
0184     .success    = afs_silly_unlink_success,
0185     .aborted    = afs_check_for_remote_deletion,
0186     .edit_dir   = afs_silly_unlink_edit_dir,
0187 };
0188 
0189 /*
0190  * Tell the server to remove a sillyrename file.
0191  */
0192 static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode,
0193                    struct dentry *dentry, struct key *key)
0194 {
0195     struct afs_operation *op;
0196 
0197     _enter("");
0198 
0199     op = afs_alloc_operation(NULL, dvnode->volume);
0200     if (IS_ERR(op))
0201         return PTR_ERR(op);
0202 
0203     afs_op_set_vnode(op, 0, dvnode);
0204     afs_op_set_vnode(op, 1, vnode);
0205     op->file[0].dv_delta = 1;
0206     op->file[0].modification = true;
0207     op->file[0].update_ctime = true;
0208     op->file[1].op_unlinked = true;
0209     op->file[1].update_ctime = true;
0210 
0211     op->dentry  = dentry;
0212     op->ops     = &afs_silly_unlink_operation;
0213 
0214     trace_afs_silly_rename(vnode, true);
0215     afs_begin_vnode_operation(op);
0216     afs_wait_for_operation(op);
0217 
0218     /* If there was a conflict with a third party, check the status of the
0219      * unlinked vnode.
0220      */
0221     if (op->error == 0 && (op->flags & AFS_OPERATION_DIR_CONFLICT)) {
0222         op->file[1].update_ctime = false;
0223         op->fetch_status.which = 1;
0224         op->ops = &afs_fetch_status_operation;
0225         afs_begin_vnode_operation(op);
0226         afs_wait_for_operation(op);
0227     }
0228 
0229     return afs_put_operation(op);
0230 }
0231 
0232 /*
0233  * Remove sillyrename file on iput.
0234  */
0235 int afs_silly_iput(struct dentry *dentry, struct inode *inode)
0236 {
0237     struct afs_vnode *dvnode = AFS_FS_I(d_inode(dentry->d_parent));
0238     struct afs_vnode *vnode = AFS_FS_I(inode);
0239     struct dentry *alias;
0240     int ret;
0241 
0242     DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
0243 
0244     _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode);
0245 
0246     down_read(&dvnode->rmdir_lock);
0247 
0248     alias = d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq);
0249     if (IS_ERR(alias)) {
0250         up_read(&dvnode->rmdir_lock);
0251         return 0;
0252     }
0253 
0254     if (!d_in_lookup(alias)) {
0255         /* We raced with lookup...  See if we need to transfer the
0256          * sillyrename information to the aliased dentry.
0257          */
0258         ret = 0;
0259         spin_lock(&alias->d_lock);
0260         if (d_really_is_positive(alias) &&
0261             !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
0262             alias->d_flags |= DCACHE_NFSFS_RENAMED;
0263             ret = 1;
0264         }
0265         spin_unlock(&alias->d_lock);
0266         up_read(&dvnode->rmdir_lock);
0267         dput(alias);
0268         return ret;
0269     }
0270 
0271     /* Stop lock-release from complaining. */
0272     spin_lock(&vnode->lock);
0273     vnode->lock_state = AFS_VNODE_LOCK_DELETED;
0274     trace_afs_flock_ev(vnode, NULL, afs_flock_silly_delete, 0);
0275     spin_unlock(&vnode->lock);
0276 
0277     afs_do_silly_unlink(dvnode, vnode, dentry, dvnode->silly_key);
0278     up_read(&dvnode->rmdir_lock);
0279     d_lookup_done(alias);
0280     dput(alias);
0281     return 1;
0282 }