~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/afs/dir_silly.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 /*
 16  * Actually perform the silly rename step.
 17  */
 18 static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
 19                                struct dentry *old, struct dentry *new,
 20                                struct key *key)
 21 {
 22         struct afs_fs_cursor fc;
 23         struct afs_status_cb *scb;
 24         int ret = -ERESTARTSYS;
 25 
 26         _enter("%pd,%pd", old, new);
 27 
 28         scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL);
 29         if (!scb)
 30                 return -ENOMEM;
 31 
 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;
 35 
 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,
 40                                       scb, scb);
 41                 }
 42 
 43                 afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
 44                                         &dir_data_version, scb);
 45                 ret = afs_end_vnode_operation(&fc);
 46         }
 47 
 48         if (ret == 0) {
 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);
 55                 }
 56 
 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);
 63         }
 64 
 65         kfree(scb);
 66         _leave(" = %d", ret);
 67         return ret;
 68 }
 69 
 70 /**
 71  * afs_sillyrename - Perform a silly-rename of a dentry
 72  *
 73  * AFS is stateless and the server doesn't know when the client is holding a
 74  * file open.  To prevent application problems when a file is unlinked while
 75  * it's still open, the client performs a "silly-rename".  That is, it renames
 76  * the file to a hidden file in the same directory, and only performs the
 77  * unlink once the last reference to it is put.
 78  *
 79  * The final cleanup is done during dentry_iput.
 80  */
 81 int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
 82                     struct dentry *dentry, struct key *key)
 83 {
 84         static unsigned int sillycounter;
 85         struct dentry *sdentry = NULL;
 86         unsigned char silly[16];
 87         int ret = -EBUSY;
 88 
 89         _enter("");
 90 
 91         /* We don't allow a dentry to be silly-renamed twice. */
 92         if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
 93                 return -EBUSY;
 94 
 95         sdentry = NULL;
 96         do {
 97                 int slen;
 98 
 99                 dput(sdentry);
100                 sillycounter++;
101 
102                 /* Create a silly name.  Note that the ".__afs" prefix is
103                  * understood by the salvager and must not be changed.
104                  */
105                 slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
106                 sdentry = lookup_one_len(silly, dentry->d_parent, slen);
107 
108                 /* N.B. Better to return EBUSY here ... it could be dangerous
109                  * to delete the file while it's in use.
110                  */
111                 if (IS_ERR(sdentry))
112                         goto out;
113         } while (!d_is_negative(sdentry));
114 
115         ihold(&vnode->vfs_inode);
116 
117         ret = afs_do_silly_rename(dvnode, vnode, dentry, sdentry, key);
118         switch (ret) {
119         case 0:
120                 /* The rename succeeded. */
121                 d_move(dentry, sdentry);
122                 break;
123         case -ERESTARTSYS:
124                 /* The result of the rename is unknown. Play it safe by forcing
125                  * a new lookup.
126                  */
127                 d_drop(dentry);
128                 d_drop(sdentry);
129         }
130 
131         iput(&vnode->vfs_inode);
132         dput(sdentry);
133 out:
134         _leave(" = %d", ret);
135         return ret;
136 }
137 
138 /*
139  * Tell the server to remove a sillyrename file.
140  */
141 static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode,
142                                struct dentry *dentry, struct key *key)
143 {
144         struct afs_fs_cursor fc;
145         struct afs_status_cb *scb;
146         int ret = -ERESTARTSYS;
147 
148         _enter("");
149 
150         scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL);
151         if (!scb)
152                 return -ENOMEM;
153 
154         trace_afs_silly_rename(vnode, true);
155         if (afs_begin_vnode_operation(&fc, dvnode, key, false)) {
156                 afs_dataversion_t dir_data_version = dvnode->status.data_version + 1;
157 
158                 while (afs_select_fileserver(&fc)) {
159                         fc.cb_break = afs_calc_vnode_cb_break(dvnode);
160 
161                         if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
162                             !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
163                                 yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
164                                                     &scb[0], &scb[1]);
165                                 if (fc.ac.error != -ECONNABORTED ||
166                                     fc.ac.abort_code != RXGEN_OPCODE)
167                                         continue;
168                                 set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
169                         }
170 
171                         afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]);
172                 }
173 
174                 afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
175                                         &dir_data_version, &scb[0]);
176                 ret = afs_end_vnode_operation(&fc);
177                 if (ret == 0) {
178                         drop_nlink(&vnode->vfs_inode);
179                         if (vnode->vfs_inode.i_nlink == 0) {
180                                 set_bit(AFS_VNODE_DELETED, &vnode->flags);
181                                 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
182                         }
183                 }
184                 if (ret == 0 &&
185                     test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
186                         afs_edit_dir_remove(dvnode, &dentry->d_name,
187                                             afs_edit_dir_for_unlink);
188         }
189 
190         kfree(scb);
191         _leave(" = %d", ret);
192         return ret;
193 }
194 
195 /*
196  * Remove sillyrename file on iput.
197  */
198 int afs_silly_iput(struct dentry *dentry, struct inode *inode)
199 {
200         struct afs_vnode *dvnode = AFS_FS_I(d_inode(dentry->d_parent));
201         struct afs_vnode *vnode = AFS_FS_I(inode);
202         struct dentry *alias;
203         int ret;
204 
205         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
206 
207         _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode);
208 
209         down_read(&dvnode->rmdir_lock);
210 
211         alias = d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq);
212         if (IS_ERR(alias)) {
213                 up_read(&dvnode->rmdir_lock);
214                 return 0;
215         }
216 
217         if (!d_in_lookup(alias)) {
218                 /* We raced with lookup...  See if we need to transfer the
219                  * sillyrename information to the aliased dentry.
220                  */
221                 ret = 0;
222                 spin_lock(&alias->d_lock);
223                 if (d_really_is_positive(alias) &&
224                     !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
225                         alias->d_flags |= DCACHE_NFSFS_RENAMED;
226                         ret = 1;
227                 }
228                 spin_unlock(&alias->d_lock);
229                 up_read(&dvnode->rmdir_lock);
230                 dput(alias);
231                 return ret;
232         }
233 
234         /* Stop lock-release from complaining. */
235         spin_lock(&vnode->lock);
236         vnode->lock_state = AFS_VNODE_LOCK_DELETED;
237         trace_afs_flock_ev(vnode, NULL, afs_flock_silly_delete, 0);
238         spin_unlock(&vnode->lock);
239 
240         afs_do_silly_unlink(dvnode, vnode, dentry, dvnode->silly_key);
241         up_read(&dvnode->rmdir_lock);
242         d_lookup_done(alias);
243         dput(alias);
244         return 1;
245 }
246 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp