aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/dir.c70
-rw-r--r--fs/nfs/unlink.c85
2 files changed, 84 insertions, 71 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 1e9e18813ad7..86f1d41c6078 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1498,76 +1498,6 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
1498 return error; 1498 return error;
1499} 1499}
1500 1500
1501static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
1502{
1503 static unsigned int sillycounter;
1504 const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
1505 const int countersize = sizeof(sillycounter)*2;
1506 const int slen = sizeof(".nfs")+fileidsize+countersize-1;
1507 char silly[slen+1];
1508 struct qstr qsilly;
1509 struct dentry *sdentry;
1510 int error = -EIO;
1511
1512 dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
1513 dentry->d_parent->d_name.name, dentry->d_name.name,
1514 atomic_read(&dentry->d_count));
1515 nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
1516
1517 /*
1518 * We don't allow a dentry to be silly-renamed twice.
1519 */
1520 error = -EBUSY;
1521 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
1522 goto out;
1523
1524 sprintf(silly, ".nfs%*.*Lx",
1525 fileidsize, fileidsize,
1526 (unsigned long long)NFS_FILEID(dentry->d_inode));
1527
1528 /* Return delegation in anticipation of the rename */
1529 nfs_inode_return_delegation(dentry->d_inode);
1530
1531 sdentry = NULL;
1532 do {
1533 char *suffix = silly + slen - countersize;
1534
1535 dput(sdentry);
1536 sillycounter++;
1537 sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
1538
1539 dfprintk(VFS, "NFS: trying to rename %s to %s\n",
1540 dentry->d_name.name, silly);
1541
1542 sdentry = lookup_one_len(silly, dentry->d_parent, slen);
1543 /*
1544 * N.B. Better to return EBUSY here ... it could be
1545 * dangerous to delete the file while it's in use.
1546 */
1547 if (IS_ERR(sdentry))
1548 goto out;
1549 } while(sdentry->d_inode != NULL); /* need negative lookup */
1550
1551 qsilly.name = silly;
1552 qsilly.len = strlen(silly);
1553 if (dentry->d_inode) {
1554 error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
1555 dir, &qsilly);
1556 nfs_mark_for_revalidate(dentry->d_inode);
1557 } else
1558 error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
1559 dir, &qsilly);
1560 if (!error) {
1561 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1562 d_move(dentry, sdentry);
1563 error = nfs_async_unlink(dir, dentry);
1564 /* If we return 0 we don't unlink */
1565 }
1566 dput(sdentry);
1567out:
1568 return error;
1569}
1570
1571/* 1501/*
1572 * Remove a file after making sure there are no pending writes, 1502 * Remove a file after making sure there are no pending writes,
1573 * and after checking that the file has only one user. 1503 * and after checking that the file has only one user.
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}