Skip to content

Commit a38a755

Browse files
committed
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: 30062bd ("afs: Implement YFS support in the fs client") Signed-off-by: David Howells <[email protected]>
1 parent 61c347b commit a38a755

File tree

6 files changed

+33
-28
lines changed

6 files changed

+33
-28
lines changed

fs/afs/afs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ struct afs_file_status {
150150
struct afs_status_cb {
151151
struct afs_file_status status;
152152
struct afs_callback callback;
153+
bool have_status; /* True if status record was retrieved */
153154
bool have_cb; /* True if cb record was retrieved */
155+
bool have_error; /* True if status.abort_code indicates an error */
154156
};
155157

156158
/*

fs/afs/dir.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,32 +1299,27 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
12991299
* However, if we didn't have a callback promise outstanding, or it was
13001300
* outstanding on a different server, then it won't break it either...
13011301
*/
1302-
int afs_dir_remove_link(struct dentry *dentry, struct key *key,
1303-
unsigned long d_version_before,
1304-
unsigned long d_version_after)
1302+
static int afs_dir_remove_link(struct afs_vnode *dvnode, struct dentry *dentry,
1303+
struct key *key)
13051304
{
1306-
bool dir_valid;
13071305
int ret = 0;
13081306

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-
13141307
if (d_really_is_positive(dentry)) {
13151308
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
13161309

13171310
if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
13181311
/* Already done */
1319-
} else if (dir_valid) {
1312+
} else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
1313+
write_seqlock(&vnode->cb_lock);
13201314
drop_nlink(&vnode->vfs_inode);
13211315
if (vnode->vfs_inode.i_nlink == 0) {
13221316
set_bit(AFS_VNODE_DELETED, &vnode->flags);
1323-
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1317+
__afs_break_callback(vnode);
13241318
}
1319+
write_sequnlock(&vnode->cb_lock);
13251320
ret = 0;
13261321
} else {
1327-
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
1322+
afs_break_callback(vnode);
13281323

13291324
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
13301325
kdebug("AFS_VNODE_DELETED");
@@ -1348,7 +1343,6 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
13481343
struct afs_status_cb *scb;
13491344
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL;
13501345
struct key *key;
1351-
unsigned long d_version = (unsigned long)dentry->d_fsdata;
13521346
bool need_rehash = false;
13531347
int ret;
13541348

@@ -1395,20 +1389,16 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
13951389
ret = -ERESTARTSYS;
13961390
if (afs_begin_vnode_operation(&fc, dvnode, key, true)) {
13971391
afs_dataversion_t data_version = dvnode->status.data_version + 1;
1392+
afs_dataversion_t data_version_2 = vnode->status.data_version;
13981393

13991394
while (afs_select_fileserver(&fc)) {
14001395
fc.cb_break = afs_calc_vnode_cb_break(dvnode);
1396+
fc.cb_break_2 = afs_calc_vnode_cb_break(vnode);
14011397

14021398
if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) &&
14031399
!test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) {
14041400
yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name,
14051401
&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-
14121402
if (fc.ac.error != -ECONNABORTED ||
14131403
fc.ac.abort_code != RXGEN_OPCODE)
14141404
continue;
@@ -1420,11 +1410,11 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
14201410

14211411
afs_vnode_commit_status(&fc, dvnode, fc.cb_break,
14221412
&data_version, &scb[0]);
1413+
afs_vnode_commit_status(&fc, vnode, fc.cb_break_2,
1414+
&data_version_2, &scb[1]);
14231415
ret = afs_end_vnode_operation(&fc);
1424-
if (ret == 0)
1425-
ret = afs_dir_remove_link(
1426-
dentry, key, d_version,
1427-
(unsigned long)dvnode->status.data_version);
1416+
if (ret == 0 && !(scb[1].have_status || scb[1].have_error))
1417+
ret = afs_dir_remove_link(dvnode, dentry, key);
14281418
if (ret == 0 &&
14291419
test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
14301420
afs_edit_dir_remove(dvnode, &dentry->d_name,

fs/afs/fsclient.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
8383
* case.
8484
*/
8585
status->abort_code = abort_code;
86+
scb->have_error = true;
8687
return 0;
8788
}
8889

@@ -127,6 +128,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
127128
data_version = (u64)ntohl(xdr->data_version_lo);
128129
data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
129130
status->data_version = data_version;
131+
scb->have_status = true;
130132

131133
*_bp = (const void *)*_bp + sizeof(*xdr);
132134
return 0;

fs/afs/inode.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/namei.h>
2424
#include <linux/iversion.h>
2525
#include "internal.h"
26+
#include "afs_fs.h"
2627

2728
static const struct inode_operations afs_symlink_inode_operations = {
2829
.get_link = page_get_link,
@@ -271,13 +272,22 @@ void afs_vnode_commit_status(struct afs_fs_cursor *fc,
271272

272273
write_seqlock(&vnode->cb_lock);
273274

274-
afs_apply_status(fc, vnode, scb, expected_version);
275-
if (scb->have_cb)
276-
afs_apply_callback(fc, vnode, scb, cb_break);
275+
if (scb->have_error) {
276+
if (scb->status.abort_code == VNOVNODE) {
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+
}
277287

278288
write_sequnlock(&vnode->cb_lock);
279289

280-
if (fc->ac.error == 0)
290+
if (fc->ac.error == 0 && scb->have_status)
281291
afs_cache_permit(vnode, fc->key, cb_break, scb);
282292
}
283293

fs/afs/internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,6 @@ extern const struct address_space_operations afs_dir_aops;
904904
extern const struct dentry_operations afs_fs_dentry_operations;
905905

906906
extern void afs_d_release(struct dentry *);
907-
extern int afs_dir_remove_link(struct dentry *, struct key *, unsigned long, unsigned long);
908907

909908
/*
910909
* dir_edit.c

fs/afs/yfsclient.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
195195
if (status->abort_code != 0) {
196196
if (status->abort_code == VNOVNODE)
197197
status->nlink = 0;
198+
scb->have_error = true;
198199
return 0;
199200
}
200201

@@ -222,6 +223,7 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp,
222223
status->mtime_server = xdr_to_time(xdr->mtime_server);
223224
status->size = xdr_to_u64(xdr->size);
224225
status->data_version = xdr_to_u64(xdr->data_version);
226+
scb->have_status = true;
225227

226228
*_bp += xdr_size(xdr);
227229
return 0;

0 commit comments

Comments
 (0)