summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/afs/afs.h2
-rw-r--r--fs/afs/dir.c36
-rw-r--r--fs/afs/fsclient.c2
-rw-r--r--fs/afs/inode.c18
-rw-r--r--fs/afs/internal.h1
-rw-r--r--fs/afs/yfsclient.c2
6 files changed, 33 insertions, 28 deletions
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 819678bd8bec..a7d3f902a91c 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -150,7 +150,9 @@ struct afs_file_status {
150struct afs_status_cb { 150struct afs_status_cb {
151 struct afs_file_status status; 151 struct afs_file_status status;
152 struct afs_callback callback; 152 struct afs_callback callback;
153 bool have_status; /* True if status record was retrieved */
153 bool have_cb; /* True if cb record was retrieved */ 154 bool have_cb; /* True if cb record was retrieved */
155 bool have_error; /* True if status.abort_code indicates an error */
154}; 156};
155 157
156/* 158/*
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 338c2260b0a0..d1b3736a3bbd 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1299,32 +1299,27 @@ error:
1299 * However, if we didn't have a callback promise outstanding, or it was 1299 * However, if we didn't have a callback promise outstanding, or it was
1300 * outstanding on a different server, then it won't break it either... 1300 * outstanding on a different server, then it won't break it either...
1301 */ 1301 */
1302int afs_dir_remove_link(struct dentry *dentry, struct key *key, 1302static int afs_dir_remove_link(struct afs_vnode *dvnode, struct dentry *dentry,
1303 unsigned long d_version_before, 1303 struct key *key)
1304 unsigned long d_version_after)
1305{ 1304{
1306 bool dir_valid;
1307 int ret = 0; 1305 int ret = 0;
1308 1306
1309 /* There were no intervening changes on the server if the version
1310 * number we got back was incremented by exactly 1.
1311 */
1312 dir_valid = (d_version_after == d_version_before + 1);
1313
1314 if (d_really_is_positive(dentry)) { 1307 if (d_really_is_positive(dentry)) {
1315 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); 1308 struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
1316 1309
1317 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { 1310 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
1318 /* Already done */ 1311 /* Already done */
1319 } else if (dir_valid) { 1312 } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
1313 write_seqlock(&vnode->cb_lock);
1320 drop_nlink(&vnode->vfs_inode); 1314 drop_nlink(&vnode->vfs_inode);
1321 if (vnode->vfs_inode.i_nlink == 0) { 1315 if (vnode->vfs_inode.i_nlink == 0) {
1322 set_bit(AFS_VNODE_DELETED, &vnode->flags); 1316 set_bit(AFS_VNODE_DELETED, &vnode->flags);
1323 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 1317 __afs_break_callback(vnode);
1324 } 1318 }
1319 write_sequnlock(&vnode->cb_lock);
1325 ret = 0; 1320 ret = 0;
1326 } else { 1321 } else {
1327 clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 1322 afs_break_callback(vnode);
1328 1323
1329 if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) 1324 if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
1330 kdebug("AFS_VNODE_DELETED"); 1325 kdebug("AFS_VNODE_DELETED");
@@ -1348,7 +1343,6 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1348 struct afs_status_cb *scb; 1343 struct afs_status_cb *scb;
1349 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; 1344 struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
1350 struct key *key; 1345 struct key *key;
1351 unsigned long d_version = (unsigned long)dentry->d_fsdata;
1352 bool need_rehash = false; 1346 bool need_rehash = false;
1353 int ret; 1347 int ret;
1354 1348
@@ -1395,20 +1389,16 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1395 ret = -ERESTARTSYS; 1389 ret = -ERESTARTSYS;
1396 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { 1390 if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
1397 afs_dataversion_t data_version = dvnode->status.data_version + 1; 1391 afs_dataversion_t data_version = dvnode->status.data_version + 1;
1392 afs_dataversion_t data_version_2 = vnode->status.data_version;
1398 1393
1399 while (afs_select_fileserver(&fc)) { 1394 while (afs_select_fileserver(&fc)) {
1400 fc.cb_break = afs_calc_vnode_cb_break(dvnode); 1395 fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1396 fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
1401 1397
1402 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) && 1398 if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
1403 !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) { 1399 !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
1404 yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name, 1400 yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
1405 &scb[0], &scb[1]); 1401 &scb[0], &scb[1]);
1406 if (fc.ac.error == 0 &&
1407 scb[1].status.abort_code == VNOVNODE) {
1408 set_bit(AFS_VNODE_DELETED, &vnode->flags);
1409 afs_break_callback(vnode);
1410 }
1411
1412 if (fc.ac.error != -ECONNABORTED || 1402 if (fc.ac.error != -ECONNABORTED ||
1413 fc.ac.abort_code != RXGEN_OPCODE) 1403 fc.ac.abort_code != RXGEN_OPCODE)
1414 continue; 1404 continue;
@@ -1420,11 +1410,11 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
1420 1410
1421 afs_vnode_commit_status(&fc, dvnode, fc.cb_break, 1411 afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
1422 &data_version, &scb[0]); 1412 &data_version, &scb[0]);
1413 afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
1414 &data_version_2, &scb[1]);
1423 ret = afs_end_vnode_operation(&fc); 1415 ret = afs_end_vnode_operation(&fc);
1424 if (ret == 0) 1416 if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
1425 ret = afs_dir_remove_link( 1417 ret = afs_dir_remove_link(dvnode, dentry, key);
1426 dentry, key, d_version,
1427 (unsigned long)dvnode->status.data_version);
1428 if (ret == 0 && 1418 if (ret == 0 &&
1429 test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 1419 test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
1430 afs_edit_dir_remove(dvnode, &dentry->d_name, 1420 afs_edit_dir_remove(dvnode, &dentry->d_name,
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 89b684c957b9..48298408d6ac 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -83,6 +83,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
83 * case. 83 * case.
84 */ 84 */
85 status->abort_code = abort_code; 85 status->abort_code = abort_code;
86 scb->have_error = true;
86 return 0; 87 return 0;
87 } 88 }
88 89
@@ -127,6 +128,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
127 data_version = (u64)ntohl(xdr->data_version_lo); 128 data_version = (u64)ntohl(xdr->data_version_lo);
128 data_version |= (u64)ntohl(xdr->data_version_hi) << 32; 129 data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
129 status->data_version = data_version; 130 status->data_version = data_version;
131 scb->have_status = true;
130 132
131 *_bp = (const void *)*_bp + sizeof(*xdr); 133 *_bp = (const void *)*_bp + sizeof(*xdr);
132 return 0; 134 return 0;
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 37c5de793353..e1a523d2e378 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -23,6 +23,7 @@
23#include <linux/namei.h> 23#include <linux/namei.h>
24#include <linux/iversion.h> 24#include <linux/iversion.h>
25#include "internal.h" 25#include "internal.h"
26#include "afs_fs.h"
26 27
27static const struct inode_operations afs_symlink_inode_operations = { 28static const struct inode_operations afs_symlink_inode_operations = {
28 .get_link = page_get_link, 29 .get_link = page_get_link,
@@ -271,13 +272,22 @@ void afs_vnode_commit_status(struct afs_fs_cursor *fc,
271 272
272 write_seqlock(&vnode->cb_lock); 273 write_seqlock(&vnode->cb_lock);
273 274
274 afs_apply_status(fc, vnode, scb, expected_version); 275 if (scb->have_error) {
275 if (scb->have_cb) 276 if (scb->status.abort_code == VNOVNODE) {
276 afs_apply_callback(fc, vnode, scb, cb_break); 277 set_bit(AFS_VNODE_DELETED, &vnode->flags);
278 clear_nlink(&vnode->vfs_inode);
279 __afs_break_callback(vnode);
280 }
281 } else {
282 if (scb->have_status)
283 afs_apply_status(fc, vnode, scb, expected_version);
284 if (scb->have_cb)
285 afs_apply_callback(fc, vnode, scb, cb_break);
286 }
277 287
278 write_sequnlock(&vnode->cb_lock); 288 write_sequnlock(&vnode->cb_lock);
279 289
280 if (fc->ac.error == 0) 290 if (fc->ac.error == 0 && scb->have_status)
281 afs_cache_permit(vnode, fc->key, cb_break, scb); 291 afs_cache_permit(vnode, fc->key, cb_break, scb);
282} 292}
283 293
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 3dbb1e840dfd..f80ca638e70f 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -904,7 +904,6 @@ extern const struct address_space_operations afs_dir_aops;
904extern const struct dentry_operations afs_fs_dentry_operations; 904extern const struct dentry_operations afs_fs_dentry_operations;
905 905
906extern void afs_d_release(struct dentry *); 906extern void afs_d_release(struct dentry *);
907extern int afs_dir_remove_link(struct dentry *, struct key *, unsigned long, unsigned long);
908 907
909/* 908/*
910 * dir_edit.c 909 * dir_edit.c
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c
index c8f71fc9920b..10de675dc6fc 100644
--- a/fs/afs/yfsclient.c
+++ b/fs/afs/yfsclient.c
@@ -195,6 +195,7 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
195 if (status->abort_code != 0) { 195 if (status->abort_code != 0) {
196 if (status->abort_code == VNOVNODE) 196 if (status->abort_code == VNOVNODE)
197 status->nlink = 0; 197 status->nlink = 0;
198 scb->have_error = true;
198 return 0; 199 return 0;
199 } 200 }
200 201
@@ -222,6 +223,7 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
222 status->mtime_server = xdr_to_time(xdr->mtime_server); 223 status->mtime_server = xdr_to_time(xdr->mtime_server);
223 status->size = xdr_to_u64(xdr->size); 224 status->size = xdr_to_u64(xdr->size);
224 status->data_version = xdr_to_u64(xdr->data_version); 225 status->data_version = xdr_to_u64(xdr->data_version);
226 scb->have_status = true;
225 227
226 *_bp += xdr_size(xdr); 228 *_bp += xdr_size(xdr);
227 return 0; 229 return 0;