summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-05-14 07:29:11 -0400
committerDavid Howells <dhowells@redhat.com>2019-05-16 17:23:21 -0400
commita38a75581e6e2f783e7b8658e9ca5d4243279f55 (patch)
tree4df2ddb097f5301ee92e8fe9ba2541b0dd40d9e4
parent61c347ba551162edb1c6abfa60ce6907baf7a1af (diff)
afs: Fix unlink to handle YFS.RemoveFile2 better
Make use of the status update for the target file that the YFS.RemoveFile2 RPC op returns to correctly update the vnode as to whether the file was actually deleted or just had nlink reduced. Fixes: 30062bd13e36 ("afs: Implement YFS support in the fs client") Signed-off-by: David Howells <dhowells@redhat.com>
-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;