diff options
-rw-r--r-- | fs/afs/afs.h | 2 | ||||
-rw-r--r-- | fs/afs/dir.c | 36 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 2 | ||||
-rw-r--r-- | fs/afs/inode.c | 18 | ||||
-rw-r--r-- | fs/afs/internal.h | 1 | ||||
-rw-r--r-- | fs/afs/yfsclient.c | 2 |
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 { | |||
150 | struct afs_status_cb { | 150 | struct 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 | */ |
1302 | int afs_dir_remove_link(struct dentry *dentry, struct key *key, | 1302 | static 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 | ||
27 | static const struct inode_operations afs_symlink_inode_operations = { | 28 | static 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; | |||
904 | extern const struct dentry_operations afs_fs_dentry_operations; | 904 | extern const struct dentry_operations afs_fs_dentry_operations; |
905 | 905 | ||
906 | extern void afs_d_release(struct dentry *); | 906 | extern void afs_d_release(struct dentry *); |
907 | extern 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; |