aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-04-25 09:26:51 -0400
committerDavid Howells <dhowells@redhat.com>2019-04-25 09:26:51 -0400
commit79ddbfa500b37a94fa7501e65ebdd5c0e4c7592d (patch)
tree1521d6e9276078aaf142ea40ab0f1e156c0fc276 /fs/afs
parent99987c560046ea178eb5aea793043deea255f185 (diff)
afs: Implement sillyrename for unlink and rename
Implement sillyrename for AFS unlink and rename, using the NFS variant implementation as a basis. Note that the asynchronous file locking extender/releaser has to be notified with a state change to stop it complaining if there's a race between that and the actual file deletion. A tracepoint, afs_silly_rename, is also added to note the silly rename and the cleanup. The afs_edit_dir tracepoint is given some extra reason indicators and the afs_flock_ev tracepoint is given a silly-delete file lock cancellation indicator. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/dir.c116
-rw-r--r--fs/afs/dir_silly.c239
-rw-r--r--fs/afs/flock.c2
-rw-r--r--fs/afs/inode.c2
-rw-r--r--fs/afs/internal.h10
-rw-r--r--fs/afs/super.c4
7 files changed, 363 insertions, 11 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 0738e2bf5193..cbf31f6cd177 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -13,6 +13,7 @@ kafs-y := \
13 cmservice.o \ 13 cmservice.o \
14 dir.o \ 14 dir.o \
15 dir_edit.o \ 15 dir_edit.o \
16 dir_silly.o \
16 dynroot.o \ 17 dynroot.o \
17 file.o \ 18 file.o \
18 flock.o \ 19 flock.o \
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index be5d2f932b77..6c8523501639 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -26,6 +26,7 @@ static int afs_dir_open(struct inode *inode, struct file *file);
26static int afs_readdir(struct file *file, struct dir_context *ctx); 26static int afs_readdir(struct file *file, struct dir_context *ctx);
27static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); 27static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
28static int afs_d_delete(const struct dentry *dentry); 28static int afs_d_delete(const struct dentry *dentry);
29static void afs_d_iput(struct dentry *dentry, struct inode *inode);
29static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, 30static int afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
30 loff_t fpos, u64 ino, unsigned dtype); 31 loff_t fpos, u64 ino, unsigned dtype);
31static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, 32static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
@@ -85,6 +86,7 @@ const struct dentry_operations afs_fs_dentry_operations = {
85 .d_delete = afs_d_delete, 86 .d_delete = afs_d_delete,
86 .d_release = afs_d_release, 87 .d_release = afs_d_release,
87 .d_automount = afs_d_automount, 88 .d_automount = afs_d_automount,
89 .d_iput = afs_d_iput,
88}; 90};
89 91
90struct afs_lookup_one_cookie { 92struct afs_lookup_one_cookie {
@@ -1084,6 +1086,16 @@ zap:
1084} 1086}
1085 1087
1086/* 1088/*
1089 * Clean up sillyrename files on dentry removal.
1090 */
1091static void afs_d_iput(struct dentry *dentry, struct inode *inode)
1092{
1093 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
1094 afs_silly_iput(dentry, inode);
1095 iput(inode);
1096}
1097
1098/*
1087 * handle dentry release 1099 * handle dentry release
1088 */ 1100 */
1089void afs_d_release(struct dentry *dentry) 1101void afs_d_release(struct dentry *dentry)
@@ -1225,6 +1237,12 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1225 goto error_key; 1237 goto error_key;
1226 } 1238 }
1227 1239
1240 if (vnode) {
1241 ret = down_write_killable(&vnode->rmdir_lock);
1242 if (ret < 0)
1243 goto error_key;
1244 }
1245
1228 ret = -ERESTARTSYS; 1246 ret = -ERESTARTSYS;
1229 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1247 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1230 while (afs_select_fileserver(&fc)) { 1248 while (afs_select_fileserver(&fc)) {
@@ -1243,6 +1261,8 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
1243 } 1261 }
1244 } 1262 }
1245 1263
1264 if (vnode)
1265 up_write(&vnode->rmdir_lock);
1246error_key: 1266error_key:
1247 key_put(key); 1267 key_put(key);
1248error: 1268error:
@@ -1259,9 +1279,9 @@ error:
1259 * However, if we didn't have a callback promise outstanding, or it was 1279 * However, if we didn't have a callback promise outstanding, or it was
1260 * outstanding on a different server, then it won't break it either... 1280 * outstanding on a different server, then it won't break it either...
1261 */ 1281 */
1262static int afs_dir_remove_link(struct dentry *dentry, struct key *key, 1282int afs_dir_remove_link(struct dentry *dentry, struct key *key,
1263 unsigned long d_version_before, 1283 unsigned long d_version_before,
1264 unsigned long d_version_after) 1284 unsigned long d_version_after)
1265{ 1285{
1266 bool dir_valid; 1286 bool dir_valid;
1267 int ret = 0; 1287 int ret = 0;
@@ -1308,6 +1328,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1308 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; 1328 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
1309 struct key *key; 1329 struct key *key;
1310 unsigned long d_version = (unsigned long)dentry->d_fsdata; 1330 unsigned long d_version = (unsigned long)dentry->d_fsdata;
1331 bool need_rehash = false;
1311 u64 data_version = dvnode->status.data_version; 1332 u64 data_version = dvnode->status.data_version;
1312 int ret; 1333 int ret;
1313 1334
@@ -1331,6 +1352,21 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1331 goto error_key; 1352 goto error_key;
1332 } 1353 }
1333 1354
1355 spin_lock(&dentry->d_lock);
1356 if (vnode && d_count(dentry) > 1) {
1357 spin_unlock(&dentry->d_lock);
1358 /* Start asynchronous writeout of the inode */
1359 write_inode_now(d_inode(dentry), 0);
1360 ret = afs_sillyrename(dvnode, vnode, dentry, key);
1361 goto error_key;
1362 }
1363 if (!d_unhashed(dentry)) {
1364 /* Prevent a race with RCU lookup. */
1365 __d_drop(dentry);
1366 need_rehash = true;
1367 }
1368 spin_unlock(&dentry->d_lock);
1369
1334 ret = -ERESTARTSYS; 1370 ret = -ERESTARTSYS;
1335 if (afs_begin_vnode_operation(&fc, dvnode, key)) { 1371 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
1336 while (afs_select_fileserver(&fc)) { 1372 while (afs_select_fileserver(&fc)) {
@@ -1362,6 +1398,9 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1362 afs_edit_dir_for_unlink); 1398 afs_edit_dir_for_unlink);
1363 } 1399 }
1364 1400
1401 if (need_rehash && ret < 0 && ret != -ENOENT)
1402 d_rehash(dentry);
1403
1365error_key: 1404error_key:
1366 key_put(key); 1405 key_put(key);
1367error: 1406error:
@@ -1582,6 +1621,8 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1582{ 1621{
1583 struct afs_fs_cursor fc; 1622 struct afs_fs_cursor fc;
1584 struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; 1623 struct afs_vnode *orig_dvnode, *new_dvnode, *vnode;
1624 struct dentry *tmp = NULL, *rehash = NULL;
1625 struct inode *new_inode;
1585 struct key *key; 1626 struct key *key;
1586 u64 orig_data_version, new_data_version; 1627 u64 orig_data_version, new_data_version;
1587 bool new_negative = d_is_negative(new_dentry); 1628 bool new_negative = d_is_negative(new_dentry);
@@ -1590,6 +1631,10 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1590 if (flags) 1631 if (flags)
1591 return -EINVAL; 1632 return -EINVAL;
1592 1633
1634 /* Don't allow silly-rename files be moved around. */
1635 if (old_dentry->d_flags & DCACHE_NFSFS_RENAMED)
1636 return -EINVAL;
1637
1593 vnode = AFS_FS_I(d_inode(old_dentry)); 1638 vnode = AFS_FS_I(d_inode(old_dentry));
1594 orig_dvnode = AFS_FS_I(old_dir); 1639 orig_dvnode = AFS_FS_I(old_dir);
1595 new_dvnode = AFS_FS_I(new_dir); 1640 new_dvnode = AFS_FS_I(new_dir);
@@ -1608,12 +1653,48 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1608 goto error; 1653 goto error;
1609 } 1654 }
1610 1655
1656 /* For non-directories, check whether the target is busy and if so,
1657 * make a copy of the dentry and then do a silly-rename. If the
1658 * silly-rename succeeds, the copied dentry is hashed and becomes the
1659 * new target.
1660 */
1661 if (d_is_positive(new_dentry) && !d_is_dir(new_dentry)) {
1662 /* To prevent any new references to the target during the
1663 * rename, we unhash the dentry in advance.
1664 */
1665 if (!d_unhashed(new_dentry)) {
1666 d_drop(new_dentry);
1667 rehash = new_dentry;
1668 }
1669
1670 if (d_count(new_dentry) > 2) {
1671 /* copy the target dentry's name */
1672 ret = -ENOMEM;
1673 tmp = d_alloc(new_dentry->d_parent,
1674 &new_dentry->d_name);
1675 if (!tmp)
1676 goto error_rehash;
1677
1678 ret = afs_sillyrename(new_dvnode,
1679 AFS_FS_I(d_inode(new_dentry)),
1680 new_dentry, key);
1681 if (ret)
1682 goto error_rehash;
1683
1684 new_dentry = tmp;
1685 rehash = NULL;
1686 new_negative = true;
1687 orig_data_version = orig_dvnode->status.data_version;
1688 new_data_version = new_dvnode->status.data_version;
1689 }
1690 }
1691
1611 ret = -ERESTARTSYS; 1692 ret = -ERESTARTSYS;
1612 if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) { 1693 if (afs_begin_vnode_operation(&fc, orig_dvnode, key)) {
1613 if (orig_dvnode != new_dvnode) { 1694 if (orig_dvnode != new_dvnode) {
1614 if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { 1695 if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) {
1615 afs_end_vnode_operation(&fc); 1696 afs_end_vnode_operation(&fc);
1616 goto error_key; 1697 goto error_rehash;
1617 } 1698 }
1618 } 1699 }
1619 while (afs_select_fileserver(&fc)) { 1700 while (afs_select_fileserver(&fc)) {
@@ -1630,25 +1711,42 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
1630 mutex_unlock(&new_dvnode->io_lock); 1711 mutex_unlock(&new_dvnode->io_lock);
1631 ret = afs_end_vnode_operation(&fc); 1712 ret = afs_end_vnode_operation(&fc);
1632 if (ret < 0) 1713 if (ret < 0)
1633 goto error_key; 1714 goto error_rehash;
1634 } 1715 }
1635 1716
1636 if (ret == 0) { 1717 if (ret == 0) {
1718 if (rehash)
1719 d_rehash(rehash);
1637 if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags)) 1720 if (test_bit(AFS_VNODE_DIR_VALID, &orig_dvnode->flags))
1638 afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name, 1721 afs_edit_dir_remove(orig_dvnode, &old_dentry->d_name,
1639 afs_edit_dir_for_rename); 1722 afs_edit_dir_for_rename_0);
1640 1723
1641 if (!new_negative && 1724 if (!new_negative &&
1642 test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags)) 1725 test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
1643 afs_edit_dir_remove(new_dvnode, &new_dentry->d_name, 1726 afs_edit_dir_remove(new_dvnode, &new_dentry->d_name,
1644 afs_edit_dir_for_rename); 1727 afs_edit_dir_for_rename_1);
1645 1728
1646 if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags)) 1729 if (test_bit(AFS_VNODE_DIR_VALID, &new_dvnode->flags))
1647 afs_edit_dir_add(new_dvnode, &new_dentry->d_name, 1730 afs_edit_dir_add(new_dvnode, &new_dentry->d_name,
1648 &vnode->fid, afs_edit_dir_for_rename); 1731 &vnode->fid, afs_edit_dir_for_rename_2);
1732
1733 new_inode = d_inode(new_dentry);
1734 if (new_inode) {
1735 spin_lock(&new_inode->i_lock);
1736 if (new_inode->i_nlink > 0)
1737 drop_nlink(new_inode);
1738 spin_unlock(&new_inode->i_lock);
1739 }
1740 d_move(old_dentry, new_dentry);
1741 goto error_tmp;
1649 } 1742 }
1650 1743
1651error_key: 1744error_rehash:
1745 if (rehash)
1746 d_rehash(rehash);
1747error_tmp:
1748 if (tmp)
1749 dput(tmp);
1652 key_put(key); 1750 key_put(key);
1653error: 1751error:
1654 _leave(" = %d", ret); 1752 _leave(" = %d", ret);
diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c
new file mode 100644
index 000000000000..f6f89fdab6b2
--- /dev/null
+++ b/fs/afs/dir_silly.c
@@ -0,0 +1,239 @@
1/* AFS silly rename handling
2 *
3 * Copyright (C) 2019 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from NFS's sillyrename.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#include <linux/kernel.h>
14#include <linux/fs.h>
15#include <linux/namei.h>
16#include <linux/fsnotify.h>
17#include "internal.h"
18
19/*
20 * Actually perform the silly rename step.
21 */
22static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
23 struct dentry *old, struct dentry *new,
24 struct key *key)
25{
26 struct afs_fs_cursor fc;
27 u64 dir_data_version = dvnode->status.data_version;
28 int ret = -ERESTARTSYS;
29
30 _enter("%pd,%pd", old, new);
31
32 trace_afs_silly_rename(vnode, false);
33 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
34 while (afs_select_fileserver(&fc)) {
35 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
36 afs_fs_rename(&fc, old->d_name.name,
37 dvnode, new->d_name.name,
38 dir_data_version, dir_data_version);
39 }
40
41 afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
42 ret = afs_end_vnode_operation(&fc);
43 }
44
45 if (ret == 0) {
46 spin_lock(&old->d_lock);
47 old->d_flags |= DCACHE_NFSFS_RENAMED;
48 spin_unlock(&old->d_lock);
49 if (dvnode->silly_key != key) {
50 key_put(dvnode->silly_key);
51 dvnode->silly_key = key_get(key);
52 }
53
54 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
55 afs_edit_dir_remove(dvnode, &old->d_name,
56 afs_edit_dir_for_silly_0);
57 if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
58 afs_edit_dir_add(dvnode, &new->d_name,
59 &vnode->fid, afs_edit_dir_for_silly_1);
60
61 /* vfs_unlink and the like do not issue this when a file is
62 * sillyrenamed, so do it here.
63 */
64 fsnotify_nameremove(old, 0);
65 }
66
67 _leave(" = %d", ret);
68 return ret;
69}
70
71/**
72 * afs_sillyrename - Perform a silly-rename of a dentry
73 *
74 * AFS is stateless and the server doesn't know when the client is holding a
75 * file open. To prevent application problems when a file is unlinked while
76 * it's still open, the client performs a "silly-rename". That is, it renames
77 * the file to a hidden file in the same directory, and only performs the
78 * unlink once the last reference to it is put.
79 *
80 * The final cleanup is done during dentry_iput.
81 */
82int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
83 struct dentry *dentry, struct key *key)
84{
85 static unsigned int sillycounter;
86 struct dentry *sdentry = NULL;
87 unsigned char silly[16];
88 int ret = -EBUSY;
89
90 _enter("");
91
92 /* We don't allow a dentry to be silly-renamed twice. */
93 if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
94 return -EBUSY;
95
96 sdentry = NULL;
97 do {
98 int slen;
99
100 dput(sdentry);
101 sillycounter++;
102
103 /* Create a silly name. Note that the ".__afs" prefix is
104 * understood by the salvager and must not be changed.
105 */
106 slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
107 sdentry = lookup_one_len(silly, dentry->d_parent, slen);
108
109 /* N.B. Better to return EBUSY here ... it could be dangerous
110 * to delete the file while it's in use.
111 */
112 if (IS_ERR(sdentry))
113 goto out;
114 } while (!d_is_negative(sdentry));
115
116 ihold(&vnode->vfs_inode);
117
118 ret = afs_do_silly_rename(dvnode, vnode, dentry, sdentry, key);
119 switch (ret) {
120 case 0:
121 /* The rename succeeded. */
122 d_move(dentry, sdentry);
123 break;
124 case -ERESTARTSYS:
125 /* The result of the rename is unknown. Play it safe by forcing
126 * a new lookup.
127 */
128 d_drop(dentry);
129 d_drop(sdentry);
130 }
131
132 iput(&vnode->vfs_inode);
133 dput(sdentry);
134out:
135 _leave(" = %d", ret);
136 return ret;
137}
138
139/*
140 * Tell the server to remove a sillyrename file.
141 */
142static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode,
143 struct dentry *dentry, struct key *key)
144{
145 struct afs_fs_cursor fc;
146 u64 dir_data_version = dvnode->status.data_version;
147 int ret = -ERESTARTSYS;
148
149 _enter("");
150
151 trace_afs_silly_rename(vnode, true);
152 if (afs_begin_vnode_operation(&fc, dvnode, key)) {
153 while (afs_select_fileserver(&fc)) {
154 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
155
156 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
157 !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
158 yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
159 dir_data_version);
160 if (fc.ac.error != -ECONNABORTED ||
161 fc.ac.abort_code != RXGEN_OPCODE)
162 continue;
163 set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags);
164 }
165
166 afs_fs_remove(&fc, vnode, dentry->d_name.name, false,
167 dir_data_version);
168 }
169
170 afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
171 ret = afs_end_vnode_operation(&fc);
172 if (ret == 0) {
173 drop_nlink(&vnode->vfs_inode);
174 if (vnode->vfs_inode.i_nlink == 0) {
175 set_bit(AFS_VNODE_DELETED, &vnode->flags);
176 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
177 }
178 }
179 if (ret == 0 &&
180 test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
181 afs_edit_dir_remove(dvnode, &dentry->d_name,
182 afs_edit_dir_for_unlink);
183 }
184
185 _leave(" = %d", ret);
186 return ret;
187}
188
189/*
190 * Remove sillyrename file on iput.
191 */
192int afs_silly_iput(struct dentry *dentry, struct inode *inode)
193{
194 struct afs_vnode *dvnode = AFS_FS_I(d_inode(dentry->d_parent));
195 struct afs_vnode *vnode = AFS_FS_I(inode);
196 struct dentry *alias;
197 int ret;
198
199 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
200
201 _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode);
202
203 down_read(&dvnode->rmdir_lock);
204
205 alias = d_alloc_parallel(dentry->d_parent, &dentry->d_name, &wq);
206 if (IS_ERR(alias)) {
207 up_read(&dvnode->rmdir_lock);
208 return 0;
209 }
210
211 if (!d_in_lookup(alias)) {
212 /* We raced with lookup... See if we need to transfer the
213 * sillyrename information to the aliased dentry.
214 */
215 ret = 0;
216 spin_lock(&alias->d_lock);
217 if (d_really_is_positive(alias) &&
218 !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
219 alias->d_flags |= DCACHE_NFSFS_RENAMED;
220 ret = 1;
221 }
222 spin_unlock(&alias->d_lock);
223 up_read(&dvnode->rmdir_lock);
224 dput(alias);
225 return ret;
226 }
227
228 /* Stop lock-release from complaining. */
229 spin_lock(&vnode->lock);
230 vnode->lock_state = AFS_VNODE_LOCK_DELETED;
231 trace_afs_flock_ev(vnode, NULL, afs_flock_silly_delete, 0);
232 spin_unlock(&vnode->lock);
233
234 afs_do_silly_unlink(dvnode, vnode, dentry, dvnode->silly_key);
235 up_read(&dvnode->rmdir_lock);
236 d_lookup_done(alias);
237 dput(alias);
238 return 1;
239}
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
index 742038a21ef7..325bf731d8dd 100644
--- a/fs/afs/flock.c
+++ b/fs/afs/flock.c
@@ -300,7 +300,7 @@ again:
300 /* attempt to release the server lock; if it fails, we just 300 /* attempt to release the server lock; if it fails, we just
301 * wait 5 minutes and it'll expire anyway */ 301 * wait 5 minutes and it'll expire anyway */
302 ret = afs_release_lock(vnode, vnode->lock_key); 302 ret = afs_release_lock(vnode, vnode->lock_key);
303 if (ret < 0) { 303 if (ret < 0 && vnode->lock_state != AFS_VNODE_LOCK_DELETED) {
304 trace_afs_flock_ev(vnode, NULL, afs_flock_release_fail, 304 trace_afs_flock_ev(vnode, NULL, afs_flock_release_fail,
305 ret); 305 ret);
306 printk(KERN_WARNING "AFS:" 306 printk(KERN_WARNING "AFS:"
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 9cedc3fc1b77..3eef20ff285b 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -543,6 +543,8 @@ void afs_evict_inode(struct inode *inode)
543#endif 543#endif
544 544
545 afs_put_permits(rcu_access_pointer(vnode->permit_cache)); 545 afs_put_permits(rcu_access_pointer(vnode->permit_cache));
546 key_put(vnode->silly_key);
547 vnode->silly_key = NULL;
546 key_put(vnode->lock_key); 548 key_put(vnode->lock_key);
547 vnode->lock_key = NULL; 549 vnode->lock_key = NULL;
548 _leave(""); 550 _leave("");
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5eb6be3f73b2..20fd44de26ac 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -621,6 +621,8 @@ struct afs_vnode {
621 struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */ 621 struct afs_permits __rcu *permit_cache; /* cache of permits so far obtained */
622 struct mutex io_lock; /* Lock for serialising I/O on this mutex */ 622 struct mutex io_lock; /* Lock for serialising I/O on this mutex */
623 struct rw_semaphore validate_lock; /* lock for validating this vnode */ 623 struct rw_semaphore validate_lock; /* lock for validating this vnode */
624 struct rw_semaphore rmdir_lock; /* Lock for rmdir vs sillyrename */
625 struct key *silly_key; /* Silly rename key */
624 spinlock_t wb_lock; /* lock for wb_keys */ 626 spinlock_t wb_lock; /* lock for wb_keys */
625 spinlock_t lock; /* waitqueue/flags lock */ 627 spinlock_t lock; /* waitqueue/flags lock */
626 unsigned long flags; 628 unsigned long flags;
@@ -866,6 +868,7 @@ extern const struct address_space_operations afs_dir_aops;
866extern const struct dentry_operations afs_fs_dentry_operations; 868extern const struct dentry_operations afs_fs_dentry_operations;
867 869
868extern void afs_d_release(struct dentry *); 870extern void afs_d_release(struct dentry *);
871extern int afs_dir_remove_link(struct dentry *, struct key *, unsigned long, unsigned long);
869 872
870/* 873/*
871 * dir_edit.c 874 * dir_edit.c
@@ -875,6 +878,13 @@ extern void afs_edit_dir_add(struct afs_vnode *, struct qstr *, struct afs_fid *
875extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason); 878extern void afs_edit_dir_remove(struct afs_vnode *, struct qstr *, enum afs_edit_dir_reason);
876 879
877/* 880/*
881 * dir_silly.c
882 */
883extern int afs_sillyrename(struct afs_vnode *, struct afs_vnode *,
884 struct dentry *, struct key *);
885extern int afs_silly_iput(struct dentry *, struct inode *);
886
887/*
878 * dynroot.c 888 * dynroot.c
879 */ 889 */
880extern const struct file_operations afs_dynroot_file_operations; 890extern const struct file_operations afs_dynroot_file_operations;
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 5adf012b8e27..6438849a75c4 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -45,7 +45,7 @@ struct file_system_type afs_fs_type = {
45 .init_fs_context = afs_init_fs_context, 45 .init_fs_context = afs_init_fs_context,
46 .parameters = &afs_fs_parameters, 46 .parameters = &afs_fs_parameters,
47 .kill_sb = afs_kill_super, 47 .kill_sb = afs_kill_super,
48 .fs_flags = 0, 48 .fs_flags = FS_RENAME_DOES_D_MOVE,
49}; 49};
50MODULE_ALIAS_FS("afs"); 50MODULE_ALIAS_FS("afs");
51 51
@@ -656,6 +656,8 @@ static struct inode *afs_alloc_inode(struct super_block *sb)
656 vnode->cb_type = 0; 656 vnode->cb_type = 0;
657 vnode->lock_state = AFS_VNODE_LOCK_NONE; 657 vnode->lock_state = AFS_VNODE_LOCK_NONE;
658 658
659 init_rwsem(&vnode->rmdir_lock);
660
659 _leave(" = %p", &vnode->vfs_inode); 661 _leave(" = %p", &vnode->vfs_inode);
660 return &vnode->vfs_inode; 662 return &vnode->vfs_inode;
661} 663}