aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/unlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/unlink.c')
-rw-r--r--fs/nfs/unlink.c85
1 files changed, 84 insertions, 1 deletions
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 2f84adaad427..c3ce865294f1 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -13,9 +13,12 @@
13#include <linux/nfs_fs.h> 13#include <linux/nfs_fs.h>
14#include <linux/sched.h> 14#include <linux/sched.h>
15#include <linux/wait.h> 15#include <linux/wait.h>
16#include <linux/namei.h>
16 17
17#include "internal.h" 18#include "internal.h"
18#include "nfs4_fs.h" 19#include "nfs4_fs.h"
20#include "iostat.h"
21#include "delegation.h"
19 22
20struct nfs_unlinkdata { 23struct nfs_unlinkdata {
21 struct hlist_node list; 24 struct hlist_node list;
@@ -244,7 +247,7 @@ void nfs_unblock_sillyrename(struct dentry *dentry)
244 * @dir: parent directory of dentry 247 * @dir: parent directory of dentry
245 * @dentry: dentry to unlink 248 * @dentry: dentry to unlink
246 */ 249 */
247int 250static int
248nfs_async_unlink(struct inode *dir, struct dentry *dentry) 251nfs_async_unlink(struct inode *dir, struct dentry *dentry)
249{ 252{
250 struct nfs_unlinkdata *data; 253 struct nfs_unlinkdata *data;
@@ -303,3 +306,83 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
303 if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data))) 306 if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
304 nfs_free_unlinkdata(data); 307 nfs_free_unlinkdata(data);
305} 308}
309
310/**
311 * nfs_sillyrename - Perform a silly-rename of a dentry
312 * @dir: inode of directory that contains dentry
313 * @dentry: dentry to be sillyrenamed
314 *
315 * NFSv2/3 is stateless and the server doesn't know when the client is
316 * holding a file open. To prevent application problems when a file is
317 * unlinked while it's still open, the client performs a "silly-rename".
318 * That is, it renames the file to a hidden file in the same directory,
319 * and only performs the unlink once the last reference to it is put.
320 *
321 * The final cleanup is done during dentry_iput.
322 */
323int
324nfs_sillyrename(struct inode *dir, struct dentry *dentry)
325{
326 static unsigned int sillycounter;
327 const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
328 const int countersize = sizeof(sillycounter)*2;
329 const int slen = sizeof(".nfs")+fileidsize+countersize-1;
330 char silly[slen+1];
331 struct qstr qsilly;
332 struct dentry *sdentry;
333 int error = -EIO;
334
335 dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
336 dentry->d_parent->d_name.name, dentry->d_name.name,
337 atomic_read(&dentry->d_count));
338 nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
339
340 /*
341 * We don't allow a dentry to be silly-renamed twice.
342 */
343 error = -EBUSY;
344 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
345 goto out;
346
347 sprintf(silly, ".nfs%*.*Lx",
348 fileidsize, fileidsize,
349 (unsigned long long)NFS_FILEID(dentry->d_inode));
350
351 /* Return delegation in anticipation of the rename */
352 nfs_inode_return_delegation(dentry->d_inode);
353
354 sdentry = NULL;
355 do {
356 char *suffix = silly + slen - countersize;
357
358 dput(sdentry);
359 sillycounter++;
360 sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
361
362 dfprintk(VFS, "NFS: trying to rename %s to %s\n",
363 dentry->d_name.name, silly);
364
365 sdentry = lookup_one_len(silly, dentry->d_parent, slen);
366 /*
367 * N.B. Better to return EBUSY here ... it could be
368 * dangerous to delete the file while it's in use.
369 */
370 if (IS_ERR(sdentry))
371 goto out;
372 } while (sdentry->d_inode != NULL); /* need negative lookup */
373
374 qsilly.name = silly;
375 qsilly.len = strlen(silly);
376 error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
377 if (dentry->d_inode)
378 nfs_mark_for_revalidate(dentry->d_inode);
379 if (!error) {
380 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
381 d_move(dentry, sdentry);
382 error = nfs_async_unlink(dir, dentry);
383 /* If we return 0 we don't unlink */
384 }
385 dput(sdentry);
386out:
387 return error;
388}