From fefb2483dc10c736e4235984fed4f3a61c99e1c2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 17:19:10 +0100 Subject: afs: Don't pass the vnode pointer through into the inline bulk status op Don't pass the vnode pointer through into the inline bulk status op. We want to process the status records outside of it anyway. Signed-off-by: David Howells --- fs/afs/fsclient.c | 7 +------ fs/afs/yfsclient.c | 10 +--------- 2 files changed, 2 insertions(+), 15 deletions(-) (limited to 'fs') diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 388750d80cab..dc6f8da0dfa0 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -2237,7 +2237,6 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) { struct afs_file_status *statuses; struct afs_callback *callbacks; - struct afs_vnode *vnode = call->reply[0]; const __be32 *bp; u32 tmp; int ret; @@ -2278,8 +2277,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) bp = call->buffer; statuses = call->reply[1]; ret = afs_decode_status(call, &bp, &statuses[call->count], - call->count == 0 ? vnode : NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret < 0) return ret; @@ -2321,8 +2319,6 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) callbacks = call->reply[2]; xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); statuses = call->reply[1]; - if (call->count == 0 && vnode && statuses[0].abort_code == 0) - xdr_decode_AFSCallBack(call, vnode, &bp); call->count++; if (call->count < call->count2) goto more_cbs; @@ -2390,7 +2386,6 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[0] = NULL; /* vnode for fid[0] */ call->reply[1] = statuses; call->reply[2] = callbacks; call->reply[3] = volsync; diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index b42bd412dba1..3f6d50edf498 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -2055,7 +2055,6 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) { struct afs_file_status *statuses; struct afs_callback *callbacks; - struct afs_vnode *vnode = call->reply[0]; const __be32 *bp; u32 tmp; int ret; @@ -2096,8 +2095,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) bp = call->buffer; statuses = call->reply[1]; ret = yfs_decode_status(call, &bp, &statuses[call->count], - call->count == 0 ? vnode : NULL, - NULL, NULL); + NULL, NULL, NULL); if (ret < 0) return ret; @@ -2138,11 +2136,6 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) bp = call->buffer; callbacks = call->reply[2]; xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); - statuses = call->reply[1]; - if (call->count == 0 && vnode && statuses[0].abort_code == 0) { - bp = call->buffer; - xdr_decode_YFSCallBack(call, vnode, &bp); - } call->count++; if (call->count < call->count2) goto more_cbs; @@ -2210,7 +2203,6 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[0] = NULL; /* vnode for fid[0] */ call->reply[1] = statuses; call->reply[2] = callbacks; call->reply[3] = volsync; -- cgit v1.2.3 From ffba718e935402e7f42b8cd5d1e00e4a3907d361 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 22:22:50 +0100 Subject: afs: Get rid of afs_call::reply[] Replace the afs_call::reply[] array with a bunch of typed members so that the compiler can use type-checking on them. It's also easier for the eye to see what's going on. Signed-off-by: David Howells --- fs/afs/cmservice.c | 14 +-- fs/afs/file.c | 2 +- fs/afs/flock.c | 2 +- fs/afs/fs_probe.c | 4 +- fs/afs/fsclient.c | 287 +++++++++++++++++++++++++++-------------------------- fs/afs/internal.h | 24 ++++- fs/afs/rxrpc.c | 9 +- fs/afs/vl_probe.c | 4 +- fs/afs/vlclient.c | 33 +++--- fs/afs/yfsclient.c | 217 ++++++++++++++++++---------------------- 10 files changed, 293 insertions(+), 303 deletions(-) (limited to 'fs') diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 748090014519..01437cfe5432 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -213,7 +213,7 @@ static int afs_find_cm_server_by_peer(struct afs_call *call) return 0; } - call->cm_server = server; + call->server = server; return afs_record_cm_probe(call, server); } @@ -234,7 +234,7 @@ static int afs_find_cm_server_by_uuid(struct afs_call *call, return 0; } - call->cm_server = server; + call->server = server; return afs_record_cm_probe(call, server); } @@ -260,8 +260,8 @@ static void SRXAFSCB_CallBack(struct work_struct *work) * server holds up change visibility till it receives our reply so as * to maintain cache coherency. */ - if (call->cm_server) - afs_break_callbacks(call->cm_server, call->count, call->request); + if (call->server) + afs_break_callbacks(call->server, call->count, call->request); afs_send_empty_reply(call); afs_put_call(call); @@ -376,10 +376,10 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) { struct afs_call *call = container_of(work, struct afs_call, work); - _enter("{%p}", call->cm_server); + _enter("{%p}", call->server); - if (call->cm_server) - afs_init_callback_state(call->cm_server); + if (call->server) + afs_init_callback_state(call->server); afs_send_empty_reply(call); afs_put_call(call); _leave(""); diff --git a/fs/afs/file.c b/fs/afs/file.c index f59c6149fa02..415c84dddb89 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -408,7 +408,7 @@ static int afs_readpage(struct file *file, struct page *page) static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req) { #ifdef CONFIG_AFS_FSCACHE - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; #endif struct page *page = req->pages[req->index]; diff --git a/fs/afs/flock.c b/fs/afs/flock.c index c91cd201013f..ce8275940b99 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -74,7 +74,7 @@ static void afs_schedule_lock_extension(struct afs_vnode *vnode) */ void afs_lock_op_done(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; if (call->error == 0) { spin_lock(&vnode->lock); diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c index 5d3abde52a0f..9b7266209343 100644 --- a/fs/afs/fs_probe.c +++ b/fs/afs/fs_probe.c @@ -33,8 +33,8 @@ static bool afs_fs_probe_done(struct afs_server *server) void afs_fileserver_probe_result(struct afs_call *call) { struct afs_addr_list *alist = call->alist; - struct afs_server *server = call->reply[0]; - unsigned int server_index = (long)call->reply[1]; + struct afs_server *server = call->server; + unsigned int server_index = call->server_index; unsigned int index = call->addr_ix; unsigned int rtt = UINT_MAX; bool have_result = false; diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index dc6f8da0dfa0..16bcc578e3b2 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -392,7 +392,7 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, */ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -409,7 +409,7 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) if (ret < 0) return ret; xdr_decode_AFSCallBack(call, vnode, &bp); - xdr_decode_AFSVolSync(&bp, call->reply[1]); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -450,8 +450,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy } call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = volsync; + call->xvnode = vnode; + call->out_volsync = volsync; call->expected_version = new_inode ? 1 : vnode->status.data_version; call->want_reply_time = true; @@ -476,8 +476,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy */ static int afs_deliver_fs_fetch_data(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; - struct afs_read *req = call->reply[2]; + struct afs_vnode *vnode = call->xvnode; + struct afs_read *req = call->read_request; const __be32 *bp; unsigned int size; int ret; @@ -578,7 +578,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) if (ret < 0) return ret; xdr_decode_AFSCallBack(call, vnode, &bp); - xdr_decode_AFSVolSync(&bp, call->reply[1]); + xdr_decode_AFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -601,7 +601,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) static void afs_fetch_data_destructor(struct afs_call *call) { - struct afs_read *req = call->reply[2]; + struct afs_read *req = call->read_request; afs_put_read(req); afs_flat_call_destructor(call); @@ -641,9 +641,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = NULL; /* volsync */ - call->reply[2] = req; + call->xvnode = vnode; + call->out_volsync = NULL; + call->read_request = req; call->expected_version = vnode->status.data_version; call->want_reply_time = true; @@ -692,9 +692,9 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = NULL; /* volsync */ - call->reply[2] = req; + call->xvnode = vnode; + call->out_volsync = NULL; + call->read_request = req; call->expected_version = vnode->status.data_version; call->want_reply_time = true; @@ -721,7 +721,7 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) */ static int afs_deliver_fs_create_vnode(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -733,16 +733,16 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - xdr_decode_AFSFid(&bp, call->reply[1]); - ret = afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL); + xdr_decode_AFSFid(&bp, call->out_fid); + ret = afs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, + ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, &call->expected_version, NULL); if (ret < 0) return ret; - xdr_decode_AFSCallBack_raw(call, call->reply[3], &bp); - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSCallBack_raw(call, call->out_cb, &bp); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -776,9 +776,9 @@ int afs_fs_create(struct afs_fs_cursor *fc, struct afs_file_status *newstatus, struct afs_callback *newcb) { - struct afs_vnode *vnode = fc->vnode; + struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; - struct afs_net *net = afs_v2net(vnode); + struct afs_net *net = afs_v2net(dvnode); size_t namesz, reqsz, padsz; __be32 *bp; @@ -804,19 +804,19 @@ int afs_fs_create(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = newfid; - call->reply[2] = newstatus; - call->reply[3] = newcb; + call->dvnode = dvnode; + call->out_fid = newfid; + call->out_extra_status = newstatus; + call->out_cb = newcb; call->expected_version = current_data_version + 1; call->want_reply_time = true; /* marshall the parameters */ bp = call->request; *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); - *bp++ = htonl(vnode->fid.vid); - *bp++ = htonl(vnode->fid.vnode); - *bp++ = htonl(vnode->fid.unique); + *bp++ = htonl(dvnode->fid.vid); + *bp++ = htonl(dvnode->fid.vnode); + *bp++ = htonl(dvnode->fid.unique); *bp++ = htonl(namesz); memcpy(bp, name, namesz); bp = (void *) bp + namesz; @@ -825,26 +825,26 @@ int afs_fs_create(struct afs_fs_cursor *fc, bp = (void *) bp + padsz; } *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); - *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ + *bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */ *bp++ = 0; /* owner */ *bp++ = 0; /* group */ *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ *bp++ = 0; /* segment size */ afs_use_fs_server(call, fc->cbi); - trace_afs_make_fs_call1(call, &vnode->fid, name); + trace_afs_make_fs_call1(call, &dvnode->fid, name); afs_set_fc_call(call, fc); afs_make_call(&fc->ac, call, GFP_NOFS); return afs_wait_for_call_to_complete(call, &fc->ac); } /* - * Deliver reply data to any operation that returns file status and volume + * Deliver reply data to any operation that returns directory status and volume * sync. */ -static int afs_deliver_fs_status_and_vol(struct afs_call *call) +static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -856,11 +856,11 @@ static int afs_deliver_fs_status_and_vol(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, + ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, &call->expected_version, NULL); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -872,14 +872,14 @@ static int afs_deliver_fs_status_and_vol(struct afs_call *call) static const struct afs_call_type afs_RXFSRemoveFile = { .name = "FS.RemoveFile", .op = afs_FS_RemoveFile, - .deliver = afs_deliver_fs_status_and_vol, + .deliver = afs_deliver_fs_dir_status_and_vol, .destructor = afs_flat_call_destructor, }; static const struct afs_call_type afs_RXFSRemoveDir = { .name = "FS.RemoveDir", .op = afs_FS_RemoveDir, - .deliver = afs_deliver_fs_status_and_vol, + .deliver = afs_deliver_fs_dir_status_and_vol, .destructor = afs_flat_call_destructor, }; @@ -911,8 +911,8 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = vnode; + call->dvnode = dvnode; + call->xvnode = vnode; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -941,7 +941,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int afs_deliver_fs_link(struct afs_call *call) { - struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1]; + struct afs_vnode *dvnode = call->dvnode, *vnode = call->xvnode; const __be32 *bp; int ret; @@ -960,7 +960,7 @@ static int afs_deliver_fs_link(struct afs_call *call) &call->expected_version, NULL); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1002,8 +1002,8 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = vnode; + call->dvnode = dvnode; + call->xvnode = vnode; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -1035,7 +1035,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int afs_deliver_fs_symlink(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -1047,15 +1047,15 @@ static int afs_deliver_fs_symlink(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - xdr_decode_AFSFid(&bp, call->reply[1]); - ret = afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL); + xdr_decode_AFSFid(&bp, call->out_fid); + ret = afs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, + ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, &call->expected_version, NULL); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1081,9 +1081,9 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, struct afs_fid *newfid, struct afs_file_status *newstatus) { - struct afs_vnode *vnode = fc->vnode; + struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; - struct afs_net *net = afs_v2net(vnode); + struct afs_net *net = afs_v2net(dvnode); size_t namesz, reqsz, padsz, c_namesz, c_padsz; __be32 *bp; @@ -1107,17 +1107,17 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = newfid; - call->reply[2] = newstatus; + call->dvnode = dvnode; + call->out_fid = newfid; + call->out_extra_status = newstatus; call->expected_version = current_data_version + 1; /* marshall the parameters */ bp = call->request; *bp++ = htonl(FSSYMLINK); - *bp++ = htonl(vnode->fid.vid); - *bp++ = htonl(vnode->fid.vnode); - *bp++ = htonl(vnode->fid.unique); + *bp++ = htonl(dvnode->fid.vid); + *bp++ = htonl(dvnode->fid.vnode); + *bp++ = htonl(dvnode->fid.unique); *bp++ = htonl(namesz); memcpy(bp, name, namesz); bp = (void *) bp + namesz; @@ -1133,14 +1133,14 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, bp = (void *) bp + c_padsz; } *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); - *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ + *bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */ *bp++ = 0; /* owner */ *bp++ = 0; /* group */ *bp++ = htonl(S_IRWXUGO); /* unix mode */ *bp++ = 0; /* segment size */ afs_use_fs_server(call, fc->cbi); - trace_afs_make_fs_call1(call, &vnode->fid, name); + trace_afs_make_fs_call1(call, &dvnode->fid, name); afs_set_fc_call(call, fc); afs_make_call(&fc->ac, call, GFP_NOFS); return afs_wait_for_call_to_complete(call, &fc->ac); @@ -1151,7 +1151,7 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_rename(struct afs_call *call) { - struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1]; + struct afs_vnode *orig_dvnode = call->dvnode, *new_dvnode = call->xvnode; const __be32 *bp; int ret; @@ -1173,7 +1173,7 @@ static int afs_deliver_fs_rename(struct afs_call *call) if (ret < 0) return ret; } - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1229,8 +1229,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = orig_dvnode; - call->reply[1] = new_dvnode; + call->dvnode = orig_dvnode; + call->xvnode = new_dvnode; call->expected_version = current_orig_data_version + 1; call->expected_version_2 = current_new_data_version + 1; @@ -1271,7 +1271,7 @@ int afs_fs_rename(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_store_data(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1287,7 +1287,7 @@ static int afs_deliver_fs_store_data(struct afs_call *call) &call->expected_version, NULL); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); afs_pages_written_back(vnode, call); @@ -1337,7 +1337,7 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, call->key = fc->key; call->mapping = mapping; - call->reply[0] = vnode; + call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; @@ -1417,7 +1417,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, call->key = fc->key; call->mapping = mapping; - call->reply[0] = vnode; + call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; @@ -1455,7 +1455,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, */ static int afs_deliver_fs_store_status(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1471,7 +1471,7 @@ static int afs_deliver_fs_store_status(struct afs_call *call) &call->expected_version, NULL); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1524,7 +1524,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->expected_version = vnode->status.data_version + 1; /* marshall the parameters */ @@ -1575,7 +1575,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->expected_version = vnode->status.data_version + 1; /* marshall the parameters */ @@ -1625,7 +1625,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->expected_version = vnode->status.data_version; /* marshall the parameters */ @@ -1669,7 +1669,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) return ret; bp = call->buffer; - xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]); + xdr_decode_AFSFetchVolumeStatus(&bp, call->out_volstatus); call->unmarshall++; afs_extract_to_tmp(call); @@ -1685,7 +1685,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_volname_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the volume name */ @@ -1695,7 +1695,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("volname '%s'", p); afs_extract_to_tmp(call); @@ -1713,7 +1713,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_offline_msg_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the offline message */ @@ -1723,7 +1723,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("offline '%s'", p); @@ -1742,7 +1742,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_motd_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the message of the day */ @@ -1752,7 +1752,7 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("motd '%s'", p); @@ -1766,16 +1766,6 @@ static int afs_deliver_fs_get_volume_status(struct afs_call *call) return 0; } -/* - * destroy an FS.GetVolumeStatus call - */ -static void afs_get_volume_status_call_destructor(struct afs_call *call) -{ - kfree(call->reply[2]); - call->reply[2] = NULL; - afs_flat_call_destructor(call); -} - /* * FS.GetVolumeStatus operation type */ @@ -1783,7 +1773,7 @@ static const struct afs_call_type afs_RXFSGetVolumeStatus = { .name = "FS.GetVolumeStatus", .op = afs_FS_GetVolumeStatus, .deliver = afs_deliver_fs_get_volume_status, - .destructor = afs_get_volume_status_call_destructor, + .destructor = afs_flat_call_destructor, }; /* @@ -1796,27 +1786,19 @@ int afs_fs_get_volume_status(struct afs_fs_cursor *fc, struct afs_call *call; struct afs_net *net = afs_v2net(vnode); __be32 *bp; - void *tmpbuf; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) return yfs_fs_get_volume_status(fc, vs); _enter(""); - tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - - call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); - if (!call) { - kfree(tmpbuf); + call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, + max(12 * 4, AFSOPAQUEMAX + 1)); + if (!call) return -ENOMEM; - } call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = vs; - call->reply[2] = tmpbuf; + call->out_volstatus = vs; /* marshall the parameters */ bp = call->request; @@ -1846,7 +1828,7 @@ static int afs_deliver_fs_xxxx_lock(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1904,7 +1886,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->want_reply_time = true; /* marshall the parameters */ @@ -1942,7 +1924,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->want_reply_time = true; /* marshall the parameters */ @@ -1979,7 +1961,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; /* marshall the parameters */ bp = call->request; @@ -2085,14 +2067,6 @@ static int afs_deliver_fs_get_capabilities(struct afs_call *call) return 0; } -static void afs_destroy_fs_get_capabilities(struct afs_call *call) -{ - struct afs_server *server = call->reply[0]; - - afs_put_server(call->net, server); - afs_flat_call_destructor(call); -} - /* * FS.GetCapabilities operation type */ @@ -2101,7 +2075,7 @@ static const struct afs_call_type afs_RXFSGetCapabilities = { .op = afs_FS_GetCapabilities, .deliver = afs_deliver_fs_get_capabilities, .done = afs_fileserver_probe_result, - .destructor = afs_destroy_fs_get_capabilities, + .destructor = afs_flat_call_destructor, }; /* @@ -2124,8 +2098,8 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net, return ERR_PTR(-ENOMEM); call->key = key; - call->reply[0] = afs_get_server(server); - call->reply[1] = (void *)(long)server_index; + call->server = afs_get_server(server); + call->server_index = server_index; call->upgrade = true; call->want_reply_time = true; call->async = true; @@ -2146,10 +2120,10 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net, */ static int afs_deliver_fs_fetch_status(struct afs_call *call) { - struct afs_file_status *status = call->reply[1]; - struct afs_callback *callback = call->reply[2]; - struct afs_volsync *volsync = call->reply[3]; - struct afs_fid *fid = call->reply[0]; + struct afs_file_status *status = call->out_vnode_status; + struct afs_callback *callback = call->out_cb; + struct afs_volsync *volsync = call->out_volsync; + struct afs_fid *fid = call->out_fid; const __be32 *bp; int ret; @@ -2208,10 +2182,10 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[0] = fid; - call->reply[1] = status; - call->reply[2] = callback; - call->reply[3] = volsync; + call->out_fid = fid; + call->out_vnode_status = status; + call->out_cb = callback; + call->out_volsync = volsync; call->expected_version = 1; /* vnode->status.data_version */ call->want_reply_time = true; @@ -2275,7 +2249,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - statuses = call->reply[1]; + statuses = call->out_extra_status; ret = afs_decode_status(call, &bp, &statuses[call->count], NULL, NULL, NULL); if (ret < 0) @@ -2316,9 +2290,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; - callbacks = call->reply[2]; + callbacks = call->out_cb; xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); - statuses = call->reply[1]; + statuses = call->out_extra_status; call->count++; if (call->count < call->count2) goto more_cbs; @@ -2333,7 +2307,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - xdr_decode_AFSVolSync(&bp, call->reply[3]); + xdr_decode_AFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -2386,9 +2360,9 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[1] = statuses; - call->reply[2] = callbacks; - call->reply[3] = volsync; + call->out_extra_status = statuses; + call->out_cb = callbacks; + call->out_volsync = volsync; call->count2 = nr_fids; call->want_reply_time = true; @@ -2415,7 +2389,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_fetch_acl(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[1]; + struct afs_vnode *vnode = call->xvnode; struct afs_acl *acl; const __be32 *bp; unsigned int size; @@ -2440,7 +2414,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call) acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); if (!acl) return -ENOMEM; - call->reply[0] = acl; + call->ret_acl = acl; acl->size = call->count2; afs_extract_begin(call, acl->data, size); call->unmarshall++; @@ -2465,7 +2439,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call) &vnode->status.data_version, NULL); if (ret < 0) return ret; - xdr_decode_AFSVolSync(&bp, call->reply[2]); + xdr_decode_AFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -2479,7 +2453,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call) static void afs_destroy_fs_fetch_acl(struct afs_call *call) { - kfree(call->reply[0]); + kfree(call->ret_acl); afs_flat_call_destructor(call); } @@ -2513,10 +2487,9 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) } call->key = fc->key; - call->reply[0] = NULL; - call->reply[1] = vnode; - call->reply[2] = NULL; /* volsync */ - call->ret_reply0 = true; + call->ret_acl = NULL; + call->xvnode = vnode; + call->out_volsync = NULL; /* marshall the parameters */ bp = call->request; @@ -2532,13 +2505,41 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); } +/* + * Deliver reply data to any operation that returns file status and volume + * sync. + */ +static int afs_deliver_fs_file_status_and_vol(struct afs_call *call) +{ + struct afs_vnode *vnode = call->xvnode; + const __be32 *bp; + int ret; + + _enter("{%u}", call->unmarshall); + + ret = afs_transfer_reply(call); + if (ret < 0) + return ret; + + /* unmarshall the reply once we've received all of it */ + bp = call->buffer; + ret = afs_decode_status(call, &bp, &vnode->status, vnode, + &call->expected_version, NULL); + if (ret < 0) + return ret; + xdr_decode_AFSVolSync(&bp, call->out_volsync); + + _leave(" = 0 [done]"); + return 0; +} + /* * FS.StoreACL operation type */ static const struct afs_call_type afs_RXFSStoreACL = { .name = "FS.StoreACL", .op = afs_FS_StoreACL, - .deliver = afs_deliver_fs_status_and_vol, + .deliver = afs_deliver_fs_file_status_and_vol, .destructor = afs_flat_call_destructor, }; @@ -2565,8 +2566,8 @@ int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl) } call->key = fc->key; - call->reply[0] = vnode; - call->reply[2] = NULL; /* volsync */ + call->xvnode = vnode; + call->out_volsync = NULL; /* marshall the parameters */ bp = call->request; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 833fa39ee337..705833eb2d45 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -111,8 +111,13 @@ struct afs_call { struct rxrpc_call *rxcall; /* RxRPC call handle */ struct key *key; /* security for this call */ struct afs_net *net; /* The network namespace */ - struct afs_server *cm_server; /* Server affected by incoming CM call */ + union { + struct afs_server *server; + struct afs_vlserver *vlserver; + }; struct afs_cb_interest *cbi; /* Callback interest for server used */ + struct afs_vnode *dvnode; /* Directory vnode of call */ + struct afs_vnode *xvnode; /* Other vnode of call */ void *request; /* request data (first part) */ struct address_space *mapping; /* Pages being written from */ struct iov_iter iter; /* Buffer iterator */ @@ -122,7 +127,21 @@ struct afs_call { struct bio_vec bvec[1]; }; void *buffer; /* reply receive buffer */ - void *reply[4]; /* Where to put the reply */ + union { + long ret0; /* Value to reply with instead of 0 */ + struct afs_addr_list *ret_alist; + struct afs_vldb_entry *ret_vldb; + struct afs_acl *ret_acl; + }; + struct afs_fid *out_fid; + struct afs_file_status *out_vnode_status; + struct afs_file_status *out_extra_status; + struct afs_callback *out_cb; + struct yfs_acl *out_yacl; + struct afs_volsync *out_volsync; + struct afs_volume_status *out_volstatus; + struct afs_read *read_request; + unsigned int server_index; pgoff_t first; /* first page in mapping to deal with */ pgoff_t last; /* last page in mapping to deal with */ atomic_t usage; @@ -146,7 +165,6 @@ struct afs_call { bool send_pages; /* T if data from mapping should be sent */ bool need_attention; /* T if RxRPC poked us */ bool async; /* T if asynchronous */ - bool ret_reply0; /* T if should return reply[0] on success */ bool upgrade; /* T to request service upgrade */ bool want_reply_time; /* T if want reply_time */ bool intr; /* T if interruptible */ diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 02a39e6adf63..d63e0c9c09e7 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -188,7 +188,7 @@ void afs_put_call(struct afs_call *call) if (call->type->destructor) call->type->destructor(call); - afs_put_server(call->net, call->cm_server); + afs_put_server(call->net, call->server); afs_put_cb_interest(call->net, call->cbi); afs_put_addrlist(call->alist); kfree(call->request); @@ -696,10 +696,9 @@ long afs_wait_for_call_to_complete(struct afs_call *call, ret = ac->error; switch (ret) { case 0: - if (call->ret_reply0) { - ret = (long)call->reply[0]; - call->reply[0] = NULL; - } + ret = call->ret0; + call->ret0 = 0; + /* Fall through */ case -ECONNABORTED: ac->responded = true; diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c index b05e0de04f42..beb991563939 100644 --- a/fs/afs/vl_probe.c +++ b/fs/afs/vl_probe.c @@ -33,8 +33,8 @@ static bool afs_vl_probe_done(struct afs_vlserver *server) void afs_vlserver_probe_result(struct afs_call *call) { struct afs_addr_list *alist = call->alist; - struct afs_vlserver *server = call->reply[0]; - unsigned int server_index = (long)call->reply[1]; + struct afs_vlserver *server = call->vlserver; + unsigned int server_index = call->server_index; unsigned int index = call->addr_ix; unsigned int rtt = UINT_MAX; bool have_result = false; diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 7c53768a360b..06d010abee96 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c @@ -34,7 +34,7 @@ static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call) /* unmarshall the reply once we've received all of it */ uvldb = call->buffer; - entry = call->reply[0]; + entry = call->ret_vldb; nr_servers = ntohl(uvldb->nServers); if (nr_servers > AFS_NMAXNSERVERS) @@ -110,7 +110,7 @@ static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call) static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call) { - kfree(call->reply[0]); + kfree(call->ret_vldb); afs_flat_call_destructor(call); } @@ -155,8 +155,7 @@ struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_vl_cursor *vc, } call->key = vc->key; - call->reply[0] = entry; - call->ret_reply0 = true; + call->ret_vldb = entry; call->max_lifespan = AFS_VL_MAX_LIFESPAN; /* Marshall the parameters */ @@ -215,7 +214,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) if (!alist) return -ENOMEM; alist->version = uniquifier; - call->reply[0] = alist; + call->ret_alist = alist; call->count = count; call->count2 = nentries; call->unmarshall++; @@ -230,7 +229,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) if (ret < 0) return ret; - alist = call->reply[0]; + alist = call->ret_alist; bp = call->buffer; count = min(call->count, 4U); for (i = 0; i < count; i++) @@ -250,8 +249,7 @@ static int afs_deliver_vl_get_addrs_u(struct afs_call *call) static void afs_vl_get_addrs_u_destructor(struct afs_call *call) { - afs_put_server(call->net, (struct afs_server *)call->reply[0]); - kfree(call->reply[1]); + afs_put_addrlist(call->ret_alist); return afs_flat_call_destructor(call); } @@ -288,8 +286,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc, return ERR_PTR(-ENOMEM); call->key = vc->key; - call->reply[0] = NULL; - call->ret_reply0 = true; + call->ret_alist = NULL; call->max_lifespan = AFS_VL_MAX_LIFESPAN; /* Marshall the parameters */ @@ -360,9 +357,7 @@ static int afs_deliver_vl_get_capabilities(struct afs_call *call) static void afs_destroy_vl_get_capabilities(struct afs_call *call) { - struct afs_vlserver *server = call->reply[0]; - - afs_put_vlserver(call->net, server); + afs_put_vlserver(call->net, call->vlserver); afs_flat_call_destructor(call); } @@ -400,8 +395,8 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net, return ERR_PTR(-ENOMEM); call->key = key; - call->reply[0] = afs_get_vlserver(server); - call->reply[1] = (void *)(long)server_index; + call->vlserver = afs_get_vlserver(server); + call->server_index = server_index; call->upgrade = true; call->want_reply_time = true; call->async = true; @@ -463,7 +458,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) if (!alist) return -ENOMEM; alist->version = uniquifier; - call->reply[0] = alist; + call->ret_alist = alist; if (call->count == 0) goto extract_volendpoints; @@ -491,7 +486,7 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) if (ret < 0) return ret; - alist = call->reply[0]; + alist = call->ret_alist; bp = call->buffer; switch (call->count2) { case YFS_ENDPOINT_IPV4: @@ -612,7 +607,6 @@ static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) break; } - alist = call->reply[0]; _leave(" = 0 [done]"); return 0; } @@ -647,8 +641,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc, return ERR_PTR(-ENOMEM); call->key = vc->key; - call->reply[0] = NULL; - call->ret_reply0 = true; + call->ret_alist = NULL; call->max_lifespan = AFS_VL_MAX_LIFESPAN; /* Marshall the parameters */ diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 3f6d50edf498..a815d22f62f1 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -445,7 +445,7 @@ static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp, */ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -462,7 +462,7 @@ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call) if (ret < 0) return ret; xdr_decode_YFSCallBack(call, vnode, &bp); - xdr_decode_YFSVolSync(&bp, call->reply[1]); + xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -504,8 +504,8 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy } call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = volsync; + call->xvnode = vnode; + call->out_volsync = volsync; call->expected_version = new_inode ? 1 : vnode->status.data_version; /* marshall the parameters */ @@ -528,8 +528,8 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy */ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; - struct afs_read *req = call->reply[2]; + struct afs_vnode *vnode = call->xvnode; + struct afs_read *req = call->read_request; const __be32 *bp; unsigned int size; int ret; @@ -628,7 +628,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) if (ret < 0) return ret; xdr_decode_YFSCallBack(call, vnode, &bp); - xdr_decode_YFSVolSync(&bp, call->reply[1]); + xdr_decode_YFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -652,9 +652,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) static void yfs_fetch_data_destructor(struct afs_call *call) { - struct afs_read *req = call->reply[2]; - - afs_put_read(req); + afs_put_read(call->read_request); afs_flat_call_destructor(call); } @@ -693,9 +691,9 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = NULL; /* volsync */ - call->reply[2] = req; + call->xvnode = vnode; + call->out_volsync = NULL; + call->read_request = req; call->expected_version = vnode->status.data_version; call->want_reply_time = true; @@ -722,7 +720,7 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) */ static int yfs_deliver_fs_create_vnode(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -734,15 +732,15 @@ static int yfs_deliver_fs_create_vnode(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - xdr_decode_YFSFid(&bp, call->reply[1]); - ret = yfs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL); + xdr_decode_YFSFid(&bp, call->out_fid); + ret = yfs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); if (ret < 0) return ret; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, + ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, &call->expected_version, NULL); if (ret < 0) return ret; - xdr_decode_YFSCallBack_raw(call, call->reply[3], &bp); + xdr_decode_YFSCallBack_raw(call, call->out_cb, &bp); xdr_decode_YFSVolSync(&bp, NULL); _leave(" = 0 [done]"); @@ -770,9 +768,9 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc, struct afs_file_status *newstatus, struct afs_callback *newcb) { - struct afs_vnode *vnode = fc->vnode; + struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; - struct afs_net *net = afs_v2net(vnode); + struct afs_net *net = afs_v2net(dvnode); size_t namesz, reqsz, rplsz; __be32 *bp; @@ -796,24 +794,24 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = newfid; - call->reply[2] = newstatus; - call->reply[3] = newcb; + call->dvnode = dvnode; + call->out_fid = newfid; + call->out_extra_status = newstatus; + call->out_cb = newcb; call->expected_version = current_data_version + 1; /* marshall the parameters */ bp = call->request; bp = xdr_encode_u32(bp, YFSCREATEFILE); bp = xdr_encode_u32(bp, 0); /* RPC flags */ - bp = xdr_encode_YFSFid(bp, &vnode->fid); + bp = xdr_encode_YFSFid(bp, &dvnode->fid); bp = xdr_encode_string(bp, name, namesz); bp = xdr_encode_YFSStoreStatus_mode(bp, mode); bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */ yfs_check_req(call, bp); afs_use_fs_server(call, fc->cbi); - trace_afs_make_fs_call1(call, &vnode->fid, name); + trace_afs_make_fs_call1(call, &dvnode->fid, name); afs_set_fc_call(call, fc); afs_make_call(&fc->ac, call, GFP_NOFS); return afs_wait_for_call_to_complete(call, &fc->ac); @@ -837,9 +835,9 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc, struct afs_file_status *newstatus, struct afs_callback *newcb) { - struct afs_vnode *vnode = fc->vnode; + struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; - struct afs_net *net = afs_v2net(vnode); + struct afs_net *net = afs_v2net(dvnode); size_t namesz, reqsz, rplsz; __be32 *bp; @@ -862,23 +860,23 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = newfid; - call->reply[2] = newstatus; - call->reply[3] = newcb; + call->dvnode = dvnode; + call->out_fid = newfid; + call->out_extra_status = newstatus; + call->out_cb = newcb; call->expected_version = current_data_version + 1; /* marshall the parameters */ bp = call->request; bp = xdr_encode_u32(bp, YFSMAKEDIR); bp = xdr_encode_u32(bp, 0); /* RPC flags */ - bp = xdr_encode_YFSFid(bp, &vnode->fid); + bp = xdr_encode_YFSFid(bp, &dvnode->fid); bp = xdr_encode_string(bp, name, namesz); bp = xdr_encode_YFSStoreStatus_mode(bp, mode); yfs_check_req(call, bp); afs_use_fs_server(call, fc->cbi); - trace_afs_make_fs_call1(call, &vnode->fid, name); + trace_afs_make_fs_call1(call, &dvnode->fid, name); afs_set_fc_call(call, fc); afs_make_call(&fc->ac, call, GFP_NOFS); return afs_wait_for_call_to_complete(call, &fc->ac); @@ -889,8 +887,8 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_remove_file2(struct afs_call *call) { - struct afs_vnode *dvnode = call->reply[0]; - struct afs_vnode *vnode = call->reply[1]; + struct afs_vnode *dvnode = call->dvnode; + struct afs_vnode *vnode = call->xvnode; struct afs_fid fid; const __be32 *bp; int ret; @@ -957,8 +955,8 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = vnode; + call->dvnode = dvnode; + call->xvnode = vnode; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -981,7 +979,7 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_remove(struct afs_call *call) { - struct afs_vnode *dvnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -1046,8 +1044,8 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = vnode; + call->dvnode = dvnode; + call->xvnode = vnode; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -1070,7 +1068,7 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_link(struct afs_call *call) { - struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1]; + struct afs_vnode *dvnode = call->dvnode, *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1132,8 +1130,8 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = vnode; + call->dvnode = dvnode; + call->xvnode = vnode; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -1157,7 +1155,7 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_symlink(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -1169,11 +1167,11 @@ static int yfs_deliver_fs_symlink(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - xdr_decode_YFSFid(&bp, call->reply[1]); - ret = yfs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL); + xdr_decode_YFSFid(&bp, call->out_fid); + ret = yfs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); if (ret < 0) return ret; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, + ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, &call->expected_version, NULL); if (ret < 0) return ret; @@ -1228,9 +1226,9 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = dvnode; - call->reply[1] = newfid; - call->reply[2] = newstatus; + call->dvnode = dvnode; + call->out_fid = newfid; + call->out_extra_status = newstatus; call->expected_version = current_data_version + 1; /* marshall the parameters */ @@ -1255,8 +1253,8 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_rename(struct afs_call *call) { - struct afs_vnode *orig_dvnode = call->reply[0]; - struct afs_vnode *new_dvnode = call->reply[1]; + struct afs_vnode *orig_dvnode = call->dvnode; + struct afs_vnode *new_dvnode = call->xvnode; const __be32 *bp; int ret; @@ -1328,8 +1326,8 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->reply[0] = orig_dvnode; - call->reply[1] = new_dvnode; + call->dvnode = orig_dvnode; + call->xvnode = new_dvnode; call->expected_version = current_orig_data_version + 1; call->expected_version_2 = current_new_data_version + 1; @@ -1355,7 +1353,7 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_store_data(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1432,7 +1430,7 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, call->key = fc->key; call->mapping = mapping; - call->reply[0] = vnode; + call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; @@ -1463,7 +1461,7 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, */ static int yfs_deliver_fs_store_status(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1527,7 +1525,7 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->expected_version = vnode->status.data_version + 1; /* marshall the parameters */ @@ -1575,7 +1573,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->expected_version = vnode->status.data_version; /* marshall the parameters */ @@ -1618,7 +1616,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) return ret; bp = call->buffer; - xdr_decode_YFSFetchVolumeStatus(&bp, call->reply[1]); + xdr_decode_YFSFetchVolumeStatus(&bp, call->out_volstatus); call->unmarshall++; afs_extract_to_tmp(call); @@ -1634,7 +1632,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_volname_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the volume name */ @@ -1644,7 +1642,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("volname '%s'", p); afs_extract_to_tmp(call); @@ -1662,7 +1660,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_offline_msg_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the offline message */ @@ -1672,7 +1670,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("offline '%s'", p); @@ -1691,7 +1689,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) return afs_protocol_error(call, -EBADMSG, afs_eproto_motd_len); size = (call->count + 3) & ~3; /* It's padded */ - afs_extract_begin(call, call->reply[2], size); + afs_extract_to_buf(call, size); call->unmarshall++; /* Fall through - and extract the message of the day */ @@ -1701,7 +1699,7 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) if (ret < 0) return ret; - p = call->reply[2]; + p = call->buffer; p[call->count] = 0; _debug("motd '%s'", p); @@ -1716,16 +1714,6 @@ static int yfs_deliver_fs_get_volume_status(struct afs_call *call) return 0; } -/* - * Destroy a YFS.GetVolumeStatus call. - */ -static void yfs_get_volume_status_call_destructor(struct afs_call *call) -{ - kfree(call->reply[2]); - call->reply[2] = NULL; - afs_flat_call_destructor(call); -} - /* * YFS.GetVolumeStatus operation type */ @@ -1733,7 +1721,7 @@ static const struct afs_call_type yfs_RXYFSGetVolumeStatus = { .name = "YFS.GetVolumeStatus", .op = yfs_FS_GetVolumeStatus, .deliver = yfs_deliver_fs_get_volume_status, - .destructor = yfs_get_volume_status_call_destructor, + .destructor = afs_flat_call_destructor, }; /* @@ -1746,28 +1734,21 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc, struct afs_call *call; struct afs_net *net = afs_v2net(vnode); __be32 *bp; - void *tmpbuf; _enter(""); - tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); - if (!tmpbuf) - return -ENOMEM; - call = afs_alloc_flat_call(net, &yfs_RXYFSGetVolumeStatus, sizeof(__be32) * 2 + sizeof(struct yfs_xdr_u64), - sizeof(struct yfs_xdr_YFSFetchVolumeStatus) + - sizeof(__be32)); - if (!call) { - kfree(tmpbuf); + max_t(size_t, + sizeof(struct yfs_xdr_YFSFetchVolumeStatus) + + sizeof(__be32), + AFSOPAQUEMAX + 1)); + if (!call) return -ENOMEM; - } call->key = fc->key; - call->reply[0] = vnode; - call->reply[1] = vs; - call->reply[2] = tmpbuf; + call->out_volstatus = vs; /* marshall the parameters */ bp = call->request; @@ -1789,7 +1770,7 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc, */ static int yfs_deliver_status_and_volsync(struct afs_call *call) { - struct afs_vnode *vnode = call->reply[0]; + struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1865,7 +1846,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->want_reply_time = true; /* marshall the parameters */ @@ -1904,7 +1885,7 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; call->want_reply_time = true; /* marshall the parameters */ @@ -1942,7 +1923,7 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->reply[0] = vnode; + call->xvnode = vnode; /* marshall the parameters */ bp = call->request; @@ -1963,10 +1944,9 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc) */ static int yfs_deliver_fs_fetch_status(struct afs_call *call) { - struct afs_file_status *status = call->reply[1]; - struct afs_callback *callback = call->reply[2]; - struct afs_volsync *volsync = call->reply[3]; - struct afs_vnode *vnode = call->reply[0]; + struct afs_file_status *status = call->out_extra_status; + struct afs_callback *callback = call->out_cb; + struct afs_volsync *volsync = call->out_volsync; const __be32 *bp; int ret; @@ -1974,11 +1954,11 @@ static int yfs_deliver_fs_fetch_status(struct afs_call *call) if (ret < 0) return ret; - _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); + _enter(""); /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, status, vnode, + ret = yfs_decode_status(call, &bp, status, NULL, &call->expected_version, NULL); if (ret < 0) return ret; @@ -2027,10 +2007,9 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[0] = NULL; /* vnode for fid[0] */ - call->reply[1] = status; - call->reply[2] = callback; - call->reply[3] = volsync; + call->out_extra_status = status; + call->out_cb = callback; + call->out_volsync = volsync; call->expected_version = 1; /* vnode->status.data_version */ /* marshall the parameters */ @@ -2093,7 +2072,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - statuses = call->reply[1]; + statuses = call->out_extra_status; ret = yfs_decode_status(call, &bp, &statuses[call->count], NULL, NULL, NULL); if (ret < 0) @@ -2134,7 +2113,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; - callbacks = call->reply[2]; + callbacks = call->out_cb; xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); call->count++; if (call->count < call->count2) @@ -2150,7 +2129,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - xdr_decode_YFSVolSync(&bp, call->reply[3]); + xdr_decode_YFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -2203,9 +2182,9 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[1] = statuses; - call->reply[2] = callbacks; - call->reply[3] = volsync; + call->out_extra_status = statuses; + call->out_cb = callbacks; + call->out_volsync = volsync; call->count2 = nr_fids; /* marshall the parameters */ @@ -2230,9 +2209,9 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) { - struct afs_volsync *volsync = call->reply[2]; - struct afs_vnode *vnode = call->reply[1]; - struct yfs_acl *yacl = call->reply[0]; + struct afs_volsync *volsync = call->out_volsync; + struct afs_vnode *vnode = call->xvnode; + struct yfs_acl *yacl = call->out_yacl; struct afs_acl *acl; const __be32 *bp; unsigned int size; @@ -2378,9 +2357,9 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, } call->key = fc->key; - call->reply[0] = yacl; - call->reply[1] = vnode; - call->reply[2] = NULL; /* volsync */ + call->out_yacl = yacl; + call->xvnode = vnode; + call->out_volsync = NULL; /* volsync */ /* marshall the parameters */ bp = call->request; @@ -2433,8 +2412,8 @@ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl } call->key = fc->key; - call->reply[0] = vnode; - call->reply[2] = NULL; /* volsync */ + call->xvnode = vnode; + call->out_volsync = NULL; /* marshall the parameters */ bp = call->request; -- cgit v1.2.3 From 87182759cd6f94875d6aaaac74eaa52aa6aa6f98 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 16:17:05 +0100 Subject: afs: Fix order-1 allocation in afs_do_lookup() afs_do_lookup() will do an order-1 allocation to allocate status records if there are more than 39 vnodes to stat. Fix this by allocating an array of {status,callback} records for each vnode we want to examine using vmalloc() if larger than a page. This not only gets rid of the order-1 allocation, but makes it easier to grow beyond 50 records for YFS servers. It also allows us to move to {status,callback} tuples for other calls too and makes it easier to lock across the application of the status and the callback to the vnode. Fixes: 5cf9dd55a0ec ("afs: Prospectively look up extra files when doing a single lookup") Signed-off-by: David Howells --- fs/afs/afs.h | 6 ++++++ fs/afs/dir.c | 37 ++++++++++++++++--------------------- fs/afs/fsclient.c | 21 +++++++++------------ fs/afs/internal.h | 11 +++++------ fs/afs/yfsclient.c | 20 +++++++++----------- 5 files changed, 45 insertions(+), 50 deletions(-) (limited to 'fs') diff --git a/fs/afs/afs.h b/fs/afs/afs.h index 74913c707bba..8fa0dffff1cc 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h @@ -147,6 +147,12 @@ struct afs_file_status { u32 abort_code; /* Abort if bulk-fetching this failed */ }; +struct afs_status_cb { + struct afs_file_status status; + struct afs_callback callback; + bool have_cb; /* True if cb record was retrieved */ +}; + /* * AFS file status change request */ diff --git a/fs/afs/dir.c b/fs/afs/dir.c index c15550310f62..0f14bcfe233d 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -102,8 +102,7 @@ struct afs_lookup_cookie { bool found; bool one_only; unsigned short nr_fids; - struct afs_file_status *statuses; - struct afs_callback *callbacks; + struct afs_status_cb *statuses; struct afs_fid fids[50]; }; @@ -640,6 +639,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct afs_lookup_cookie *cookie; struct afs_cb_interest *cbi = NULL; struct afs_super_info *as = dir->i_sb->s_fs_info; + struct afs_status_cb *scb; struct afs_iget_data data; struct afs_fs_cursor fc; struct afs_vnode *dvnode = AFS_FS_I(dir); @@ -686,16 +686,11 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, /* Need space for examining all the selected files */ inode = ERR_PTR(-ENOMEM); - cookie->statuses = kcalloc(cookie->nr_fids, sizeof(struct afs_file_status), - GFP_KERNEL); + cookie->statuses = kvcalloc(cookie->nr_fids, sizeof(struct afs_status_cb), + GFP_KERNEL); if (!cookie->statuses) goto out; - cookie->callbacks = kcalloc(cookie->nr_fids, sizeof(struct afs_callback), - GFP_KERNEL); - if (!cookie->callbacks) - goto out_s; - /* Try FS.InlineBulkStatus first. Abort codes for the individual * lookups contained therein are stored in the reply without aborting * the whole operation. @@ -716,7 +711,6 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, afs_v2net(dvnode), cookie->fids, cookie->statuses, - cookie->callbacks, cookie->nr_fids, NULL); } @@ -741,11 +735,12 @@ no_inline_bulk_status: inode = ERR_PTR(-ERESTARTSYS); if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { while (afs_select_fileserver(&fc)) { + scb = &cookie->statuses[0]; afs_fs_fetch_status(&fc, afs_v2net(dvnode), cookie->fids, - cookie->statuses, - cookie->callbacks, + &scb->status, + &scb->callback, NULL); } @@ -758,24 +753,26 @@ no_inline_bulk_status: goto out_c; for (i = 0; i < cookie->nr_fids; i++) - cookie->statuses[i].abort_code = 0; + cookie->statuses[i].status.abort_code = 0; success: /* Turn all the files into inodes and save the first one - which is the * one we actually want. */ - if (cookie->statuses[0].abort_code != 0) - inode = ERR_PTR(afs_abort_to_error(cookie->statuses[0].abort_code)); + scb = &cookie->statuses[0]; + if (scb->status.abort_code != 0) + inode = ERR_PTR(afs_abort_to_error(scb->status.abort_code)); for (i = 0; i < cookie->nr_fids; i++) { + struct afs_status_cb *scb = &cookie->statuses[i]; struct inode *ti; - if (cookie->statuses[i].abort_code != 0) + if (scb->status.abort_code != 0) continue; ti = afs_iget(dir->i_sb, key, &cookie->fids[i], - &cookie->statuses[i], - &cookie->callbacks[i], + &scb->status, + &scb->callback, cbi, dvnode); if (i == 0) { inode = ti; @@ -787,9 +784,7 @@ success: out_c: afs_put_cb_interest(afs_v2net(dvnode), cbi); - kfree(cookie->callbacks); -out_s: - kfree(cookie->statuses); + kvfree(cookie->statuses); out: kfree(cookie); return inode; diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 16bcc578e3b2..eeba2a359fb4 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -2209,8 +2209,7 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) { - struct afs_file_status *statuses; - struct afs_callback *callbacks; + struct afs_status_cb *scb; const __be32 *bp; u32 tmp; int ret; @@ -2249,8 +2248,8 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - statuses = call->out_extra_status; - ret = afs_decode_status(call, &bp, &statuses[call->count], + scb = &call->out_scb[call->count]; + ret = afs_decode_status(call, &bp, &scb->status, NULL, NULL, NULL); if (ret < 0) return ret; @@ -2290,9 +2289,9 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; - callbacks = call->out_cb; - xdr_decode_AFSCallBack_raw(call, &callbacks[call->count], &bp); - statuses = call->out_extra_status; + scb = &call->out_scb[call->count]; + xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp); + scb->have_cb = true; call->count++; if (call->count < call->count2) goto more_cbs; @@ -2335,8 +2334,7 @@ static const struct afs_call_type afs_RXFSInlineBulkStatus = { int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, struct afs_net *net, struct afs_fid *fids, - struct afs_file_status *statuses, - struct afs_callback *callbacks, + struct afs_status_cb *statuses, unsigned int nr_fids, struct afs_volsync *volsync) { @@ -2345,7 +2343,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, int i; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_inline_bulk_status(fc, net, fids, statuses, callbacks, + return yfs_fs_inline_bulk_status(fc, net, fids, statuses, nr_fids, volsync); _enter(",%x,{%llx:%llu},%u", @@ -2360,8 +2358,7 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->out_extra_status = statuses; - call->out_cb = callbacks; + call->out_scb = statuses; call->out_volsync = volsync; call->count2 = nr_fids; call->want_reply_time = true; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 705833eb2d45..2a100be91721 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -137,6 +137,7 @@ struct afs_call { struct afs_file_status *out_vnode_status; struct afs_file_status *out_extra_status; struct afs_callback *out_cb; + struct afs_status_cb *out_scb; struct yfs_acl *out_yacl; struct afs_volsync *out_volsync; struct afs_volume_status *out_volstatus; @@ -991,9 +992,8 @@ extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_ser struct afs_addr_cursor *, struct key *, unsigned int); extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, - struct afs_fid *, struct afs_file_status *, - struct afs_callback *, unsigned int, - struct afs_volsync *); + struct afs_fid *, struct afs_status_cb *, + unsigned int, struct afs_volsync *); extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, struct afs_fid *, struct afs_file_status *, struct afs_callback *, struct afs_volsync *); @@ -1393,9 +1393,8 @@ extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, struct afs_fid *, struct afs_file_status *, struct afs_callback *, struct afs_volsync *); extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, - struct afs_fid *, struct afs_file_status *, - struct afs_callback *, unsigned int, - struct afs_volsync *); + struct afs_fid *, struct afs_status_cb *, + unsigned int, struct afs_volsync *); struct yfs_acl { struct afs_acl *acl; /* Dir/file/symlink ACL */ diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index a815d22f62f1..1f1ccf7b7822 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -338,7 +338,7 @@ static void xdr_decode_YFSCallBack(struct afs_call *call, struct afs_callback cb; xdr_decode_YFSCallBack_raw(call, &cb, _bp); - + write_seqlock(&vnode->cb_lock); if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { @@ -2032,8 +2032,7 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) { - struct afs_file_status *statuses; - struct afs_callback *callbacks; + struct afs_status_cb *scb; const __be32 *bp; u32 tmp; int ret; @@ -2072,8 +2071,8 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) return ret; bp = call->buffer; - statuses = call->out_extra_status; - ret = yfs_decode_status(call, &bp, &statuses[call->count], + scb = &call->out_scb[call->count]; + ret = yfs_decode_status(call, &bp, &scb->status, NULL, NULL, NULL); if (ret < 0) return ret; @@ -2113,8 +2112,9 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; - callbacks = call->out_cb; - xdr_decode_YFSCallBack_raw(call, &callbacks[call->count], &bp); + scb = &call->out_scb[call->count]; + xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp); + scb->have_cb = true; call->count++; if (call->count < call->count2) goto more_cbs; @@ -2158,8 +2158,7 @@ static const struct afs_call_type yfs_RXYFSInlineBulkStatus = { int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, struct afs_net *net, struct afs_fid *fids, - struct afs_file_status *statuses, - struct afs_callback *callbacks, + struct afs_status_cb *statuses, unsigned int nr_fids, struct afs_volsync *volsync) { @@ -2182,8 +2181,7 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->out_extra_status = statuses; - call->out_cb = callbacks; + call->out_scb = statuses; call->out_volsync = volsync; call->count2 = nr_fids; -- cgit v1.2.3 From 4571577f16c82f8db8133b228cdca5fd61042c77 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 May 2019 11:44:26 +0100 Subject: afs: Always get the reply time Always ask for the reply time from AF_RXRPC as it's used to calculate the callback expiry time and lock expiry times, so it's needed by most FS operations. Signed-off-by: David Howells --- fs/afs/fsclient.c | 9 --------- fs/afs/internal.h | 2 +- fs/afs/rxrpc.c | 4 ++-- fs/afs/vlclient.c | 1 - fs/afs/yfsclient.c | 3 --- 5 files changed, 3 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index eeba2a359fb4..d4bce3816978 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -453,7 +453,6 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy call->xvnode = vnode; call->out_volsync = volsync; call->expected_version = new_inode ? 1 : vnode->status.data_version; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -645,7 +644,6 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) call->out_volsync = NULL; call->read_request = req; call->expected_version = vnode->status.data_version; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -696,7 +694,6 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) call->out_volsync = NULL; call->read_request = req; call->expected_version = vnode->status.data_version; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -809,7 +806,6 @@ int afs_fs_create(struct afs_fs_cursor *fc, call->out_extra_status = newstatus; call->out_cb = newcb; call->expected_version = current_data_version + 1; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1887,7 +1883,6 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) call->key = fc->key; call->xvnode = vnode; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1925,7 +1920,6 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) call->key = fc->key; call->xvnode = vnode; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -2101,7 +2095,6 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net, call->server = afs_get_server(server); call->server_index = server_index; call->upgrade = true; - call->want_reply_time = true; call->async = true; call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; @@ -2187,7 +2180,6 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, call->out_cb = callback; call->out_volsync = volsync; call->expected_version = 1; /* vnode->status.data_version */ - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -2361,7 +2353,6 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, call->out_scb = statuses; call->out_volsync = volsync; call->count2 = nr_fids; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 2a100be91721..9b44307bd934 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -167,7 +167,7 @@ struct afs_call { bool need_attention; /* T if RxRPC poked us */ bool async; /* T if asynchronous */ bool upgrade; /* T to request service upgrade */ - bool want_reply_time; /* T if want reply_time */ + bool have_reply_time; /* T if have got reply_time */ bool intr; /* T if interruptible */ u16 service_id; /* Actual service ID (after upgrade) */ unsigned int debug_id; /* Trace ID */ diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index d63e0c9c09e7..4fa5ce92b9b9 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -534,11 +534,11 @@ static void afs_deliver_to_call(struct afs_call *call) return; } - if (call->want_reply_time && + if (!call->have_reply_time && rxrpc_kernel_get_reply_time(call->net->socket, call->rxcall, &call->reply_time)) - call->want_reply_time = false; + call->have_reply_time = true; ret = call->type->deliver(call); state = READ_ONCE(call->state); diff --git a/fs/afs/vlclient.c b/fs/afs/vlclient.c index 06d010abee96..3d4b9836a2e2 100644 --- a/fs/afs/vlclient.c +++ b/fs/afs/vlclient.c @@ -398,7 +398,6 @@ struct afs_call *afs_vl_get_capabilities(struct afs_net *net, call->vlserver = afs_get_vlserver(server); call->server_index = server_index; call->upgrade = true; - call->want_reply_time = true; call->async = true; call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 1f1ccf7b7822..b3ee99972d2f 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -695,7 +695,6 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) call->out_volsync = NULL; call->read_request = req; call->expected_version = vnode->status.data_version; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1847,7 +1846,6 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) call->key = fc->key; call->xvnode = vnode; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; @@ -1886,7 +1884,6 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc) call->key = fc->key; call->xvnode = vnode; - call->want_reply_time = true; /* marshall the parameters */ bp = call->request; -- cgit v1.2.3 From a58823ac458968f9fb3dbf97ee2749a62be12807 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 15:16:10 +0100 Subject: afs: Fix application of status and callback to be under same lock When applying the status and callback in the response of an operation, apply them in the same critical section so that there's no race between checking the callback state and checking status-dependent state (such as the data version). Fix this by: (1) Allocating a joint {status,callback} record (afs_status_cb) before calling the RPC function for each vnode for which the RPC reply contains a status or a status plus a callback. A flag is set in the record to indicate if a callback was actually received. (2) These records are passed into the RPC functions to be filled in. The afs_decode_status() and yfs_decode_status() functions are removed and the cb_lock is no longer taken. (3) xdr_decode_AFSFetchStatus() and xdr_decode_YFSFetchStatus() no longer update the vnode. (4) xdr_decode_AFSCallBack() and xdr_decode_YFSCallBack() no longer update the vnode. (5) vnodes, expected data-version numbers and callback break counters (cb_break) no longer need to be passed to the reply delivery functions. Note that, for the moment, the file locking functions still need access to both the call and the vnode at the same time. (6) afs_vnode_commit_status() is now given the cb_break value and the expected data_version and the task of applying the status and the callback to the vnode are now done here. This is done under a single taking of vnode->cb_lock. (7) afs_pages_written_back() is now called by afs_store_data() rather than by the reply delivery function. afs_pages_written_back() has been moved to before the call point and is now given the first and last page numbers rather than a pointer to the call. (8) The indicator from YFS.RemoveFile2 as to whether the target file actually got removed (status.abort_code == VNOVNODE) rather than merely dropping a link is now checked in afs_unlink rather than in xdr_decode_YFSFetchStatus(). Supplementary fixes: (*) afs_cache_permit() now gets the caller_access mask from the afs_status_cb object rather than picking it out of the vnode's status record. afs_fetch_status() returns caller_access through its argument list for this purpose also. (*) afs_inode_init_from_status() now uses a write lock on cb_lock rather than a read lock and now sets the callback inside the same critical section. Fixes: c435ee34551e ("afs: Overhaul the callback handling") Signed-off-by: David Howells --- fs/afs/dir.c | 204 +++++++++++++------- fs/afs/dir_silly.c | 31 +++- fs/afs/file.c | 20 +- fs/afs/flock.c | 40 ++-- fs/afs/fsclient.c | 465 +++++++++++++--------------------------------- fs/afs/inode.c | 286 ++++++++++++++++++++++------ fs/afs/internal.h | 134 +++++++------- fs/afs/security.c | 7 +- fs/afs/super.c | 3 +- fs/afs/write.c | 98 +++++----- fs/afs/xattr.c | 103 ++++++++--- fs/afs/yfsclient.c | 534 +++++++++++++++-------------------------------------- 12 files changed, 921 insertions(+), 1004 deletions(-) (limited to 'fs') diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 0f14bcfe233d..f7344b045799 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -18,6 +18,7 @@ #include #include #include "internal.h" +#include "afs_fs.h" #include "xdr_fs.h" static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, @@ -739,8 +740,7 @@ no_inline_bulk_status: afs_fs_fetch_status(&fc, afs_v2net(dvnode), cookie->fids, - &scb->status, - &scb->callback, + scb, NULL); } @@ -771,9 +771,7 @@ success: continue; ti = afs_iget(dir->i_sb, key, &cookie->fids[i], - &scb->status, - &scb->callback, - cbi, dvnode); + scb, cbi, dvnode); if (i == 0) { inode = ti; } else { @@ -1110,8 +1108,7 @@ void afs_d_release(struct dentry *dentry) static void afs_vnode_new_inode(struct afs_fs_cursor *fc, struct dentry *new_dentry, struct afs_fid *newfid, - struct afs_file_status *newstatus, - struct afs_callback *newcb) + struct afs_status_cb *new_scb) { struct afs_vnode *vnode; struct inode *inode; @@ -1120,7 +1117,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, return; inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key, - newfid, newstatus, newcb, fc->cbi, fc->vnode); + newfid, new_scb, fc->cbi, fc->vnode); if (IS_ERR(inode)) { /* ENOMEM or EINTR at a really inconvenient time - just abandon * the new directory on the server. @@ -1131,7 +1128,8 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, vnode = AFS_FS_I(inode); set_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); - afs_vnode_commit_status(fc, vnode, 0); + if (fc->ac.error == 0) + afs_cache_permit(vnode, fc->key, vnode->cb_break, new_scb); d_instantiate(new_dentry, inode); } @@ -1140,13 +1138,11 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, */ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { - struct afs_file_status newstatus; + struct afs_status_cb *scb; struct afs_fs_cursor fc; - struct afs_callback newcb; struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_fid newfid; struct key *key; - u64 data_version = dvnode->status.data_version; int ret; mode |= S_IFDIR; @@ -1154,23 +1150,31 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) _enter("{%llx:%llu},{%pd},%ho", dvnode->fid.vid, dvnode->fid.vnode, dentry, mode); + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); - afs_fs_create(&fc, dentry->d_name.name, mode, data_version, - &newfid, &newstatus, &newcb); + afs_fs_create(&fc, dentry->d_name.name, mode, + &scb[0], &newfid, &scb[1]); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); - afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb); + afs_check_for_remote_deletion(&fc, dvnode); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, &scb[0]); + afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1184,11 +1188,14 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) afs_edit_dir_for_create); key_put(key); + kfree(scb); _leave(" = 0"); return 0; error_key: key_put(key); +error_scb: + kfree(scb); error: d_drop(dentry); _leave(" = %d", ret); @@ -1215,15 +1222,19 @@ static void afs_dir_remove_subdir(struct dentry *dentry) */ static int afs_rmdir(struct inode *dir, struct dentry *dentry) { + struct afs_status_cb *scb; struct afs_fs_cursor fc; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; struct key *key; - u64 data_version = dvnode->status.data_version; int ret; _enter("{%llx:%llu},{%pd}", dvnode->fid.vid, dvnode->fid.vnode, dentry); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); @@ -1246,13 +1257,15 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); - afs_fs_remove(&fc, vnode, dentry->d_name.name, true, - data_version); + afs_fs_remove(&fc, vnode, dentry->d_name.name, true, scb); } - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); if (ret == 0) { afs_dir_remove_subdir(dentry); @@ -1267,6 +1280,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) error_key: key_put(key); error: + kfree(scb); return ret; } @@ -1326,11 +1340,11 @@ int afs_dir_remove_link(struct dentry *dentry, struct key *key, static int afs_unlink(struct inode *dir, struct dentry *dentry) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; struct key *key; unsigned long d_version = (unsigned long)dentry->d_fsdata; bool need_rehash = false; - u64 data_version = dvnode->status.data_version; int ret; _enter("{%llx:%llu},{%pd}", @@ -1339,10 +1353,15 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) if (dentry->d_name.len >= AFSNAMEMAX) return -ENAMETOOLONG; + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } /* Try to make sure we have a callback promise on the victim. */ @@ -1370,24 +1389,32 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) && !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) { yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name, - data_version); + &scb[0], &scb[1]); + if (fc.ac.error == 0 && + scb[1].status.abort_code == VNOVNODE) { + set_bit(AFS_VNODE_DELETED, &vnode->flags); + afs_break_callback(vnode); + } + if (fc.ac.error != -ECONNABORTED || fc.ac.abort_code != RXGEN_OPCODE) continue; set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags); } - afs_fs_remove(&fc, vnode, dentry->d_name.name, false, - data_version); + afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]); } - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, &scb[0]); ret = afs_end_vnode_operation(&fc); if (ret == 0) ret = afs_dir_remove_link( @@ -1404,6 +1431,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) error_key: key_put(key); +error_scb: + kfree(scb); error: _leave(" = %d", ret); return ret; @@ -1416,12 +1445,10 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct afs_fs_cursor fc; - struct afs_file_status newstatus; - struct afs_callback newcb; + struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_fid newfid; struct key *key; - u64 data_version = dvnode->status.data_version; int ret; mode |= S_IFREG; @@ -1439,17 +1466,25 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, goto error; } + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error_scb; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); - afs_fs_create(&fc, dentry->d_name.name, mode, data_version, - &newfid, &newstatus, &newcb); + afs_fs_create(&fc, dentry->d_name.name, mode, + &scb[0], &newfid, &scb[1]); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); - afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, &newcb); + afs_check_for_remote_deletion(&fc, dvnode); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, &scb[0]); + afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1461,10 +1496,13 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, afs_edit_dir_for_create); + kfree(scb); key_put(key); _leave(" = 0"); return 0; +error_scb: + kfree(scb); error_key: key_put(key); error: @@ -1480,15 +1518,12 @@ static int afs_link(struct dentry *from, struct inode *dir, struct dentry *dentry) { struct afs_fs_cursor fc; - struct afs_vnode *dvnode, *vnode; + struct afs_status_cb *scb; + struct afs_vnode *dvnode = AFS_FS_I(dir); + struct afs_vnode *vnode = AFS_FS_I(d_inode(from)); struct key *key; - u64 data_version; int ret; - vnode = AFS_FS_I(d_inode(from)); - dvnode = AFS_FS_I(dir); - data_version = dvnode->status.data_version; - _enter("{%llx:%llu},{%llx:%llu},{%pd}", vnode->fid.vid, vnode->fid.vnode, dvnode->fid.vid, dvnode->fid.vnode, @@ -1498,14 +1533,21 @@ static int afs_link(struct dentry *from, struct inode *dir, if (dentry->d_name.len >= AFSNAMEMAX) goto error; + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + if (mutex_lock_interruptible_nested(&vnode->io_lock, 1) < 0) { afs_end_vnode_operation(&fc); goto error_key; @@ -1514,11 +1556,14 @@ static int afs_link(struct dentry *from, struct inode *dir, while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); fc.cb_break_2 = afs_calc_vnode_cb_break(vnode); - afs_fs_link(&fc, vnode, dentry->d_name.name, data_version); + afs_fs_link(&fc, vnode, dentry->d_name.name, + &scb[0], &scb[1]); } - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); - afs_vnode_commit_status(&fc, vnode, fc.cb_break_2); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, &scb[0]); + afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, + NULL, &scb[1]); ihold(&vnode->vfs_inode); d_instantiate(dentry, &vnode->vfs_inode); @@ -1535,11 +1580,14 @@ static int afs_link(struct dentry *from, struct inode *dir, afs_edit_dir_for_link); key_put(key); + kfree(scb); _leave(" = 0"); return 0; error_key: key_put(key); +error_scb: + kfree(scb); error: d_drop(dentry); _leave(" = %d", ret); @@ -1553,11 +1601,10 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content) { struct afs_fs_cursor fc; - struct afs_file_status newstatus; + struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); struct afs_fid newfid; struct key *key; - u64 data_version = dvnode->status.data_version; int ret; _enter("{%llx:%llu},{%pd},%s", @@ -1572,24 +1619,31 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, if (strlen(content) >= AFSPATHMAX) goto error; + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + key = afs_request_key(dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); - afs_fs_symlink(&fc, dentry->d_name.name, - content, data_version, - &newfid, &newstatus); + afs_fs_symlink(&fc, dentry->d_name.name, content, + &scb[0], &newfid, &scb[1]); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); - afs_vnode_new_inode(&fc, dentry, &newfid, &newstatus, NULL); + afs_check_for_remote_deletion(&fc, dvnode); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &data_version, &scb[0]); + afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1602,11 +1656,14 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, afs_edit_dir_for_symlink); key_put(key); + kfree(scb); _leave(" = 0"); return 0; error_key: key_put(key); +error_scb: + kfree(scb); error: d_drop(dentry); _leave(" = %d", ret); @@ -1621,11 +1678,11 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, unsigned int flags) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *orig_dvnode, *new_dvnode, *vnode; struct dentry *tmp = NULL, *rehash = NULL; struct inode *new_inode; struct key *key; - u64 orig_data_version, new_data_version; bool new_negative = d_is_negative(new_dentry); int ret; @@ -1639,8 +1696,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, vnode = AFS_FS_I(d_inode(old_dentry)); orig_dvnode = AFS_FS_I(old_dir); new_dvnode = AFS_FS_I(new_dir); - orig_data_version = orig_dvnode->status.data_version; - new_data_version = new_dvnode->status.data_version; _enter("{%llx:%llu},{%llx:%llu},{%llx:%llu},{%pd}", orig_dvnode->fid.vid, orig_dvnode->fid.vnode, @@ -1648,10 +1703,15 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dvnode->fid.vid, new_dvnode->fid.vnode, new_dentry); + ret = -ENOMEM; + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + key = afs_request_key(orig_dvnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } /* For non-directories, check whether the target is busy and if so, @@ -1685,31 +1745,43 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dentry = tmp; rehash = NULL; new_negative = true; - orig_data_version = orig_dvnode->status.data_version; - new_data_version = new_dvnode->status.data_version; } } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, orig_dvnode, key, true)) { + afs_dataversion_t orig_data_version; + afs_dataversion_t new_data_version; + struct afs_status_cb *new_scb = &scb[1]; + + orig_data_version = orig_dvnode->status.data_version + 1; + if (orig_dvnode != new_dvnode) { if (mutex_lock_interruptible_nested(&new_dvnode->io_lock, 1) < 0) { afs_end_vnode_operation(&fc); goto error_rehash; } + new_data_version = new_dvnode->status.data_version; + } else { + new_data_version = orig_data_version; + new_scb = &scb[0]; } + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(orig_dvnode); fc.cb_break_2 = afs_calc_vnode_cb_break(new_dvnode); afs_fs_rename(&fc, old_dentry->d_name.name, new_dvnode, new_dentry->d_name.name, - orig_data_version, new_data_version); + &scb[0], new_scb); } - afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break); - afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2); - if (orig_dvnode != new_dvnode) + afs_vnode_commit_status(&fc, orig_dvnode, fc.cb_break, + &orig_data_version, &scb[0]); + if (new_dvnode != orig_dvnode) { + afs_vnode_commit_status(&fc, new_dvnode, fc.cb_break_2, + &new_data_version, &scb[1]); mutex_unlock(&new_dvnode->io_lock); + } ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_rehash; @@ -1749,6 +1821,8 @@ error_tmp: if (tmp) dput(tmp); key_put(key); +error_scb: + kfree(scb); error: _leave(" = %d", ret); return ret; diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c index fbc2d301ffe8..28f4aa015229 100644 --- a/fs/afs/dir_silly.c +++ b/fs/afs/dir_silly.c @@ -24,21 +24,28 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode struct key *key) { struct afs_fs_cursor fc; - u64 dir_data_version = dvnode->status.data_version; + struct afs_status_cb *scb; int ret = -ERESTARTSYS; _enter("%pd,%pd", old, new); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + trace_afs_silly_rename(vnode, false); if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { + afs_dataversion_t dir_data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); afs_fs_rename(&fc, old->d_name.name, dvnode, new->d_name.name, - dir_data_version, dir_data_version); + scb, scb); } - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &dir_data_version, scb); ret = afs_end_vnode_operation(&fc); } @@ -64,6 +71,7 @@ static int afs_do_silly_rename(struct afs_vnode *dvnode, struct afs_vnode *vnode fsnotify_nameremove(old, 0); } + kfree(scb); _leave(" = %d", ret); return ret; } @@ -143,31 +151,37 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode struct dentry *dentry, struct key *key) { struct afs_fs_cursor fc; - u64 dir_data_version = dvnode->status.data_version; + struct afs_status_cb *scb; int ret = -ERESTARTSYS; _enter(""); + scb = kcalloc(2, sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + trace_afs_silly_rename(vnode, true); if (afs_begin_vnode_operation(&fc, dvnode, key, false)) { + afs_dataversion_t dir_data_version = dvnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) && !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) { yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name, - dir_data_version); + &scb[0], &scb[1]); if (fc.ac.error != -ECONNABORTED || fc.ac.abort_code != RXGEN_OPCODE) continue; set_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags); } - afs_fs_remove(&fc, vnode, dentry->d_name.name, false, - dir_data_version); + afs_fs_remove(&fc, vnode, dentry->d_name.name, false, &scb[0]); } - afs_vnode_commit_status(&fc, dvnode, fc.cb_break); + afs_vnode_commit_status(&fc, dvnode, fc.cb_break, + &dir_data_version, &scb[0]); ret = afs_end_vnode_operation(&fc); if (ret == 0) { drop_nlink(&vnode->vfs_inode); @@ -182,6 +196,7 @@ static int afs_do_silly_unlink(struct afs_vnode *dvnode, struct afs_vnode *vnode afs_edit_dir_for_unlink); } + kfree(scb); _leave(" = %d", ret); return ret; } diff --git a/fs/afs/file.c b/fs/afs/file.c index 415c84dddb89..11e69c5fb7ab 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -228,6 +228,7 @@ static void afs_file_readpage_read_complete(struct page *page, int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *desc) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; int ret; _enter("%s{%llx:%llu.%u},%x,,,", @@ -237,15 +238,22 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de vnode->fid.unique, key_serial(key)); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_fetch_data(&fc, desc); + afs_fs_fetch_data(&fc, scb, desc); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } @@ -255,6 +263,7 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de &afs_v2net(vnode)->n_fetch_bytes); } + kfree(scb); _leave(" = %d", ret); return ret; } @@ -405,10 +414,10 @@ static int afs_readpage(struct file *file, struct page *page) /* * Make pages available as they're filled. */ -static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req) +static void afs_readpages_page_done(struct afs_read *req) { #ifdef CONFIG_AFS_FSCACHE - struct afs_vnode *vnode = call->xvnode; + struct afs_vnode *vnode = req->vnode; #endif struct page *page = req->pages[req->index]; @@ -462,6 +471,7 @@ static int afs_readpages_one(struct file *file, struct address_space *mapping, return -ENOMEM; refcount_set(&req->usage, 1); + req->vnode = vnode; req->page_done = afs_readpages_page_done; req->pos = first->index; req->pos <<= PAGE_SHIFT; diff --git a/fs/afs/flock.c b/fs/afs/flock.c index ce8275940b99..ed3ac03682d7 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -74,7 +74,7 @@ static void afs_schedule_lock_extension(struct afs_vnode *vnode) */ void afs_lock_op_done(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; + struct afs_vnode *vnode = call->lvnode; if (call->error == 0) { spin_lock(&vnode->lock); @@ -182,6 +182,7 @@ static void afs_kill_lockers_enoent(struct afs_vnode *vnode) static int afs_set_lock(struct afs_vnode *vnode, struct key *key, afs_lock_type_t type) { + struct afs_status_cb *scb; struct afs_fs_cursor fc; int ret; @@ -192,18 +193,23 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key, vnode->fid.unique, key_serial(key), type); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_set_lock(&fc, type); + afs_fs_set_lock(&fc, type, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb); ret = afs_end_vnode_operation(&fc); } + kfree(scb); _leave(" = %d", ret); return ret; } @@ -213,6 +219,7 @@ static int afs_set_lock(struct afs_vnode *vnode, struct key *key, */ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) { + struct afs_status_cb *scb; struct afs_fs_cursor fc; int ret; @@ -223,18 +230,23 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) vnode->fid.unique, key_serial(key)); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, false)) { while (afs_select_current_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_extend_lock(&fc); + afs_fs_extend_lock(&fc, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb); ret = afs_end_vnode_operation(&fc); } + kfree(scb); _leave(" = %d", ret); return ret; } @@ -244,6 +256,7 @@ static int afs_extend_lock(struct afs_vnode *vnode, struct key *key) */ static int afs_release_lock(struct afs_vnode *vnode, struct key *key) { + struct afs_status_cb *scb; struct afs_fs_cursor fc; int ret; @@ -254,18 +267,23 @@ static int afs_release_lock(struct afs_vnode *vnode, struct key *key) vnode->fid.unique, key_serial(key)); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, false)) { while (afs_select_current_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_release_lock(&fc); + afs_fs_release_lock(&fc, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, NULL, scb); ret = afs_end_vnode_operation(&fc); } + kfree(scb); _leave(" = %d", ret); return ret; } @@ -733,7 +751,7 @@ static int afs_do_getlk(struct file *file, struct file_lock *fl) posix_test_lock(file, fl); if (fl->fl_type == F_UNLCK) { /* no local locks; consult the server */ - ret = afs_fetch_status(vnode, key, false); + ret = afs_fetch_status(vnode, key, false, NULL); if (ret < 0) goto error; diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index d4bce3816978..5c1b7a031509 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -59,79 +59,18 @@ static void xdr_dump_bad(const __be32 *bp) pr_notice("0x50: %08x\n", ntohl(x[0])); } -/* - * Update the core inode struct from a returned status record. - */ -void afs_update_inode_from_status(struct afs_vnode *vnode, - struct afs_file_status *status, - const afs_dataversion_t *expected_version, - u8 flags) -{ - struct timespec64 t; - umode_t mode; - - t = status->mtime_client; - vnode->vfs_inode.i_ctime = t; - vnode->vfs_inode.i_mtime = t; - vnode->vfs_inode.i_atime = t; - - if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) { - vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); - vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); - set_nlink(&vnode->vfs_inode, status->nlink); - - mode = vnode->vfs_inode.i_mode; - mode &= ~S_IALLUGO; - mode |= status->mode; - barrier(); - vnode->vfs_inode.i_mode = mode; - } - - if (!(flags & AFS_VNODE_NOT_YET_SET)) { - if (expected_version && - *expected_version != status->data_version) { - _debug("vnode modified %llx on {%llx:%llu} [exp %llx]", - (unsigned long long) status->data_version, - vnode->fid.vid, vnode->fid.vnode, - (unsigned long long) *expected_version); - vnode->invalid_before = status->data_version; - if (vnode->status.type == AFS_FTYPE_DIR) { - if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) - afs_stat_v(vnode, n_inval); - } else { - set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); - } - } else if (vnode->status.type == AFS_FTYPE_DIR) { - /* Expected directory change is handled elsewhere so - * that we can locally edit the directory and save on a - * download. - */ - if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) - flags &= ~AFS_VNODE_DATA_CHANGED; - } - } - - if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) { - inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); - i_size_write(&vnode->vfs_inode, status->size); - } -} - /* * decode an AFSFetchStatus block */ -static int xdr_decode_AFSFetchStatus(struct afs_call *call, - const __be32 **_bp, - struct afs_file_status *status, - struct afs_vnode *vnode, - const afs_dataversion_t *expected_version, - struct afs_read *read_req) +static int xdr_decode_AFSFetchStatus(const __be32 **_bp, + struct afs_call *call, + struct afs_status_cb *scb) { const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; + struct afs_file_status *status = &scb->status; bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); u64 data_version, size; u32 type, abort_code; - u8 flags = 0; abort_code = ntohl(xdr->abort_code); @@ -161,44 +100,25 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, case AFS_FTYPE_FILE: case AFS_FTYPE_DIR: case AFS_FTYPE_SYMLINK: - if (type != status->type && - vnode && - !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { - pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n", - vnode->fid.vid, - vnode->fid.vnode, - vnode->fid.unique, - status->type, type); - goto bad; - } status->type = type; break; default: goto bad; } -#define EXTRACT_M(FIELD) \ - do { \ - u32 x = ntohl(xdr->FIELD); \ - if (status->FIELD != x) { \ - flags |= AFS_VNODE_META_CHANGED; \ - status->FIELD = x; \ - } \ - } while (0) - - EXTRACT_M(nlink); - EXTRACT_M(author); - EXTRACT_M(owner); - EXTRACT_M(caller_access); /* call ticket dependent */ - EXTRACT_M(anon_access); - EXTRACT_M(mode); - EXTRACT_M(group); + status->nlink = ntohl(xdr->nlink); + status->author = ntohl(xdr->author); + status->owner = ntohl(xdr->owner); + status->caller_access = ntohl(xdr->caller_access); /* Ticket dependent */ + status->anon_access = ntohl(xdr->anon_access); + status->mode = ntohl(xdr->mode) & S_IALLUGO; + status->group = ntohl(xdr->group); + status->lock_count = ntohl(xdr->lock_count); status->mtime_client.tv_sec = ntohl(xdr->mtime_client); status->mtime_client.tv_nsec = 0; status->mtime_server.tv_sec = ntohl(xdr->mtime_server); status->mtime_server.tv_nsec = 0; - status->lock_count = ntohl(xdr->lock_count); size = (u64)ntohl(xdr->size_lo); size |= (u64)ntohl(xdr->size_hi) << 32; @@ -206,25 +126,9 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, data_version = (u64)ntohl(xdr->data_version_lo); data_version |= (u64)ntohl(xdr->data_version_hi) << 32; - if (data_version != status->data_version) { - status->data_version = data_version; - flags |= AFS_VNODE_DATA_CHANGED; - } - - if (read_req) { - read_req->data_version = data_version; - read_req->file_size = size; - } + status->data_version = data_version; *_bp = (const void *)*_bp + sizeof(*xdr); - - if (vnode) { - if (test_bit(AFS_VNODE_UNSET, &vnode->flags)) - flags |= AFS_VNODE_NOT_YET_SET; - afs_update_inode_from_status(vnode, status, expected_version, - flags); - } - return 0; bad: @@ -232,77 +136,25 @@ bad: return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status); } -/* - * Decode the file status. We need to lock the target vnode if we're going to - * update its status so that stat() sees the attributes update atomically. - */ -static int afs_decode_status(struct afs_call *call, - const __be32 **_bp, - struct afs_file_status *status, - struct afs_vnode *vnode, - const afs_dataversion_t *expected_version, - struct afs_read *read_req) -{ - int ret; - - if (!vnode) - return xdr_decode_AFSFetchStatus(call, _bp, status, vnode, - expected_version, read_req); - - write_seqlock(&vnode->cb_lock); - ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode, - expected_version, read_req); - write_sequnlock(&vnode->cb_lock); - return ret; -} - static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry) { return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry; } -static void xdr_decode_AFSCallBack_raw(struct afs_call *call, - struct afs_callback *cb, - const __be32 **_bp) +static void xdr_decode_AFSCallBack(const __be32 **_bp, + struct afs_call *call, + struct afs_status_cb *scb) { + struct afs_callback *cb = &scb->callback; const __be32 *bp = *_bp; cb->version = ntohl(*bp++); cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++)); cb->type = ntohl(*bp++); + scb->have_cb = true; *_bp = bp; } -/* - * decode an AFSCallBack block - */ -static void xdr_decode_AFSCallBack(struct afs_call *call, - struct afs_vnode *vnode, - const __be32 **_bp) -{ - struct afs_cb_interest *old, *cbi = call->cbi; - struct afs_callback cb; - - xdr_decode_AFSCallBack_raw(call, &cb, _bp); - - write_seqlock(&vnode->cb_lock); - - if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { - vnode->cb_version = cb.version; - vnode->cb_type = cb.type; - vnode->cb_expires_at = cb.expires_at; - old = vnode->cb_interest; - if (old != call->cbi) { - vnode->cb_interest = cbi; - cbi = old; - } - set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); - } - - write_sequnlock(&vnode->cb_lock); - call->cbi = cbi; -} - /* * decode an AFSVolSync block */ @@ -392,7 +244,6 @@ static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, */ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -400,15 +251,12 @@ static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) if (ret < 0) return ret; - _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_AFSCallBack(call, vnode, &bp); + xdr_decode_AFSCallBack(&bp, call, call->out_scb); xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); @@ -428,8 +276,8 @@ static const struct afs_call_type afs_RXFSFetchStatus_vnode = { /* * fetch the status information for a file */ -int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync, - bool new_inode) +int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb, + struct afs_volsync *volsync) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -437,7 +285,7 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_fetch_file_status(fc, volsync, new_inode); + return yfs_fs_fetch_file_status(fc, scb, volsync); _enter(",%x,{%llx:%llu},,", key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); @@ -450,9 +298,8 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy } call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = volsync; - call->expected_version = new_inode ? 1 : vnode->status.data_version; /* marshall the parameters */ bp = call->request; @@ -461,7 +308,6 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy bp[2] = htonl(vnode->fid.vnode); bp[3] = htonl(vnode->fid.unique); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); @@ -475,7 +321,6 @@ int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy */ static int afs_deliver_fs_fetch_data(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; struct afs_read *req = call->read_request; const __be32 *bp; unsigned int size; @@ -538,7 +383,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) if (req->offset == PAGE_SIZE) { req->offset = 0; if (req->page_done) - req->page_done(call, req); + req->page_done(req); req->index++; if (req->remain > 0) goto begin_page; @@ -572,13 +417,15 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) return ret; bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &vnode->status.data_version, req); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_AFSCallBack(call, vnode, &bp); + xdr_decode_AFSCallBack(&bp, call, call->out_scb); xdr_decode_AFSVolSync(&bp, call->out_volsync); + req->data_version = call->out_scb->status.data_version; + req->file_size = call->out_scb->status.size; + call->unmarshall++; case 5: @@ -590,7 +437,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call) zero_user_segment(req->pages[req->index], req->offset, PAGE_SIZE); if (req->page_done) - req->page_done(call, req); + req->page_done(req); req->offset = 0; } @@ -626,7 +473,9 @@ static const struct afs_call_type afs_RXFSFetchData64 = { /* * fetch data from a very large file */ -static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) +static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, + struct afs_status_cb *scb, + struct afs_read *req) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -640,10 +489,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; call->read_request = req; - call->expected_version = vnode->status.data_version; /* marshall the parameters */ bp = call->request; @@ -657,7 +505,6 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) bp[7] = htonl(lower_32_bits(req->len)); refcount_inc(&req->usage); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_set_fc_call(call, fc); @@ -668,7 +515,9 @@ static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) /* * fetch data from a file */ -int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) +int afs_fs_fetch_data(struct afs_fs_cursor *fc, + struct afs_status_cb *scb, + struct afs_read *req) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -676,12 +525,12 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_fetch_data(fc, req); + return yfs_fs_fetch_data(fc, scb, req); if (upper_32_bits(req->pos) || upper_32_bits(req->len) || upper_32_bits(req->pos + req->len)) - return afs_fs_fetch_data64(fc, req); + return afs_fs_fetch_data64(fc, scb, req); _enter(""); @@ -690,10 +539,9 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; call->read_request = req; - call->expected_version = vnode->status.data_version; /* marshall the parameters */ bp = call->request; @@ -705,7 +553,6 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) bp[5] = htonl(lower_32_bits(req->len)); refcount_inc(&req->usage); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_set_fc_call(call, fc); @@ -718,12 +565,9 @@ int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) */ static int afs_deliver_fs_create_vnode(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; - _enter("{%u}", call->unmarshall); - ret = afs_transfer_reply(call); if (ret < 0) return ret; @@ -731,14 +575,13 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; xdr_decode_AFSFid(&bp, call->out_fid); - ret = afs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - xdr_decode_AFSCallBack_raw(call, call->out_cb, &bp); + xdr_decode_AFSCallBack(&bp, call, call->out_scb); xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); @@ -768,10 +611,9 @@ static const struct afs_call_type afs_RXFSMakeDir = { int afs_fs_create(struct afs_fs_cursor *fc, const char *name, umode_t mode, - u64 current_data_version, + struct afs_status_cb *dvnode_scb, struct afs_fid *newfid, - struct afs_file_status *newstatus, - struct afs_callback *newcb) + struct afs_status_cb *new_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -781,11 +623,11 @@ int afs_fs_create(struct afs_fs_cursor *fc, if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){ if (S_ISDIR(mode)) - return yfs_fs_make_dir(fc, name, mode, current_data_version, - newfid, newstatus, newcb); + return yfs_fs_make_dir(fc, name, mode, dvnode_scb, + newfid, new_scb); else - return yfs_fs_create_file(fc, name, mode, current_data_version, - newfid, newstatus, newcb); + return yfs_fs_create_file(fc, name, mode, dvnode_scb, + newfid, new_scb); } _enter(""); @@ -801,11 +643,9 @@ int afs_fs_create(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; + call->out_dir_scb = dvnode_scb; call->out_fid = newfid; - call->out_extra_status = newstatus; - call->out_cb = newcb; - call->expected_version = current_data_version + 1; + call->out_scb = new_scb; /* marshall the parameters */ bp = call->request; @@ -840,20 +680,16 @@ int afs_fs_create(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; - _enter("{%u}", call->unmarshall); - ret = afs_transfer_reply(call); if (ret < 0) return ret; /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -883,7 +719,7 @@ static const struct afs_call_type afs_RXFSRemoveDir = { * remove a file or directory */ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - const char *name, bool isdir, u64 current_data_version) + const char *name, bool isdir, struct afs_status_cb *dvnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -892,7 +728,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_remove(fc, vnode, name, isdir, current_data_version); + return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb); _enter(""); @@ -907,9 +743,7 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; - call->xvnode = vnode; - call->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; /* marshall the parameters */ bp = call->request; @@ -937,7 +771,6 @@ int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int afs_deliver_fs_link(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode, *vnode = call->xvnode; const __be32 *bp; int ret; @@ -949,11 +782,10 @@ static int afs_deliver_fs_link(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -976,7 +808,9 @@ static const struct afs_call_type afs_RXFSLink = { * make a hard link */ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - const char *name, u64 current_data_version) + const char *name, + struct afs_status_cb *dvnode_scb, + struct afs_status_cb *vnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -985,7 +819,7 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_link(fc, vnode, name, current_data_version); + return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb); _enter(""); @@ -998,9 +832,8 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; - call->xvnode = vnode; - call->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; + call->out_scb = vnode_scb; /* marshall the parameters */ bp = call->request; @@ -1031,7 +864,6 @@ int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int afs_deliver_fs_symlink(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -1044,11 +876,10 @@ static int afs_deliver_fs_symlink(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; xdr_decode_AFSFid(&bp, call->out_fid); - ret = afs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -1073,9 +904,9 @@ static const struct afs_call_type afs_RXFSSymlink = { int afs_fs_symlink(struct afs_fs_cursor *fc, const char *name, const char *contents, - u64 current_data_version, + struct afs_status_cb *dvnode_scb, struct afs_fid *newfid, - struct afs_file_status *newstatus) + struct afs_status_cb *new_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -1084,8 +915,8 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_symlink(fc, name, contents, current_data_version, - newfid, newstatus); + return yfs_fs_symlink(fc, name, contents, dvnode_scb, + newfid, new_scb); _enter(""); @@ -1103,10 +934,9 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; + call->out_dir_scb = dvnode_scb; call->out_fid = newfid; - call->out_extra_status = newstatus; - call->expected_version = current_data_version + 1; + call->out_scb = new_scb; /* marshall the parameters */ bp = call->request; @@ -1147,25 +977,20 @@ int afs_fs_symlink(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_rename(struct afs_call *call) { - struct afs_vnode *orig_dvnode = call->dvnode, *new_dvnode = call->xvnode; const __be32 *bp; int ret; - _enter("{%u}", call->unmarshall); - ret = afs_transfer_reply(call); if (ret < 0) return ret; /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - if (new_dvnode != orig_dvnode) { - ret = afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode, - &call->expected_version_2, NULL); + if (call->out_dir_scb != call->out_scb) { + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; } @@ -1186,14 +1011,14 @@ static const struct afs_call_type afs_RXFSRename = { }; /* - * create a symbolic link + * Rename/move a file or directory. */ int afs_fs_rename(struct afs_fs_cursor *fc, const char *orig_name, struct afs_vnode *new_dvnode, const char *new_name, - u64 current_orig_data_version, - u64 current_new_data_version) + struct afs_status_cb *orig_dvnode_scb, + struct afs_status_cb *new_dvnode_scb) { struct afs_vnode *orig_dvnode = fc->vnode; struct afs_call *call; @@ -1204,8 +1029,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc, if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) return yfs_fs_rename(fc, orig_name, new_dvnode, new_name, - current_orig_data_version, - current_new_data_version); + orig_dvnode_scb, + new_dvnode_scb); _enter(""); @@ -1225,10 +1050,8 @@ int afs_fs_rename(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = orig_dvnode; - call->xvnode = new_dvnode; - call->expected_version = current_orig_data_version + 1; - call->expected_version_2 = current_new_data_version + 1; + call->out_dir_scb = orig_dvnode_scb; + call->out_scb = new_dvnode_scb; /* marshall the parameters */ bp = call->request; @@ -1267,7 +1090,6 @@ int afs_fs_rename(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_store_data(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1279,14 +1101,11 @@ static int afs_deliver_fs_store_data(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); - afs_pages_written_back(vnode, call); - _leave(" = 0 [done]"); return 0; } @@ -1315,7 +1134,8 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, struct address_space *mapping, pgoff_t first, pgoff_t last, unsigned offset, unsigned to, - loff_t size, loff_t pos, loff_t i_size) + loff_t size, loff_t pos, loff_t i_size, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1333,13 +1153,12 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, call->key = fc->key; call->mapping = mapping; - call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; call->last_to = to; call->send_pages = true; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1373,7 +1192,8 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, */ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, pgoff_t first, pgoff_t last, - unsigned offset, unsigned to) + unsigned offset, unsigned to, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1382,7 +1202,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_store_data(fc, mapping, first, last, offset, to); + return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb); _enter(",%x,{%llx:%llu},,", key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); @@ -1403,7 +1223,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) return afs_fs_store_data64(fc, mapping, first, last, offset, to, - size, pos, i_size); + size, pos, i_size, scb); call = afs_alloc_flat_call(net, &afs_RXFSStoreData, (4 + 6 + 3) * 4, @@ -1413,13 +1233,12 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, call->key = fc->key; call->mapping = mapping; - call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; call->last_to = to; call->send_pages = true; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1451,7 +1270,6 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, */ static int afs_deliver_fs_store_status(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1463,8 +1281,7 @@ static int afs_deliver_fs_store_status(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -1501,7 +1318,8 @@ static const struct afs_call_type afs_RXFSStoreData64_as_Status = { * set the attributes on a very large file, using FS.StoreData rather than * FS.StoreStatus so as to alter the file size also */ -static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) +static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1520,8 +1338,7 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1550,7 +1367,8 @@ static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus * so as to alter the file size also */ -static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) +static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1562,7 +1380,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) ASSERT(attr->ia_valid & ATTR_SIZE); if (attr->ia_size >> 32) - return afs_fs_setattr_size64(fc, attr); + return afs_fs_setattr_size64(fc, attr, scb); call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status, (4 + 6 + 3) * 4, @@ -1571,8 +1389,7 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1598,7 +1415,8 @@ static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) * set the attributes on a file, using FS.StoreData if there's a change in file * size, and FS.StoreStatus otherwise */ -int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) +int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1606,10 +1424,10 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_setattr(fc, attr); + return yfs_fs_setattr(fc, attr, scb); if (attr->ia_valid & ATTR_SIZE) - return afs_fs_setattr_size(fc, attr); + return afs_fs_setattr_size(fc, attr, scb); _enter(",%x,{%llx:%llu},,", key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); @@ -1621,8 +1439,7 @@ int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; - call->expected_version = vnode->status.data_version; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1865,7 +1682,8 @@ static const struct afs_call_type afs_RXFSReleaseLock = { /* * Set a lock on a file */ -int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) +int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1873,7 +1691,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_set_lock(fc, type); + return yfs_fs_set_lock(fc, type, scb); _enter(""); @@ -1882,7 +1700,8 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1902,7 +1721,7 @@ int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) /* * extend a lock on a file */ -int afs_fs_extend_lock(struct afs_fs_cursor *fc) +int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1910,7 +1729,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_extend_lock(fc); + return yfs_fs_extend_lock(fc, scb); _enter(""); @@ -1919,7 +1738,8 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1938,7 +1758,7 @@ int afs_fs_extend_lock(struct afs_fs_cursor *fc) /* * release a lock on a file */ -int afs_fs_release_lock(struct afs_fs_cursor *fc) +int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1946,7 +1766,7 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc) __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_release_lock(fc); + return yfs_fs_release_lock(fc, scb); _enter(""); @@ -1955,7 +1775,8 @@ int afs_fs_release_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -2113,10 +1934,6 @@ struct afs_call *afs_fs_get_capabilities(struct afs_net *net, */ static int afs_deliver_fs_fetch_status(struct afs_call *call) { - struct afs_file_status *status = call->out_vnode_status; - struct afs_callback *callback = call->out_cb; - struct afs_volsync *volsync = call->out_volsync; - struct afs_fid *fid = call->out_fid; const __be32 *bp; int ret; @@ -2124,16 +1941,13 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call) if (ret < 0) return ret; - _enter("{%llx:%llu}", fid->vid, fid->vnode); - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, status, NULL, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_AFSCallBack_raw(call, callback, &bp); - xdr_decode_AFSVolSync(&bp, volsync); + xdr_decode_AFSCallBack(&bp, call, call->out_scb); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -2155,15 +1969,14 @@ static const struct afs_call_type afs_RXFSFetchStatus = { int afs_fs_fetch_status(struct afs_fs_cursor *fc, struct afs_net *net, struct afs_fid *fid, - struct afs_file_status *status, - struct afs_callback *callback, + struct afs_status_cb *scb, struct afs_volsync *volsync) { struct afs_call *call; __be32 *bp; if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)) - return yfs_fs_fetch_status(fc, net, fid, status, callback, volsync); + return yfs_fs_fetch_status(fc, net, fid, scb, volsync); _enter(",%x,{%llx:%llu},,", key_serial(fc->key), fid->vid, fid->vnode); @@ -2176,10 +1989,8 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, call->key = fc->key; call->out_fid = fid; - call->out_vnode_status = status; - call->out_cb = callback; + call->out_scb = scb; call->out_volsync = volsync; - call->expected_version = 1; /* vnode->status.data_version */ /* marshall the parameters */ bp = call->request; @@ -2188,7 +1999,6 @@ int afs_fs_fetch_status(struct afs_fs_cursor *fc, bp[2] = htonl(fid->vnode); bp[3] = htonl(fid->unique); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, fid); afs_set_fc_call(call, fc); @@ -2241,8 +2051,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) bp = call->buffer; scb = &call->out_scb[call->count]; - ret = afs_decode_status(call, &bp, &scb->status, - NULL, NULL, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, scb); if (ret < 0) return ret; @@ -2282,8 +2091,7 @@ static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; scb = &call->out_scb[call->count]; - xdr_decode_AFSCallBack_raw(call, &scb->callback, &bp); - scb->have_cb = true; + xdr_decode_AFSCallBack(&bp, call, scb); call->count++; if (call->count < call->count2) goto more_cbs; @@ -2364,7 +2172,6 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, *bp++ = htonl(fids[i].unique); } - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &fids[0]); afs_set_fc_call(call, fc); @@ -2377,7 +2184,6 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, */ static int afs_deliver_fs_fetch_acl(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; struct afs_acl *acl; const __be32 *bp; unsigned int size; @@ -2423,8 +2229,7 @@ static int afs_deliver_fs_fetch_acl(struct afs_call *call) return ret; bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &vnode->status.data_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -2458,7 +2263,8 @@ static const struct afs_call_type afs_RXFSFetchACL = { /* * Fetch the ACL for a file. */ -struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) +struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -2476,7 +2282,7 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) call->key = fc->key; call->ret_acl = NULL; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; /* marshall the parameters */ @@ -2486,7 +2292,6 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) bp[2] = htonl(vnode->fid.vnode); bp[3] = htonl(vnode->fid.unique); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_make_call(&fc->ac, call, GFP_KERNEL); @@ -2499,20 +2304,15 @@ struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) */ static int afs_deliver_fs_file_status_and_vol(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; - _enter("{%u}", call->unmarshall); - ret = afs_transfer_reply(call); if (ret < 0) return ret; - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; xdr_decode_AFSVolSync(&bp, call->out_volsync); @@ -2534,7 +2334,8 @@ static const struct afs_call_type afs_RXFSStoreACL = { /* * Fetch the ACL for a file. */ -int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl) +int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -2554,7 +2355,7 @@ int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl) } call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; /* marshall the parameters */ diff --git a/fs/afs/inode.c b/fs/afs/inode.c index bf8f56e851df..4a9004b9ac5f 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -58,38 +58,50 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren * Initialise an inode from the vnode status. */ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, - struct afs_vnode *parent_vnode) + struct afs_cb_interest *cbi, + struct afs_vnode *parent_vnode, + struct afs_status_cb *scb) { + struct afs_cb_interest *old_cbi = NULL; + struct afs_file_status *status = &scb->status; struct inode *inode = AFS_VNODE_TO_I(vnode); + struct timespec64 t; _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu", - vnode->status.type, - vnode->status.nlink, - (unsigned long long) vnode->status.size, - vnode->status.data_version, - vnode->status.mode); + status->type, + status->nlink, + (unsigned long long) status->size, + status->data_version, + status->mode); - read_seqlock_excl(&vnode->cb_lock); + write_seqlock(&vnode->cb_lock); + + vnode->status = *status; - afs_update_inode_from_status(vnode, &vnode->status, NULL, - AFS_VNODE_NOT_YET_SET); + t = status->mtime_client; + inode->i_ctime = t; + inode->i_mtime = t; + inode->i_atime = t; + inode->i_uid = make_kuid(&init_user_ns, status->owner); + inode->i_gid = make_kgid(&init_user_ns, status->group); + set_nlink(&vnode->vfs_inode, status->nlink); - switch (vnode->status.type) { + switch (status->type) { case AFS_FTYPE_FILE: - inode->i_mode = S_IFREG | vnode->status.mode; + inode->i_mode = S_IFREG | status->mode; inode->i_op = &afs_file_inode_operations; inode->i_fop = &afs_file_operations; inode->i_mapping->a_ops = &afs_fs_aops; break; case AFS_FTYPE_DIR: - inode->i_mode = S_IFDIR | vnode->status.mode; + inode->i_mode = S_IFDIR | status->mode; inode->i_op = &afs_dir_inode_operations; inode->i_fop = &afs_dir_file_operations; inode->i_mapping->a_ops = &afs_dir_aops; break; case AFS_FTYPE_SYMLINK: /* Symlinks with a mode of 0644 are actually mountpoints. */ - if ((vnode->status.mode & 0777) == 0644) { + if ((status->mode & 0777) == 0644) { inode->i_flags |= S_AUTOMOUNT; set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); @@ -99,7 +111,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, inode->i_fop = &afs_mntpt_file_operations; inode->i_mapping->a_ops = &afs_fs_aops; } else { - inode->i_mode = S_IFLNK | vnode->status.mode; + inode->i_mode = S_IFLNK | status->mode; inode->i_op = &afs_symlink_inode_operations; inode->i_mapping->a_ops = &afs_fs_aops; } @@ -107,7 +119,7 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, break; default: dump_vnode(vnode, parent_vnode); - read_sequnlock_excl(&vnode->cb_lock); + write_sequnlock(&vnode->cb_lock); return afs_protocol_error(NULL, -EBADMSG, afs_eproto_file_type); } @@ -116,17 +128,170 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, * for consistency with other AFS clients. */ inode->i_blocks = ((i_size_read(inode) + 1023) >> 10) << 1; - vnode->invalid_before = vnode->status.data_version; + i_size_write(&vnode->vfs_inode, status->size); - read_sequnlock_excl(&vnode->cb_lock); + vnode->invalid_before = status->data_version; + inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); + + if (!scb->have_cb) { + /* it's a symlink we just created (the fileserver + * didn't give us a callback) */ + vnode->cb_version = 0; + vnode->cb_type = 0; + vnode->cb_expires_at = ktime_get_real_seconds(); + } else { + vnode->cb_version = scb->callback.version; + vnode->cb_type = scb->callback.type; + vnode->cb_expires_at = scb->callback.expires_at; + old_cbi = vnode->cb_interest; + if (cbi != old_cbi) + vnode->cb_interest = afs_get_cb_interest(cbi); + else + old_cbi = NULL; + set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); + } + + write_sequnlock(&vnode->cb_lock); + afs_put_cb_interest(afs_v2net(vnode), old_cbi); return 0; } +/* + * Update the core inode struct from a returned status record. + */ +static void afs_apply_status(struct afs_fs_cursor *fc, + struct afs_vnode *vnode, + struct afs_status_cb *scb, + const afs_dataversion_t *expected_version) +{ + struct afs_file_status *status = &scb->status; + struct timespec64 t; + umode_t mode; + bool data_changed = false; + + BUG_ON(test_bit(AFS_VNODE_UNSET, &vnode->flags)); + + if (status->type != vnode->status.type) { + pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n", + vnode->fid.vid, + vnode->fid.vnode, + vnode->fid.unique, + status->type, vnode->status.type); + afs_protocol_error(NULL, -EBADMSG, afs_eproto_bad_status); + return; + } + + if (status->nlink != vnode->status.nlink) + set_nlink(&vnode->vfs_inode, status->nlink); + + if (status->owner != vnode->status.owner) + vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); + + if (status->group != vnode->status.group) + vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); + + if (status->mode != vnode->status.mode) { + mode = vnode->vfs_inode.i_mode; + mode &= ~S_IALLUGO; + mode |= status->mode; + WRITE_ONCE(vnode->vfs_inode.i_mode, mode); + } + + t = status->mtime_client; + vnode->vfs_inode.i_ctime = t; + vnode->vfs_inode.i_mtime = t; + vnode->vfs_inode.i_atime = t; + + if (vnode->status.data_version != status->data_version) + data_changed = true; + + vnode->status = *status; + + if (expected_version && + *expected_version != status->data_version) { + kdebug("vnode modified %llx on {%llx:%llu} [exp %llx] %s", + (unsigned long long) status->data_version, + vnode->fid.vid, vnode->fid.vnode, + (unsigned long long) *expected_version, + fc->type ? fc->type->name : "???"); + vnode->invalid_before = status->data_version; + if (vnode->status.type == AFS_FTYPE_DIR) { + if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) + afs_stat_v(vnode, n_inval); + } else { + set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); + } + } else if (vnode->status.type == AFS_FTYPE_DIR) { + /* Expected directory change is handled elsewhere so + * that we can locally edit the directory and save on a + * download. + */ + if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) + data_changed = false; + } + + if (data_changed) { + inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); + i_size_write(&vnode->vfs_inode, status->size); + } +} + +/* + * Apply a callback to a vnode. + */ +static void afs_apply_callback(struct afs_fs_cursor *fc, + struct afs_vnode *vnode, + struct afs_status_cb *scb, + unsigned int cb_break) +{ + struct afs_cb_interest *old; + struct afs_callback *cb = &scb->callback; + + if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { + vnode->cb_version = cb->version; + vnode->cb_type = cb->type; + vnode->cb_expires_at = cb->expires_at; + old = vnode->cb_interest; + if (old != fc->cbi) { + vnode->cb_interest = afs_get_cb_interest(fc->cbi); + afs_put_cb_interest(afs_v2net(vnode), old); + } + set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); + } +} + +/* + * Apply the received status and callback to an inode all in the same critical + * section to avoid races with afs_validate(). + */ +void afs_vnode_commit_status(struct afs_fs_cursor *fc, + struct afs_vnode *vnode, + unsigned int cb_break, + const afs_dataversion_t *expected_version, + struct afs_status_cb *scb) +{ + if (fc->ac.error != 0) + return; + + write_seqlock(&vnode->cb_lock); + + afs_apply_status(fc, vnode, scb, expected_version); + if (scb->have_cb) + afs_apply_callback(fc, vnode, scb, cb_break); + + write_sequnlock(&vnode->cb_lock); + + if (fc->ac.error == 0) + afs_cache_permit(vnode, fc->key, cb_break, scb); +} + /* * Fetch file status from the volume. */ -int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) +int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new, + afs_access_t *_caller_access) { + struct afs_status_cb *scb; struct afs_fs_cursor fc; int ret; @@ -135,18 +300,38 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool new_inode) vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique, vnode->flags); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + return -ENOMEM; + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_fetch_file_status(&fc, NULL, new_inode); + afs_fs_fetch_file_status(&fc, scb, NULL); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + if (fc.error) { + /* Do nothing. */ + } else if (is_new) { + ret = afs_inode_init_from_status(vnode, key, fc.cbi, + NULL, scb); + fc.error = ret; + if (ret == 0) + afs_cache_permit(vnode, key, fc.cb_break, scb); + } else { + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); + } + afs_check_for_remote_deletion(&fc, vnode); ret = afs_end_vnode_operation(&fc); } + if (ret == 0 && _caller_access) + *_caller_access = scb->status.caller_access; + kfree(scb); _leave(" = %d", ret); return ret; } @@ -299,8 +484,8 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) * inode retrieval */ struct inode *afs_iget(struct super_block *sb, struct key *key, - struct afs_fid *fid, struct afs_file_status *status, - struct afs_callback *cb, struct afs_cb_interest *cbi, + struct afs_fid *fid, struct afs_status_cb *scb, + struct afs_cb_interest *cbi, struct afs_vnode *parent_vnode) { struct afs_iget_data data = { .fid = *fid }; @@ -332,36 +517,18 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, return inode; } - if (!status) { + if (!scb) { /* it's a remotely extant inode */ - ret = afs_fetch_status(vnode, key, true); + ret = afs_fetch_status(vnode, key, true, NULL); if (ret < 0) goto bad_inode; } else { - /* it's an inode we just created */ - memcpy(&vnode->status, status, sizeof(vnode->status)); - - if (!cb) { - /* it's a symlink we just created (the fileserver - * didn't give us a callback) */ - vnode->cb_version = 0; - vnode->cb_type = 0; - vnode->cb_expires_at = ktime_get(); - } else { - vnode->cb_version = cb->version; - vnode->cb_type = cb->type; - vnode->cb_expires_at = cb->expires_at; - vnode->cb_interest = afs_get_cb_interest(cbi); - set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); - } - - vnode->cb_expires_at += ktime_get_real_seconds(); + ret = afs_inode_init_from_status(vnode, key, cbi, parent_vnode, + scb); + if (ret < 0) + goto bad_inode; } - ret = afs_inode_init_from_status(vnode, key, parent_vnode); - if (ret < 0) - goto bad_inode; - afs_get_inode_cache(vnode); /* success */ @@ -460,7 +627,7 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) * access */ if (!test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { _debug("not promised"); - ret = afs_fetch_status(vnode, key, false); + ret = afs_fetch_status(vnode, key, false, NULL); if (ret < 0) { if (ret == -ENOENT) { set_bit(AFS_VNODE_DELETED, &vnode->flags); @@ -585,9 +752,10 @@ void afs_evict_inode(struct inode *inode) int afs_setattr(struct dentry *dentry, struct iattr *attr) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); struct key *key; - int ret; + int ret = -ENOMEM; _enter("{%llx:%llu},{n=%pd},%x", vnode->fid.vid, vnode->fid.vnode, dentry, @@ -599,6 +767,10 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) return 0; } + scb = kzalloc(sizeof(struct afs_status_cb), GFP_KERNEL); + if (!scb) + goto error; + /* flush any dirty data outstanding on a regular file */ if (S_ISREG(vnode->vfs_inode.i_mode)) filemap_write_and_wait(vnode->vfs_inode.i_mapping); @@ -609,25 +781,33 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr) key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error; + goto error_scb; } } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, false)) { + afs_dataversion_t data_version = vnode->status.data_version; + + if (attr->ia_valid & ATTR_SIZE) + data_version++; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_setattr(&fc, attr); + afs_fs_setattr(&fc, attr, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } if (!(attr->ia_valid & ATTR_FILE)) key_put(key); +error_scb: + kfree(scb); error: _leave(" = %d", ret); return ret; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 9b44307bd934..6ed7d4df4ec6 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -116,8 +116,7 @@ struct afs_call { struct afs_vlserver *vlserver; }; struct afs_cb_interest *cbi; /* Callback interest for server used */ - struct afs_vnode *dvnode; /* Directory vnode of call */ - struct afs_vnode *xvnode; /* Other vnode of call */ + struct afs_vnode *lvnode; /* vnode being locked */ void *request; /* request data (first part) */ struct address_space *mapping; /* Pages being written from */ struct iov_iter iter; /* Buffer iterator */ @@ -134,9 +133,7 @@ struct afs_call { struct afs_acl *ret_acl; }; struct afs_fid *out_fid; - struct afs_file_status *out_vnode_status; - struct afs_file_status *out_extra_status; - struct afs_callback *out_cb; + struct afs_status_cb *out_dir_scb; struct afs_status_cb *out_scb; struct yfs_acl *out_yacl; struct afs_volsync *out_volsync; @@ -155,7 +152,6 @@ struct afs_call { unsigned request_size; /* size of request data */ unsigned reply_max; /* maximum size of reply */ unsigned first_offset; /* offset into mapping[first] */ - unsigned int cb_break; /* cb_break + cb_s_break before the call */ union { unsigned last_to; /* amount of mapping[last] */ unsigned count2; /* count used in unmarshalling */ @@ -180,8 +176,6 @@ struct afs_call { } __attribute__((packed)); __be64 tmp64; }; - afs_dataversion_t expected_version; /* Updated version expected from store */ - afs_dataversion_t expected_version_2; /* 2nd updated version expected from store */ ktime_t reply_time; /* Time of first reply packet */ }; @@ -242,7 +236,8 @@ struct afs_read { unsigned int index; /* Which page we're reading into */ unsigned int nr_pages; unsigned int offset; /* offset into current page */ - void (*page_done)(struct afs_call *, struct afs_read *); + struct afs_vnode *vnode; + void (*page_done)(struct afs_read *); struct page **pages; struct page *array[]; }; @@ -776,6 +771,7 @@ struct afs_vl_cursor { * Cursor for iterating over a set of fileservers. */ struct afs_fs_cursor { + const struct afs_call_type *type; /* Type of call done */ struct afs_addr_cursor ac; struct afs_vnode *vnode; struct afs_server_list *server_list; /* Current server list (pins ref) */ @@ -962,30 +958,28 @@ extern int afs_flock(struct file *, int, struct file_lock *); /* * fsclient.c */ -#define AFS_VNODE_NOT_YET_SET 0x01 -#define AFS_VNODE_META_CHANGED 0x02 -#define AFS_VNODE_DATA_CHANGED 0x04 -extern void afs_update_inode_from_status(struct afs_vnode *, struct afs_file_status *, - const afs_dataversion_t *, u8); - -extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool); +extern int afs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_status_cb *, + struct afs_volsync *); extern int afs_fs_give_up_callbacks(struct afs_net *, struct afs_server *); -extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); -extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, u64, - struct afs_fid *, struct afs_file_status *, struct afs_callback *); -extern int afs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64); -extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64); -extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64, - struct afs_fid *, struct afs_file_status *); +extern int afs_fs_fetch_data(struct afs_fs_cursor *, struct afs_status_cb *, struct afs_read *); +extern int afs_fs_create(struct afs_fs_cursor *, const char *, umode_t, + struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *); +extern int afs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, + struct afs_status_cb *); +extern int afs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, + struct afs_status_cb *, struct afs_status_cb *); +extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, + struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *); extern int afs_fs_rename(struct afs_fs_cursor *, const char *, - struct afs_vnode *, const char *, u64, u64); + struct afs_vnode *, const char *, + struct afs_status_cb *, struct afs_status_cb *); extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *, - pgoff_t, pgoff_t, unsigned, unsigned); -extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *); + pgoff_t, pgoff_t, unsigned, unsigned, struct afs_status_cb *); +extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *, struct afs_status_cb *); extern int afs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *); -extern int afs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t); -extern int afs_fs_extend_lock(struct afs_fs_cursor *); -extern int afs_fs_release_lock(struct afs_fs_cursor *); +extern int afs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t, struct afs_status_cb *); +extern int afs_fs_extend_lock(struct afs_fs_cursor *, struct afs_status_cb *); +extern int afs_fs_release_lock(struct afs_fs_cursor *, struct afs_status_cb *); extern int afs_fs_give_up_all_callbacks(struct afs_net *, struct afs_server *, struct afs_addr_cursor *, struct key *); extern struct afs_call *afs_fs_get_capabilities(struct afs_net *, struct afs_server *, @@ -995,16 +989,17 @@ extern int afs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, struct afs_fid *, struct afs_status_cb *, unsigned int, struct afs_volsync *); extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, - struct afs_fid *, struct afs_file_status *, - struct afs_callback *, struct afs_volsync *); + struct afs_fid *, struct afs_status_cb *, + struct afs_volsync *); struct afs_acl { u32 size; u8 data[]; }; -extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *); -extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *); +extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *, struct afs_status_cb *); +extern int afs_fs_store_acl(struct afs_fs_cursor *, const struct afs_acl *, + struct afs_status_cb *); /* * fs_probe.c @@ -1016,12 +1011,16 @@ extern int afs_wait_for_fs_probes(struct afs_server_list *, unsigned long); /* * inode.c */ -extern int afs_fetch_status(struct afs_vnode *, struct key *, bool); +extern void afs_vnode_commit_status(struct afs_fs_cursor *, + struct afs_vnode *, + unsigned int, + const afs_dataversion_t *, + struct afs_status_cb *); +extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t *); extern int afs_iget5_test(struct inode *, void *); extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); extern struct inode *afs_iget(struct super_block *, struct key *, - struct afs_fid *, struct afs_file_status *, - struct afs_callback *, + struct afs_fid *, struct afs_status_cb *, struct afs_cb_interest *, struct afs_vnode *); extern void afs_zap_data(struct afs_vnode *); @@ -1145,6 +1144,7 @@ extern int afs_protocol_error(struct afs_call *, int, enum afs_eproto_cause); static inline void afs_set_fc_call(struct afs_call *call, struct afs_fs_cursor *fc) { call->intr = fc->flags & AFS_FS_CURSOR_INTR; + fc->type = call->type; } static inline void afs_extract_begin(struct afs_call *call, void *buf, size_t size) @@ -1227,7 +1227,8 @@ static inline void afs_set_call_complete(struct afs_call *call, */ extern void afs_put_permits(struct afs_permits *); extern void afs_clear_permits(struct afs_vnode *); -extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int); +extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int, + struct afs_status_cb *); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); @@ -1353,7 +1354,6 @@ extern int afs_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata); extern int afs_writepage(struct page *, struct writeback_control *); extern int afs_writepages(struct address_space *, struct writeback_control *); -extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *); extern int afs_fsync(struct file *, loff_t, loff_t, int); extern vm_fault_t afs_page_mkwrite(struct vm_fault *vmf); @@ -1369,29 +1369,33 @@ extern ssize_t afs_listxattr(struct dentry *, char *, size_t); /* * yfsclient.c */ -extern int yfs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_volsync *, bool); -extern int yfs_fs_fetch_data(struct afs_fs_cursor *, struct afs_read *); -extern int yfs_fs_create_file(struct afs_fs_cursor *, const char *, umode_t, u64, - struct afs_fid *, struct afs_file_status *, struct afs_callback *); -extern int yfs_fs_make_dir(struct afs_fs_cursor *, const char *, umode_t, u64, - struct afs_fid *, struct afs_file_status *, struct afs_callback *); -extern int yfs_fs_remove_file2(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64); -extern int yfs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, u64); -extern int yfs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, u64); -extern int yfs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, u64, - struct afs_fid *, struct afs_file_status *); -extern int yfs_fs_rename(struct afs_fs_cursor *, const char *, - struct afs_vnode *, const char *, u64, u64); +extern int yfs_fs_fetch_file_status(struct afs_fs_cursor *, struct afs_status_cb *, + struct afs_volsync *); +extern int yfs_fs_fetch_data(struct afs_fs_cursor *, struct afs_status_cb *, struct afs_read *); +extern int yfs_fs_create_file(struct afs_fs_cursor *, const char *, umode_t, struct afs_status_cb *, + struct afs_fid *, struct afs_status_cb *); +extern int yfs_fs_make_dir(struct afs_fs_cursor *, const char *, umode_t, struct afs_status_cb *, + struct afs_fid *, struct afs_status_cb *); +extern int yfs_fs_remove_file2(struct afs_fs_cursor *, struct afs_vnode *, const char *, + struct afs_status_cb *, struct afs_status_cb *); +extern int yfs_fs_remove(struct afs_fs_cursor *, struct afs_vnode *, const char *, bool, + struct afs_status_cb *); +extern int yfs_fs_link(struct afs_fs_cursor *, struct afs_vnode *, const char *, + struct afs_status_cb *, struct afs_status_cb *); +extern int yfs_fs_symlink(struct afs_fs_cursor *, const char *, const char *, + struct afs_status_cb *, struct afs_fid *, struct afs_status_cb *); +extern int yfs_fs_rename(struct afs_fs_cursor *, const char *, struct afs_vnode *, const char *, + struct afs_status_cb *, struct afs_status_cb *); extern int yfs_fs_store_data(struct afs_fs_cursor *, struct address_space *, - pgoff_t, pgoff_t, unsigned, unsigned); -extern int yfs_fs_setattr(struct afs_fs_cursor *, struct iattr *); + pgoff_t, pgoff_t, unsigned, unsigned, struct afs_status_cb *); +extern int yfs_fs_setattr(struct afs_fs_cursor *, struct iattr *, struct afs_status_cb *); extern int yfs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *); -extern int yfs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t); -extern int yfs_fs_extend_lock(struct afs_fs_cursor *); -extern int yfs_fs_release_lock(struct afs_fs_cursor *); +extern int yfs_fs_set_lock(struct afs_fs_cursor *, afs_lock_type_t, struct afs_status_cb *); +extern int yfs_fs_extend_lock(struct afs_fs_cursor *, struct afs_status_cb *); +extern int yfs_fs_release_lock(struct afs_fs_cursor *, struct afs_status_cb *); extern int yfs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, - struct afs_fid *, struct afs_file_status *, - struct afs_callback *, struct afs_volsync *); + struct afs_fid *, struct afs_status_cb *, + struct afs_volsync *); extern int yfs_fs_inline_bulk_status(struct afs_fs_cursor *, struct afs_net *, struct afs_fid *, struct afs_status_cb *, unsigned int, struct afs_volsync *); @@ -1407,8 +1411,10 @@ struct yfs_acl { }; extern void yfs_free_opaque_acl(struct yfs_acl *); -extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, struct yfs_acl *); -extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *); +extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, struct yfs_acl *, + struct afs_status_cb *); +extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *, + struct afs_status_cb *); /* * Miscellaneous inline functions. @@ -1423,14 +1429,6 @@ static inline struct inode *AFS_VNODE_TO_I(struct afs_vnode *vnode) return &vnode->vfs_inode; } -static inline void afs_vnode_commit_status(struct afs_fs_cursor *fc, - struct afs_vnode *vnode, - unsigned int cb_break) -{ - if (fc->ac.error == 0) - afs_cache_permit(vnode, fc->key, cb_break); -} - static inline void afs_check_for_remote_deletion(struct afs_fs_cursor *fc, struct afs_vnode *vnode) { diff --git a/fs/afs/security.c b/fs/afs/security.c index db5529e47eb8..857f09d09ee9 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -116,10 +116,10 @@ static void afs_hash_permits(struct afs_permits *permits) * as the ACL *may* have changed. */ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, - unsigned int cb_break) + unsigned int cb_break, struct afs_status_cb *scb) { struct afs_permits *permits, *xpermits, *replacement, *zap, *new = NULL; - afs_access_t caller_access = READ_ONCE(vnode->status.caller_access); + afs_access_t caller_access = scb->status.caller_access; size_t size = 0; bool changed = false; int i, j; @@ -320,13 +320,12 @@ int afs_check_permit(struct afs_vnode *vnode, struct key *key, */ _debug("no valid permit"); - ret = afs_fetch_status(vnode, key, false); + ret = afs_fetch_status(vnode, key, false, _access); if (ret < 0) { *_access = 0; _leave(" = %d", ret); return ret; } - *_access = vnode->status.caller_access; } _leave(" = 0 [access %x]", *_access); diff --git a/fs/afs/super.c b/fs/afs/super.c index 3df11eede7f4..f45a95eea237 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -455,7 +455,7 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) fid.vnode = 1; fid.vnode_hi = 0; fid.unique = 1; - inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL, NULL); + inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); } if (IS_ERR(inode)) @@ -749,7 +749,6 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) } afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); ret = afs_end_vnode_operation(&fc); } diff --git a/fs/afs/write.c b/fs/afs/write.c index e669f2fae873..8bcab95f1127 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -313,6 +313,46 @@ static void afs_redirty_pages(struct writeback_control *wbc, _leave(""); } +/* + * completion of write to server + */ +static void afs_pages_written_back(struct afs_vnode *vnode, + pgoff_t first, pgoff_t last) +{ + struct pagevec pv; + unsigned long priv; + unsigned count, loop; + + _enter("{%llx:%llu},{%lx-%lx}", + vnode->fid.vid, vnode->fid.vnode, first, last); + + pagevec_init(&pv); + + do { + _debug("done %lx-%lx", first, last); + + count = last - first + 1; + if (count > PAGEVEC_SIZE) + count = PAGEVEC_SIZE; + pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, + first, count, pv.pages); + ASSERTCMP(pv.nr, ==, count); + + for (loop = 0; loop < count; loop++) { + priv = page_private(pv.pages[loop]); + trace_afs_page_dirty(vnode, tracepoint_string("clear"), + pv.pages[loop]->index, priv); + set_page_private(pv.pages[loop], 0); + end_page_writeback(pv.pages[loop]); + } + first += count; + __pagevec_release(&pv); + } while (first <= last); + + afs_prune_wb_keys(vnode); + _leave(""); +} + /* * write to a file */ @@ -322,6 +362,7 @@ static int afs_store_data(struct address_space *mapping, { struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_wb_key *wbk = NULL; struct list_head *p; int ret = -ENOKEY, ret2; @@ -333,6 +374,10 @@ static int afs_store_data(struct address_space *mapping, vnode->fid.unique, first, last, offset, to); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + return -ENOMEM; + spin_lock(&vnode->wb_lock); p = vnode->wb_keys.next; @@ -351,6 +396,7 @@ try_next_key: spin_unlock(&vnode->wb_lock); afs_put_wb_key(wbk); + kfree(scb); _leave(" = %d [no keys]", ret); return ret; @@ -362,13 +408,18 @@ found_key: ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, wbk->key, false)) { + afs_dataversion_t data_version = vnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_store_data(&fc, mapping, first, last, offset, to); + afs_fs_store_data(&fc, mapping, first, last, offset, to, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); + if (fc.ac.error == 0) + afs_pages_written_back(vnode, first, last); ret = afs_end_vnode_operation(&fc); } @@ -393,6 +444,7 @@ found_key: } afs_put_wb_key(wbk); + kfree(scb); _leave(" = %d", ret); return ret; } @@ -678,46 +730,6 @@ int afs_writepages(struct address_space *mapping, return ret; } -/* - * completion of write to server - */ -void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) -{ - struct pagevec pv; - unsigned long priv; - unsigned count, loop; - pgoff_t first = call->first, last = call->last; - - _enter("{%llx:%llu},{%lx-%lx}", - vnode->fid.vid, vnode->fid.vnode, first, last); - - pagevec_init(&pv); - - do { - _debug("done %lx-%lx", first, last); - - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, - first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); - - for (loop = 0; loop < count; loop++) { - priv = page_private(pv.pages[loop]); - trace_afs_page_dirty(vnode, tracepoint_string("clear"), - pv.pages[loop]->index, priv); - set_page_private(pv.pages[loop], 0); - end_page_writeback(pv.pages[loop]); - } - first += count; - __pagevec_release(&pv); - } while (first <= last); - - afs_prune_wb_keys(vnode); - _leave(""); -} - /* * write to an AFS file */ diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index e13b005fac42..17f58fea7ec1 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -47,24 +47,34 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler, void *buffer, size_t size) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_acl *acl = NULL; struct key *key; - int ret; + int ret = -ENOMEM; + + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + goto error; key = afs_request_key(vnode->volume->cell); - if (IS_ERR(key)) - return PTR_ERR(key); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto error_scb; + } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - acl = afs_fs_fetch_acl(&fc); + acl = afs_fs_fetch_acl(&fc, scb); } afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } @@ -80,6 +90,9 @@ static int afs_xattr_get_acl(const struct xattr_handler *handler, } key_put(key); +error_scb: + kfree(scb); +error: return ret; } @@ -92,22 +105,27 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler, const void *buffer, size_t size, int flags) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_acl *acl = NULL; struct key *key; - int ret; + int ret = -ENOMEM; if (flags == XATTR_CREATE) return -EINVAL; - key = afs_request_key(vnode->volume->cell); - if (IS_ERR(key)) - return PTR_ERR(key); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + goto error; acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); - if (!acl) { - key_put(key); - return -ENOMEM; + if (!acl) + goto error_scb; + + key = afs_request_key(vnode->volume->cell); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto error_acl; } acl->size = size; @@ -115,18 +133,25 @@ static int afs_xattr_set_acl(const struct xattr_handler *handler, ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_store_acl(&fc, acl); + afs_fs_store_acl(&fc, acl, scb); } afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } - kfree(acl); key_put(key); +error_acl: + kfree(acl); +error_scb: + kfree(scb); +error: return ret; } @@ -145,6 +170,7 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, void *buffer, size_t size) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *vnode = AFS_FS_I(inode); struct yfs_acl *yacl = NULL; struct key *key; @@ -171,21 +197,28 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, else if (which == 3) yacl->flags |= YFS_ACL_WANT_VOL_ACL; + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + goto error_yacl; + key = afs_request_key(vnode->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); - goto error_yacl; + goto error_scb; } ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - yfs_fs_fetch_opaque_acl(&fc, yacl); + yfs_fs_fetch_opaque_acl(&fc, yacl, scb); } afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } @@ -225,6 +258,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, error_key: key_put(key); +error_scb: + kfree(scb); error_yacl: yfs_free_opaque_acl(yacl); error: @@ -240,42 +275,54 @@ static int afs_xattr_set_yfs(const struct xattr_handler *handler, const void *buffer, size_t size, int flags) { struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_vnode *vnode = AFS_FS_I(inode); struct afs_acl *acl = NULL; struct key *key; - int ret; + int ret = -ENOMEM; if (flags == XATTR_CREATE || strcmp(name, "acl") != 0) return -EINVAL; - key = afs_request_key(vnode->volume->cell); - if (IS_ERR(key)) - return PTR_ERR(key); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + goto error; acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL); - if (!acl) { - key_put(key); - return -ENOMEM; - } + if (!acl) + goto error_scb; acl->size = size; memcpy(acl->data, buffer, size); + key = afs_request_key(vnode->volume->cell); + if (IS_ERR(key)) { + ret = PTR_ERR(key); + goto error_acl; + } + ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, key, true)) { + afs_dataversion_t data_version = vnode->status.data_version; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - yfs_fs_store_opaque_acl2(&fc, acl); + yfs_fs_store_opaque_acl2(&fc, acl, scb); } afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); ret = afs_end_vnode_operation(&fc); } +error_acl: kfree(acl); key_put(key); +error_scb: + kfree(scb); +error: return ret; } diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index b3ee99972d2f..80f579594660 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -183,24 +183,18 @@ static void xdr_dump_bad(const __be32 *bp) /* * Decode a YFSFetchStatus block */ -static int xdr_decode_YFSFetchStatus(struct afs_call *call, - const __be32 **_bp, - struct afs_file_status *status, - struct afs_vnode *vnode, - const afs_dataversion_t *expected_version, - struct afs_read *read_req) +static int xdr_decode_YFSFetchStatus(const __be32 **_bp, + struct afs_call *call, + struct afs_status_cb *scb) { const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp; + struct afs_file_status *status = &scb->status; u32 type; - u8 flags = 0; status->abort_code = ntohl(xdr->abort_code); if (status->abort_code != 0) { - if (vnode && status->abort_code == VNOVNODE) { - set_bit(AFS_VNODE_DELETED, &vnode->flags); + if (status->abort_code == VNOVNODE) status->nlink = 0; - __afs_break_callback(vnode); - } return 0; } @@ -209,77 +203,27 @@ static int xdr_decode_YFSFetchStatus(struct afs_call *call, case AFS_FTYPE_FILE: case AFS_FTYPE_DIR: case AFS_FTYPE_SYMLINK: - if (type != status->type && - vnode && - !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { - pr_warning("Vnode %llx:%llx:%x changed type %u to %u\n", - vnode->fid.vid, - vnode->fid.vnode, - vnode->fid.unique, - status->type, type); - goto bad; - } status->type = type; break; default: goto bad; } -#define EXTRACT_M4(FIELD) \ - do { \ - u32 x = ntohl(xdr->FIELD); \ - if (status->FIELD != x) { \ - flags |= AFS_VNODE_META_CHANGED; \ - status->FIELD = x; \ - } \ - } while (0) - -#define EXTRACT_M8(FIELD) \ - do { \ - u64 x = xdr_to_u64(xdr->FIELD); \ - if (status->FIELD != x) { \ - flags |= AFS_VNODE_META_CHANGED; \ - status->FIELD = x; \ - } \ - } while (0) - -#define EXTRACT_D8(FIELD) \ - do { \ - u64 x = xdr_to_u64(xdr->FIELD); \ - if (status->FIELD != x) { \ - flags |= AFS_VNODE_DATA_CHANGED; \ - status->FIELD = x; \ - } \ - } while (0) - - EXTRACT_M4(nlink); - EXTRACT_D8(size); - EXTRACT_D8(data_version); - EXTRACT_M8(author); - EXTRACT_M8(owner); - EXTRACT_M8(group); - EXTRACT_M4(mode); - EXTRACT_M4(caller_access); /* call ticket dependent */ - EXTRACT_M4(anon_access); - - status->mtime_client = xdr_to_time(xdr->mtime_client); - status->mtime_server = xdr_to_time(xdr->mtime_server); - status->lock_count = ntohl(xdr->lock_count); - - if (read_req) { - read_req->data_version = status->data_version; - read_req->file_size = status->size; - } - - *_bp += xdr_size(xdr); + status->nlink = ntohl(xdr->nlink); + status->author = xdr_to_u64(xdr->author); + status->owner = xdr_to_u64(xdr->owner); + status->caller_access = ntohl(xdr->caller_access); /* Ticket dependent */ + status->anon_access = ntohl(xdr->anon_access); + status->mode = ntohl(xdr->mode) & S_IALLUGO; + status->group = xdr_to_u64(xdr->group); + status->lock_count = ntohl(xdr->lock_count); - if (vnode) { - if (test_bit(AFS_VNODE_UNSET, &vnode->flags)) - flags |= AFS_VNODE_NOT_YET_SET; - afs_update_inode_from_status(vnode, status, expected_version, - flags); - } + status->mtime_client = xdr_to_time(xdr->mtime_client); + status->mtime_server = xdr_to_time(xdr->mtime_server); + status->size = xdr_to_u64(xdr->size); + status->data_version = xdr_to_u64(xdr->data_version); + *_bp += xdr_size(xdr); return 0; bad: @@ -288,34 +232,14 @@ bad: } /* - * Decode the file status. We need to lock the target vnode if we're going to - * update its status so that stat() sees the attributes update atomically. + * Decode a YFSCallBack block */ -static int yfs_decode_status(struct afs_call *call, - const __be32 **_bp, - struct afs_file_status *status, - struct afs_vnode *vnode, - const afs_dataversion_t *expected_version, - struct afs_read *read_req) -{ - int ret; - - if (!vnode) - return xdr_decode_YFSFetchStatus(call, _bp, status, vnode, - expected_version, read_req); - - write_seqlock(&vnode->cb_lock); - ret = xdr_decode_YFSFetchStatus(call, _bp, status, vnode, - expected_version, read_req); - write_sequnlock(&vnode->cb_lock); - return ret; -} - -static void xdr_decode_YFSCallBack_raw(struct afs_call *call, - struct afs_callback *cb, - const __be32 **_bp) +static void xdr_decode_YFSCallBack(const __be32 **_bp, + struct afs_call *call, + struct afs_status_cb *scb) { struct yfs_xdr_YFSCallBack *x = (void *)*_bp; + struct afs_callback *cb = &scb->callback; ktime_t cb_expiry; cb_expiry = call->reply_time; @@ -323,40 +247,10 @@ static void xdr_decode_YFSCallBack_raw(struct afs_call *call, cb->expires_at = ktime_divns(cb_expiry, NSEC_PER_SEC); cb->version = ntohl(x->version); cb->type = ntohl(x->type); - + scb->have_cb = true; *_bp += xdr_size(x); } -/* - * Decode a YFSCallBack block - */ -static void xdr_decode_YFSCallBack(struct afs_call *call, - struct afs_vnode *vnode, - const __be32 **_bp) -{ - struct afs_cb_interest *old, *cbi = call->cbi; - struct afs_callback cb; - - xdr_decode_YFSCallBack_raw(call, &cb, _bp); - - write_seqlock(&vnode->cb_lock); - - if (!afs_cb_is_broken(call->cb_break, vnode, cbi)) { - vnode->cb_version = cb.version; - vnode->cb_type = cb.type; - vnode->cb_expires_at = cb.expires_at; - old = vnode->cb_interest; - if (old != call->cbi) { - vnode->cb_interest = cbi; - cbi = old; - } - set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); - } - - write_sequnlock(&vnode->cb_lock); - call->cbi = cbi; -} - /* * Decode a YFSVolSync block */ @@ -441,11 +335,10 @@ static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp, } /* - * deliver reply data to an FS.FetchStatus + * Deliver a reply that's a status, callback and volsync. */ -static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call) +static int yfs_deliver_fs_status_cb_and_volsync(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; const __be32 *bp; int ret; @@ -453,15 +346,35 @@ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call) if (ret < 0) return ret; - _enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); + if (ret < 0) + return ret; + xdr_decode_YFSCallBack(&bp, call, call->out_scb); + xdr_decode_YFSVolSync(&bp, call->out_volsync); + + _leave(" = 0 [done]"); + return 0; +} + +/* + * Deliver reply data to operations that just return a file status and a volume + * sync record. + */ +static int yfs_deliver_status_and_volsync(struct afs_call *call) +{ + const __be32 *bp; + int ret; + + ret = afs_transfer_reply(call); + if (ret < 0) + return ret; + + bp = call->buffer; + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_YFSCallBack(call, vnode, &bp); xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); @@ -474,15 +387,15 @@ static int yfs_deliver_fs_fetch_status_vnode(struct afs_call *call) static const struct afs_call_type yfs_RXYFSFetchStatus_vnode = { .name = "YFS.FetchStatus(vnode)", .op = yfs_FS_FetchStatus, - .deliver = yfs_deliver_fs_fetch_status_vnode, + .deliver = yfs_deliver_fs_status_cb_and_volsync, .destructor = afs_flat_call_destructor, }; /* * Fetch the status information for a file. */ -int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync, - bool new_inode) +int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb, + struct afs_volsync *volsync) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -504,9 +417,8 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy } call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = volsync; - call->expected_version = new_inode ? 1 : vnode->status.data_version; /* marshall the parameters */ bp = call->request; @@ -515,7 +427,6 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy bp = xdr_encode_YFSFid(bp, &vnode->fid); yfs_check_req(call, bp); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_set_fc_call(call, fc); @@ -528,7 +439,6 @@ int yfs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsy */ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) { - struct afs_vnode *vnode = call->xvnode; struct afs_read *req = call->read_request; const __be32 *bp; unsigned int size; @@ -586,7 +496,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) if (req->offset == PAGE_SIZE) { req->offset = 0; if (req->page_done) - req->page_done(call, req); + req->page_done(req); req->index++; if (req->remain > 0) goto begin_page; @@ -623,13 +533,15 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) return ret; bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &vnode->status.data_version, req); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_YFSCallBack(call, vnode, &bp); + xdr_decode_YFSCallBack(&bp, call, call->out_scb); xdr_decode_YFSVolSync(&bp, call->out_volsync); + req->data_version = call->out_scb->status.data_version; + req->file_size = call->out_scb->status.size; + call->unmarshall++; /* Fall through */ @@ -642,7 +554,7 @@ static int yfs_deliver_fs_fetch_data64(struct afs_call *call) zero_user_segment(req->pages[req->index], req->offset, PAGE_SIZE); if (req->page_done) - req->page_done(call, req); + req->page_done(req); req->offset = 0; } @@ -669,7 +581,8 @@ static const struct afs_call_type yfs_RXYFSFetchData64 = { /* * Fetch data from a file. */ -int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) +int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_status_cb *scb, + struct afs_read *req) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -691,10 +604,9 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; call->read_request = req; - call->expected_version = vnode->status.data_version; /* marshall the parameters */ bp = call->request; @@ -706,7 +618,6 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) yfs_check_req(call, bp); refcount_inc(&req->usage); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_set_fc_call(call, fc); @@ -719,7 +630,6 @@ int yfs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) */ static int yfs_deliver_fs_create_vnode(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -732,15 +642,14 @@ static int yfs_deliver_fs_create_vnode(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; xdr_decode_YFSFid(&bp, call->out_fid); - ret = yfs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - xdr_decode_YFSCallBack_raw(call, call->out_cb, &bp); - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSCallBack(&bp, call, call->out_scb); + xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -762,10 +671,9 @@ static const struct afs_call_type afs_RXFSCreateFile = { int yfs_fs_create_file(struct afs_fs_cursor *fc, const char *name, umode_t mode, - u64 current_data_version, + struct afs_status_cb *dvnode_scb, struct afs_fid *newfid, - struct afs_file_status *newstatus, - struct afs_callback *newcb) + struct afs_status_cb *new_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -793,11 +701,9 @@ int yfs_fs_create_file(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; + call->out_dir_scb = dvnode_scb; call->out_fid = newfid; - call->out_extra_status = newstatus; - call->out_cb = newcb; - call->expected_version = current_data_version + 1; + call->out_scb = new_scb; /* marshall the parameters */ bp = call->request; @@ -829,10 +735,9 @@ static const struct afs_call_type yfs_RXFSMakeDir = { int yfs_fs_make_dir(struct afs_fs_cursor *fc, const char *name, umode_t mode, - u64 current_data_version, + struct afs_status_cb *dvnode_scb, struct afs_fid *newfid, - struct afs_file_status *newstatus, - struct afs_callback *newcb) + struct afs_status_cb *new_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -859,11 +764,9 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; + call->out_dir_scb = dvnode_scb; call->out_fid = newfid; - call->out_extra_status = newstatus; - call->out_cb = newcb; - call->expected_version = current_data_version + 1; + call->out_scb = new_scb; /* marshall the parameters */ bp = call->request; @@ -886,8 +789,6 @@ int yfs_fs_make_dir(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_remove_file2(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; - struct afs_vnode *vnode = call->xvnode; struct afs_fid fid; const __be32 *bp; int ret; @@ -898,20 +799,18 @@ static int yfs_deliver_fs_remove_file2(struct afs_call *call) if (ret < 0) return ret; - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; xdr_decode_YFSFid(&bp, &fid); - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; /* Was deleted if vnode->status.abort_code == VNOVNODE. */ - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSVolSync(&bp, call->out_volsync); return 0; } @@ -929,7 +828,8 @@ static const struct afs_call_type yfs_RXYFSRemoveFile2 = { * Remove a file and retrieve new file status. */ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - const char *name, u64 current_data_version) + const char *name, struct afs_status_cb *dvnode_scb, + struct afs_status_cb *vnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -954,9 +854,8 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; - call->xvnode = vnode; - call->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; + call->out_scb = vnode_scb; /* marshall the parameters */ bp = call->request; @@ -978,7 +877,6 @@ int yfs_fs_remove_file2(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_remove(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -988,14 +886,12 @@ static int yfs_deliver_fs_remove(struct afs_call *call) if (ret < 0) return ret; - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSVolSync(&bp, call->out_volsync); return 0; } @@ -1020,7 +916,8 @@ static const struct afs_call_type yfs_RXYFSRemoveDir = { * remove a file or directory */ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - const char *name, bool isdir, u64 current_data_version) + const char *name, bool isdir, + struct afs_status_cb *dvnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -1043,9 +940,7 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; - call->xvnode = vnode; - call->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; /* marshall the parameters */ bp = call->request; @@ -1067,7 +962,6 @@ int yfs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_link(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode, *vnode = call->xvnode; const __be32 *bp; int ret; @@ -1077,16 +971,14 @@ static int yfs_deliver_fs_link(struct afs_call *call) if (ret < 0) return ret; - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; } @@ -1105,7 +997,9 @@ static const struct afs_call_type yfs_RXYFSLink = { * Make a hard link. */ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, - const char *name, u64 current_data_version) + const char *name, + struct afs_status_cb *dvnode_scb, + struct afs_status_cb *vnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -1129,9 +1023,8 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; - call->xvnode = vnode; - call->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; + call->out_scb = vnode_scb; /* marshall the parameters */ bp = call->request; @@ -1154,7 +1047,6 @@ int yfs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, */ static int yfs_deliver_fs_symlink(struct afs_call *call) { - struct afs_vnode *dvnode = call->dvnode; const __be32 *bp; int ret; @@ -1167,14 +1059,13 @@ static int yfs_deliver_fs_symlink(struct afs_call *call) /* unmarshall the reply once we've received all of it */ bp = call->buffer; xdr_decode_YFSFid(&bp, call->out_fid); - ret = yfs_decode_status(call, &bp, call->out_extra_status, NULL, NULL, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = yfs_decode_status(call, &bp, &dvnode->status, dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1196,9 +1087,9 @@ static const struct afs_call_type yfs_RXYFSSymlink = { int yfs_fs_symlink(struct afs_fs_cursor *fc, const char *name, const char *contents, - u64 current_data_version, + struct afs_status_cb *dvnode_scb, struct afs_fid *newfid, - struct afs_file_status *newstatus) + struct afs_status_cb *vnode_scb) { struct afs_vnode *dvnode = fc->vnode; struct afs_call *call; @@ -1225,10 +1116,9 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = dvnode; + call->out_dir_scb = dvnode_scb; call->out_fid = newfid; - call->out_extra_status = newstatus; - call->expected_version = current_data_version + 1; + call->out_scb = vnode_scb; /* marshall the parameters */ bp = call->request; @@ -1252,8 +1142,6 @@ int yfs_fs_symlink(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_rename(struct afs_call *call) { - struct afs_vnode *orig_dvnode = call->dvnode; - struct afs_vnode *new_dvnode = call->xvnode; const __be32 *bp; int ret; @@ -1263,20 +1151,17 @@ static int yfs_deliver_fs_rename(struct afs_call *call) if (ret < 0) return ret; - /* unmarshall the reply once we've received all of it */ bp = call->buffer; - ret = yfs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - if (new_dvnode != orig_dvnode) { - ret = yfs_decode_status(call, &bp, &new_dvnode->status, new_dvnode, - &call->expected_version_2, NULL); + if (call->out_dir_scb != call->out_scb) { + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; } - xdr_decode_YFSVolSync(&bp, NULL); + xdr_decode_YFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; } @@ -1298,8 +1183,8 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, const char *orig_name, struct afs_vnode *new_dvnode, const char *new_name, - u64 current_orig_data_version, - u64 current_new_data_version) + struct afs_status_cb *orig_dvnode_scb, + struct afs_status_cb *new_dvnode_scb) { struct afs_vnode *orig_dvnode = fc->vnode; struct afs_call *call; @@ -1325,10 +1210,8 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, return -ENOMEM; call->key = fc->key; - call->dvnode = orig_dvnode; - call->xvnode = new_dvnode; - call->expected_version = current_orig_data_version + 1; - call->expected_version_2 = current_new_data_version + 1; + call->out_dir_scb = orig_dvnode_scb; + call->out_scb = new_dvnode_scb; /* marshall the parameters */ bp = call->request; @@ -1347,42 +1230,13 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, return afs_wait_for_call_to_complete(call, &fc->ac); } -/* - * Deliver reply data to a YFS.StoreData64 operation. - */ -static int yfs_deliver_fs_store_data(struct afs_call *call) -{ - struct afs_vnode *vnode = call->xvnode; - const __be32 *bp; - int ret; - - _enter(""); - - ret = afs_transfer_reply(call); - if (ret < 0) - return ret; - - /* unmarshall the reply once we've received all of it */ - bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); - if (ret < 0) - return ret; - xdr_decode_YFSVolSync(&bp, NULL); - - afs_pages_written_back(vnode, call); - - _leave(" = 0 [done]"); - return 0; -} - /* * YFS.StoreData64 operation type. */ static const struct afs_call_type yfs_RXYFSStoreData64 = { .name = "YFS.StoreData64", .op = yfs_FS_StoreData64, - .deliver = yfs_deliver_fs_store_data, + .deliver = yfs_deliver_status_and_volsync, .destructor = afs_flat_call_destructor, }; @@ -1391,7 +1245,8 @@ static const struct afs_call_type yfs_RXYFSStoreData64 = { */ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, pgoff_t first, pgoff_t last, - unsigned offset, unsigned to) + unsigned offset, unsigned to, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1429,13 +1284,12 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, call->key = fc->key; call->mapping = mapping; - call->xvnode = vnode; call->first = first; call->last = last; call->first_offset = offset; call->last_to = to; call->send_pages = true; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1455,47 +1309,20 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, return afs_wait_for_call_to_complete(call, &fc->ac); } -/* - * deliver reply data to an FS.StoreStatus - */ -static int yfs_deliver_fs_store_status(struct afs_call *call) -{ - struct afs_vnode *vnode = call->xvnode; - const __be32 *bp; - int ret; - - _enter(""); - - ret = afs_transfer_reply(call); - if (ret < 0) - return ret; - - /* unmarshall the reply once we've received all of it */ - bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); - if (ret < 0) - return ret; - xdr_decode_YFSVolSync(&bp, NULL); - - _leave(" = 0 [done]"); - return 0; -} - /* * YFS.StoreStatus operation type */ static const struct afs_call_type yfs_RXYFSStoreStatus = { .name = "YFS.StoreStatus", .op = yfs_FS_StoreStatus, - .deliver = yfs_deliver_fs_store_status, + .deliver = yfs_deliver_status_and_volsync, .destructor = afs_flat_call_destructor, }; static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = { .name = "YFS.StoreData64", .op = yfs_FS_StoreData64, - .deliver = yfs_deliver_fs_store_status, + .deliver = yfs_deliver_status_and_volsync, .destructor = afs_flat_call_destructor, }; @@ -1503,7 +1330,8 @@ static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = { * Set the attributes on a file, using YFS.StoreData64 rather than * YFS.StoreStatus so as to alter the file size also. */ -static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) +static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1524,8 +1352,7 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; - call->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1549,7 +1376,8 @@ static int yfs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) * Set the attributes on a file, using YFS.StoreData64 if there's a change in * file size, and YFS.StoreStatus otherwise. */ -int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) +int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1557,7 +1385,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) __be32 *bp; if (attr->ia_valid & ATTR_SIZE) - return yfs_fs_setattr_size(fc, attr); + return yfs_fs_setattr_size(fc, attr, scb); _enter(",%x,{%llx:%llu},,", key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); @@ -1572,8 +1400,7 @@ int yfs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; - call->expected_version = vnode->status.data_version; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1763,34 +1590,6 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc, return afs_wait_for_call_to_complete(call, &fc->ac); } -/* - * Deliver reply data to operations that just return a file status and a volume - * sync record. - */ -static int yfs_deliver_status_and_volsync(struct afs_call *call) -{ - struct afs_vnode *vnode = call->xvnode; - const __be32 *bp; - int ret; - - _enter("{%u}", call->unmarshall); - - ret = afs_transfer_reply(call); - if (ret < 0) - return ret; - - /* unmarshall the reply once we've received all of it */ - bp = call->buffer; - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); - if (ret < 0) - return ret; - xdr_decode_YFSVolSync(&bp, NULL); - - _leave(" = 0 [done]"); - return 0; -} - /* * YFS.SetLock operation type */ @@ -1826,7 +1625,8 @@ static const struct afs_call_type yfs_RXYFSReleaseLock = { /* * Set a lock on a file */ -int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) +int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1845,7 +1645,8 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1865,7 +1666,7 @@ int yfs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) /* * extend a lock on a file */ -int yfs_fs_extend_lock(struct afs_fs_cursor *fc) +int yfs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1883,7 +1684,8 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1902,7 +1704,7 @@ int yfs_fs_extend_lock(struct afs_fs_cursor *fc) /* * release a lock on a file */ -int yfs_fs_release_lock(struct afs_fs_cursor *fc) +int yfs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -1920,7 +1722,8 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc) return -ENOMEM; call->key = fc->key; - call->xvnode = vnode; + call->lvnode = vnode; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1936,43 +1739,13 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc) return afs_wait_for_call_to_complete(call, &fc->ac); } -/* - * Deliver reply data to an FS.FetchStatus with no vnode. - */ -static int yfs_deliver_fs_fetch_status(struct afs_call *call) -{ - struct afs_file_status *status = call->out_extra_status; - struct afs_callback *callback = call->out_cb; - struct afs_volsync *volsync = call->out_volsync; - const __be32 *bp; - int ret; - - ret = afs_transfer_reply(call); - if (ret < 0) - return ret; - - _enter(""); - - /* unmarshall the reply once we've received all of it */ - bp = call->buffer; - ret = yfs_decode_status(call, &bp, status, NULL, - &call->expected_version, NULL); - if (ret < 0) - return ret; - xdr_decode_YFSCallBack_raw(call, callback, &bp); - xdr_decode_YFSVolSync(&bp, volsync); - - _leave(" = 0 [done]"); - return 0; -} - /* * YFS.FetchStatus operation type */ static const struct afs_call_type yfs_RXYFSFetchStatus = { .name = "YFS.FetchStatus", .op = yfs_FS_FetchStatus, - .deliver = yfs_deliver_fs_fetch_status, + .deliver = yfs_deliver_fs_status_cb_and_volsync, .destructor = afs_flat_call_destructor, }; @@ -1982,8 +1755,7 @@ static const struct afs_call_type yfs_RXYFSFetchStatus = { int yfs_fs_fetch_status(struct afs_fs_cursor *fc, struct afs_net *net, struct afs_fid *fid, - struct afs_file_status *status, - struct afs_callback *callback, + struct afs_status_cb *scb, struct afs_volsync *volsync) { struct afs_call *call; @@ -2004,10 +1776,8 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, } call->key = fc->key; - call->out_extra_status = status; - call->out_cb = callback; + call->out_scb = scb; call->out_volsync = volsync; - call->expected_version = 1; /* vnode->status.data_version */ /* marshall the parameters */ bp = call->request; @@ -2016,7 +1786,6 @@ int yfs_fs_fetch_status(struct afs_fs_cursor *fc, bp = xdr_encode_YFSFid(bp, fid); yfs_check_req(call, bp); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, fid); afs_set_fc_call(call, fc); @@ -2069,8 +1838,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) bp = call->buffer; scb = &call->out_scb[call->count]; - ret = yfs_decode_status(call, &bp, &scb->status, - NULL, NULL, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, scb); if (ret < 0) return ret; @@ -2110,8 +1878,7 @@ static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call) _debug("unmarshall CB array"); bp = call->buffer; scb = &call->out_scb[call->count]; - xdr_decode_YFSCallBack_raw(call, &scb->callback, &bp); - scb->have_cb = true; + xdr_decode_YFSCallBack(&bp, call, scb); call->count++; if (call->count < call->count2) goto more_cbs; @@ -2191,7 +1958,6 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, bp = xdr_encode_YFSFid(bp, &fids[i]); yfs_check_req(call, bp); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &fids[0]); afs_set_fc_call(call, fc); @@ -2204,8 +1970,6 @@ int yfs_fs_inline_bulk_status(struct afs_fs_cursor *fc, */ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) { - struct afs_volsync *volsync = call->out_volsync; - struct afs_vnode *vnode = call->xvnode; struct yfs_acl *yacl = call->out_yacl; struct afs_acl *acl; const __be32 *bp; @@ -2291,11 +2055,10 @@ static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call) bp = call->buffer; yacl->inherit_flag = ntohl(*bp++); yacl->num_cleaned = ntohl(*bp++); - ret = yfs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_YFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - xdr_decode_YFSVolSync(&bp, volsync); + xdr_decode_YFSVolSync(&bp, call->out_volsync); call->unmarshall++; @@ -2330,7 +2093,8 @@ static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = { * Fetch the YFS advanced ACLs for a file. */ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, - struct yfs_acl *yacl) + struct yfs_acl *yacl, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -2353,8 +2117,8 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, call->key = fc->key; call->out_yacl = yacl; - call->xvnode = vnode; - call->out_volsync = NULL; /* volsync */ + call->out_scb = scb; + call->out_volsync = NULL; /* marshall the parameters */ bp = call->request; @@ -2363,7 +2127,6 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, bp = xdr_encode_YFSFid(bp, &vnode->fid); yfs_check_req(call, bp); - call->cb_break = fc->cb_break; afs_use_fs_server(call, fc->cbi); trace_afs_make_fs_call(call, &vnode->fid); afs_make_call(&fc->ac, call, GFP_KERNEL); @@ -2383,7 +2146,8 @@ static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = { /* * Fetch the YFS ACL for a file. */ -int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl) +int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl, + struct afs_status_cb *scb) { struct afs_vnode *vnode = fc->vnode; struct afs_call *call; @@ -2407,7 +2171,7 @@ int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *fc, const struct afs_acl *acl } call->key = fc->key; - call->xvnode = vnode; + call->out_scb = scb; call->out_volsync = NULL; /* marshall the parameters */ -- cgit v1.2.3 From 7c712458669f203fb2c59af8aafea4c4767b4bc9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 May 2019 15:35:44 +0100 Subject: afs: Don't save callback version and type fields Don't save callback version and type fields as the version is about the format of the callback information and the type is relative to the particular RPC call. Signed-off-by: David Howells --- fs/afs/afs.h | 4 ++-- fs/afs/fsclient.c | 4 ++-- fs/afs/inode.c | 8 +------- fs/afs/internal.h | 2 -- fs/afs/super.c | 1 - fs/afs/yfsclient.c | 2 -- 6 files changed, 5 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/afs/afs.h b/fs/afs/afs.h index 8fa0dffff1cc..819678bd8bec 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h @@ -72,8 +72,8 @@ typedef enum { struct afs_callback { time64_t expires_at; /* Time at which expires */ - unsigned version; /* Callback version */ - afs_callback_type_t type; /* Type of callback */ + //unsigned version; /* Callback version */ + //afs_callback_type_t type; /* Type of callback */ }; struct afs_callback_break { diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 5c1b7a031509..89b684c957b9 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -148,9 +148,9 @@ static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_callback *cb = &scb->callback; const __be32 *bp = *_bp; - cb->version = ntohl(*bp++); + bp++; /* version */ cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++)); - cb->type = ntohl(*bp++); + bp++; /* type */ scb->have_cb = true; *_bp = bp; } diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 4a9004b9ac5f..8d3d060a33fc 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -136,12 +136,8 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, if (!scb->have_cb) { /* it's a symlink we just created (the fileserver * didn't give us a callback) */ - vnode->cb_version = 0; - vnode->cb_type = 0; vnode->cb_expires_at = ktime_get_real_seconds(); } else { - vnode->cb_version = scb->callback.version; - vnode->cb_type = scb->callback.type; vnode->cb_expires_at = scb->callback.expires_at; old_cbi = vnode->cb_interest; if (cbi != old_cbi) @@ -248,8 +244,6 @@ static void afs_apply_callback(struct afs_fs_cursor *fc, struct afs_callback *cb = &scb->callback; if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { - vnode->cb_version = cb->version; - vnode->cb_type = cb->type; vnode->cb_expires_at = cb->expires_at; old = vnode->cb_interest; if (old != fc->cbi) { @@ -535,7 +529,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, clear_bit(AFS_VNODE_UNSET, &vnode->flags); inode->i_flags |= S_NOATIME; unlock_new_inode(inode); - _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type); + _leave(" = %p", inode); return inode; /* failure */ diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 6ed7d4df4ec6..ca7edfe97410 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -683,8 +683,6 @@ struct afs_vnode { seqlock_t cb_lock; /* Lock for ->cb_interest, ->status, ->cb_*break */ time64_t cb_expires_at; /* time at which callback expires */ - unsigned cb_version; /* callback version */ - afs_callback_type_t cb_type; /* type of callback */ }; static inline struct fscache_cookie *afs_vnode_cache(struct afs_vnode *vnode) diff --git a/fs/afs/super.c b/fs/afs/super.c index f45a95eea237..a81c235f8c57 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -683,7 +683,6 @@ static struct inode *afs_alloc_inode(struct super_block *sb) #endif vnode->flags = 1 << AFS_VNODE_UNSET; - vnode->cb_type = 0; vnode->lock_state = AFS_VNODE_LOCK_NONE; init_rwsem(&vnode->rmdir_lock); diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 80f579594660..c8f71fc9920b 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c @@ -245,8 +245,6 @@ static void xdr_decode_YFSCallBack(const __be32 **_bp, cb_expiry = call->reply_time; cb_expiry = ktime_add(cb_expiry, xdr_to_u64(x->expiration_time) * 100); cb->expires_at = ktime_divns(cb_expiry, NSEC_PER_SEC); - cb->version = ntohl(x->version); - cb->type = ntohl(x->type); scb->have_cb = true; *_bp += xdr_size(x); } -- cgit v1.2.3 From c925bd0ac4741badb567f594c41c8cba5e9e9732 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 14:31:11 +0100 Subject: afs: Split afs_validate() so first part can be used under LOOKUP_RCU Split afs_validate() so that the part that decides if the vnode is still valid can be used under LOOKUP_RCU conditions from afs_d_revalidate(). Signed-off-by: David Howells --- fs/afs/inode.c | 37 ++++++++++++++++++++++++------------- fs/afs/internal.h | 1 + 2 files changed, 25 insertions(+), 13 deletions(-) (limited to 'fs') diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 8d3d060a33fc..5c95da7d5f3d 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -561,23 +561,12 @@ void afs_zap_data(struct afs_vnode *vnode) } /* - * validate a vnode/inode - * - there are several things we need to check - * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, - * symlink) - * - parent dir metadata changed (security changes) - * - dentry data changed (write, truncate) - * - dentry metadata changed (security changes) + * Check the validity of a vnode/inode. */ -int afs_validate(struct afs_vnode *vnode, struct key *key) +bool afs_check_validity(struct afs_vnode *vnode) { time64_t now = ktime_get_real_seconds(); bool valid; - int ret; - - _enter("{v={%llx:%llu} fl=%lx},%x", - vnode->fid.vid, vnode->fid.vnode, vnode->flags, - key_serial(key)); /* Quickly check the callback state. Ideally, we'd use read_seqbegin * here, but we have no way to pass the net namespace to the RCU @@ -606,6 +595,28 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) } read_sequnlock_excl(&vnode->cb_lock); + return valid; +} + +/* + * validate a vnode/inode + * - there are several things we need to check + * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, + * symlink) + * - parent dir metadata changed (security changes) + * - dentry data changed (write, truncate) + * - dentry metadata changed (security changes) + */ +int afs_validate(struct afs_vnode *vnode, struct key *key) +{ + bool valid; + int ret; + + _enter("{v={%llx:%llu} fl=%lx},%x", + vnode->fid.vid, vnode->fid.vnode, vnode->flags, + key_serial(key)); + + valid = afs_check_validity(vnode); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) clear_nlink(&vnode->vfs_inode); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index ca7edfe97410..54688f6ca9e5 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1022,6 +1022,7 @@ extern struct inode *afs_iget(struct super_block *, struct key *, struct afs_cb_interest *, struct afs_vnode *); extern void afs_zap_data(struct afs_vnode *); +extern bool afs_check_validity(struct afs_vnode *); extern int afs_validate(struct afs_vnode *, struct key *); extern int afs_getattr(const struct path *, struct kstat *, u32, unsigned int); extern int afs_setattr(struct dentry *, struct iattr *); -- cgit v1.2.3 From f642404a0436a50912c218009ccc7856d48d784c Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 13 May 2019 16:14:32 +0100 Subject: afs: Make vnode->cb_interest RCU safe Use RCU-based freeing for afs_cb_interest struct objects and use RCU on vnode->cb_interest. Use that change to allow afs_check_validity() to use read_seqbegin_or_lock() instead of read_seqlock_excl(). This also requires the caller of afs_check_validity() to hold the RCU read lock across the call. Signed-off-by: David Howells --- fs/afs/callback.c | 21 ++++++++------- fs/afs/dir.c | 15 +++++++---- fs/afs/inode.c | 81 ++++++++++++++++++++++++++++++++++--------------------- fs/afs/internal.h | 12 ++++++--- fs/afs/rotate.c | 18 ++++++++----- fs/afs/security.c | 8 +++--- fs/afs/super.c | 4 +-- 7 files changed, 100 insertions(+), 59 deletions(-) (limited to 'fs') diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 4876079aa643..d441bef72163 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -94,15 +94,15 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode, struct afs_server *server = entry->server; again: - if (vnode->cb_interest && - likely(vnode->cb_interest == entry->cb_interest)) + vcbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); + if (vcbi && likely(vcbi == entry->cb_interest)) return 0; read_lock(&slist->lock); cbi = afs_get_cb_interest(entry->cb_interest); read_unlock(&slist->lock); - vcbi = vnode->cb_interest; if (vcbi) { if (vcbi == cbi) { afs_put_cb_interest(afs_v2net(vnode), cbi); @@ -114,8 +114,9 @@ again: */ if (cbi && vcbi->server == cbi->server) { write_seqlock(&vnode->cb_lock); - old = vnode->cb_interest; - vnode->cb_interest = cbi; + old = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); + rcu_assign_pointer(vnode->cb_interest, cbi); write_sequnlock(&vnode->cb_lock); afs_put_cb_interest(afs_v2net(vnode), old); return 0; @@ -160,8 +161,9 @@ again: */ write_seqlock(&vnode->cb_lock); - old = vnode->cb_interest; - vnode->cb_interest = cbi; + old = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); + rcu_assign_pointer(vnode->cb_interest, cbi); vnode->cb_s_break = cbi->server->cb_s_break; vnode->cb_v_break = vnode->volume->cb_v_break; clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); @@ -191,10 +193,11 @@ void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) vi = NULL; write_unlock(&cbi->server->cb_break_lock); - kfree(vi); + if (vi) + kfree_rcu(vi, rcu); afs_put_server(net, cbi->server); } - kfree(cbi); + kfree_rcu(cbi, rcu); } } diff --git a/fs/afs/dir.c b/fs/afs/dir.c index f7344b045799..338c2260b0a0 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -638,11 +638,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct key *key) { struct afs_lookup_cookie *cookie; - struct afs_cb_interest *cbi = NULL; + struct afs_cb_interest *dcbi, *cbi = NULL; struct afs_super_info *as = dir->i_sb->s_fs_info; struct afs_status_cb *scb; struct afs_iget_data data; struct afs_fs_cursor fc; + struct afs_server *server; struct afs_vnode *dvnode = AFS_FS_I(dir); struct inode *inode = NULL; int ret, i; @@ -658,10 +659,14 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, cookie->nr_fids = 1; /* slot 0 is saved for the fid we actually want */ read_seqlock_excl(&dvnode->cb_lock); - if (dvnode->cb_interest && - dvnode->cb_interest->server && - test_bit(AFS_SERVER_FL_NO_IBULK, &dvnode->cb_interest->server->flags)) - cookie->one_only = true; + dcbi = rcu_dereference_protected(dvnode->cb_interest, + lockdep_is_held(&dvnode->cb_lock.lock)); + if (dcbi) { + server = dcbi->server; + if (server && + test_bit(AFS_SERVER_FL_NO_IBULK, &server->flags)) + cookie->one_only = true; + } read_sequnlock_excl(&dvnode->cb_lock); for (i = 0; i < 50; i++) diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 5c95da7d5f3d..ba35b4824408 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -139,9 +139,10 @@ static int afs_inode_init_from_status(struct afs_vnode *vnode, struct key *key, vnode->cb_expires_at = ktime_get_real_seconds(); } else { vnode->cb_expires_at = scb->callback.expires_at; - old_cbi = vnode->cb_interest; + old_cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); if (cbi != old_cbi) - vnode->cb_interest = afs_get_cb_interest(cbi); + rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(cbi)); else old_cbi = NULL; set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); @@ -245,9 +246,10 @@ static void afs_apply_callback(struct afs_fs_cursor *fc, if (!afs_cb_is_broken(cb_break, vnode, fc->cbi)) { vnode->cb_expires_at = cb->expires_at; - old = vnode->cb_interest; + old = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); if (old != fc->cbi) { - vnode->cb_interest = afs_get_cb_interest(fc->cbi); + rcu_assign_pointer(vnode->cb_interest, afs_get_cb_interest(fc->cbi)); afs_put_cb_interest(afs_v2net(vnode), old); } set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); @@ -565,36 +567,46 @@ void afs_zap_data(struct afs_vnode *vnode) */ bool afs_check_validity(struct afs_vnode *vnode) { + struct afs_cb_interest *cbi; + struct afs_server *server; + struct afs_volume *volume = vnode->volume; time64_t now = ktime_get_real_seconds(); bool valid; + unsigned int cb_break, cb_s_break, cb_v_break; + int seq = 0; - /* Quickly check the callback state. Ideally, we'd use read_seqbegin - * here, but we have no way to pass the net namespace to the RCU - * cleanup for the server record. - */ - read_seqlock_excl(&vnode->cb_lock); - - if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { - if (vnode->cb_s_break != vnode->cb_interest->server->cb_s_break || - vnode->cb_v_break != vnode->volume->cb_v_break) { - vnode->cb_s_break = vnode->cb_interest->server->cb_s_break; - vnode->cb_v_break = vnode->volume->cb_v_break; - valid = false; - } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { - valid = false; - } else if (vnode->cb_expires_at - 10 <= now) { - valid = false; - } else { + do { + read_seqbegin_or_lock(&vnode->cb_lock, &seq); + cb_v_break = READ_ONCE(volume->cb_v_break); + cb_break = vnode->cb_break; + + if (test_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) { + cbi = rcu_dereference(vnode->cb_interest); + server = rcu_dereference(cbi->server); + cb_s_break = READ_ONCE(server->cb_s_break); + + if (vnode->cb_s_break != cb_s_break || + vnode->cb_v_break != cb_v_break) { + vnode->cb_s_break = cb_s_break; + vnode->cb_v_break = cb_v_break; + valid = false; + } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { + valid = false; + } else if (vnode->cb_expires_at - 10 <= now) { + valid = false; + } else { + valid = true; + } + } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { valid = true; + } else { + vnode->cb_v_break = cb_v_break; + valid = false; } - } else if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { - valid = true; - } else { - vnode->cb_v_break = vnode->volume->cb_v_break; - valid = false; - } - read_sequnlock_excl(&vnode->cb_lock); + } while (need_seqretry(&vnode->cb_lock, seq)); + + done_seqretry(&vnode->cb_lock, seq); return valid; } @@ -616,7 +628,9 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) vnode->fid.vid, vnode->fid.vnode, vnode->flags, key_serial(key)); + rcu_read_lock(); valid = afs_check_validity(vnode); + rcu_read_unlock(); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) clear_nlink(&vnode->vfs_inode); @@ -703,6 +717,7 @@ int afs_drop_inode(struct inode *inode) */ void afs_evict_inode(struct inode *inode) { + struct afs_cb_interest *cbi; struct afs_vnode *vnode; vnode = AFS_FS_I(inode); @@ -719,10 +734,14 @@ void afs_evict_inode(struct inode *inode) truncate_inode_pages_final(&inode->i_data); clear_inode(inode); - if (vnode->cb_interest) { - afs_put_cb_interest(afs_i2net(inode), vnode->cb_interest); - vnode->cb_interest = NULL; + write_seqlock(&vnode->cb_lock); + cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); + if (cbi) { + afs_put_cb_interest(afs_i2net(inode), cbi); + rcu_assign_pointer(vnode->cb_interest, NULL); } + write_sequnlock(&vnode->cb_lock); while (!list_empty(&vnode->wb_keys)) { struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 54688f6ca9e5..3dbb1e840dfd 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -554,7 +554,10 @@ struct afs_server { struct afs_vol_interest { struct hlist_node srv_link; /* Link in server->cb_volumes */ struct hlist_head cb_interests; /* List of callback interests on the server */ - afs_volid_t vid; /* Volume ID to match */ + union { + struct rcu_head rcu; + afs_volid_t vid; /* Volume ID to match */ + }; unsigned int usage; }; @@ -566,7 +569,10 @@ struct afs_cb_interest { struct afs_vol_interest *vol_interest; struct afs_server *server; /* Server on which this interest resides */ struct super_block *sb; /* Superblock on which inodes reside */ - afs_volid_t vid; /* Volume ID to match */ + union { + struct rcu_head rcu; + afs_volid_t vid; /* Volume ID to match */ + }; refcount_t usage; }; @@ -676,7 +682,7 @@ struct afs_vnode { afs_lock_type_t lock_type : 8; /* outstanding callback notification on this file */ - struct afs_cb_interest *cb_interest; /* Server on which this resides */ + struct afs_cb_interest __rcu *cb_interest; /* Server on which this resides */ unsigned int cb_s_break; /* Mass break counter on ->server */ unsigned int cb_v_break; /* Mass break counter on ->volume */ unsigned int cb_break; /* Break counter on vnode */ diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c index 52f3a9910f0d..b00c739e0e63 100644 --- a/fs/afs/rotate.c +++ b/fs/afs/rotate.c @@ -66,7 +66,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc, fc->untried = (1UL << fc->server_list->nr_servers) - 1; fc->index = READ_ONCE(fc->server_list->preferred); - cbi = vnode->cb_interest; + cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); if (cbi) { /* See if the vnode's preferred record is still available */ for (i = 0; i < fc->server_list->nr_servers; i++) { @@ -87,8 +88,8 @@ static bool afs_start_fs_iteration(struct afs_fs_cursor *fc, /* Note that the callback promise is effectively broken */ write_seqlock(&vnode->cb_lock); - ASSERTCMP(cbi, ==, vnode->cb_interest); - vnode->cb_interest = NULL; + ASSERTCMP(cbi, ==, rcu_access_pointer(vnode->cb_interest)); + rcu_assign_pointer(vnode->cb_interest, NULL); if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) vnode->cb_break++; write_sequnlock(&vnode->cb_lock); @@ -417,7 +418,9 @@ selected_server: if (error < 0) goto failed_set_error; - fc->cbi = afs_get_cb_interest(vnode->cb_interest); + fc->cbi = afs_get_cb_interest( + rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock))); read_lock(&server->fs_lock); alist = rcu_dereference_protected(server->addresses, @@ -487,12 +490,15 @@ failed: bool afs_select_current_fileserver(struct afs_fs_cursor *fc) { struct afs_vnode *vnode = fc->vnode; - struct afs_cb_interest *cbi = vnode->cb_interest; + struct afs_cb_interest *cbi; struct afs_addr_list *alist; int error = fc->ac.error; _enter(""); + cbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); + switch (error) { case SHRT_MAX: if (!cbi) { @@ -501,7 +507,7 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc) return false; } - fc->cbi = afs_get_cb_interest(vnode->cb_interest); + fc->cbi = afs_get_cb_interest(cbi); read_lock(&cbi->server->fs_lock); alist = rcu_dereference_protected(cbi->server->addresses, diff --git a/fs/afs/security.c b/fs/afs/security.c index 857f09d09ee9..5d8ece98561e 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -146,7 +146,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, } if (afs_cb_is_broken(cb_break, vnode, - vnode->cb_interest)) { + rcu_dereference(vnode->cb_interest))) { changed = true; break; } @@ -176,7 +176,7 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, } } - if (afs_cb_is_broken(cb_break, vnode, vnode->cb_interest)) + if (afs_cb_is_broken(cb_break, vnode, rcu_dereference(vnode->cb_interest))) goto someone_else_changed_it; /* We need a ref on any permits list we want to copy as we'll have to @@ -253,14 +253,16 @@ found: kfree(new); + rcu_read_lock(); spin_lock(&vnode->lock); zap = rcu_access_pointer(vnode->permit_cache); - if (!afs_cb_is_broken(cb_break, vnode, vnode->cb_interest) && + if (!afs_cb_is_broken(cb_break, vnode, rcu_dereference(vnode->cb_interest)) && zap == permits) rcu_assign_pointer(vnode->permit_cache, replacement); else zap = replacement; spin_unlock(&vnode->lock); + rcu_read_unlock(); afs_put_permits(zap); out_put: afs_put_permits(permits); diff --git a/fs/afs/super.c b/fs/afs/super.c index a81c235f8c57..f76473ad7bbb 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -677,7 +677,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) vnode->volume = NULL; vnode->lock_key = NULL; vnode->permit_cache = NULL; - vnode->cb_interest = NULL; + RCU_INIT_POINTER(vnode->cb_interest, NULL); #ifdef CONFIG_AFS_FSCACHE vnode->cache = NULL; #endif @@ -707,7 +707,7 @@ static void afs_destroy_inode(struct inode *inode) _debug("DESTROY INODE %p", inode); - ASSERTCMP(vnode->cb_interest, ==, NULL); + ASSERTCMP(rcu_access_pointer(vnode->cb_interest), ==, NULL); atomic_dec(&afs_count_active_inodes); } -- cgit v1.2.3 From 61c347ba551162edb1c6abfa60ce6907baf7a1af Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 9 May 2019 14:15:11 +0100 Subject: afs: Clear AFS_VNODE_CB_PROMISED if we detect callback expiry Fix afs_validate() to clear AFS_VNODE_CB_PROMISED on a vnode if we detect any condition that causes the callback promise to be broken implicitly, including server break (cb_s_break), volume break (cb_v_break) or callback expiry. Fixes: ae3b7361dc0e ("afs: Fix validation/callback interaction") Reported-by: Marc Dionne Signed-off-by: David Howells --- fs/afs/inode.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/afs/inode.c b/fs/afs/inode.c index ba35b4824408..37c5de793353 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -571,7 +571,7 @@ bool afs_check_validity(struct afs_vnode *vnode) struct afs_server *server; struct afs_volume *volume = vnode->volume; time64_t now = ktime_get_real_seconds(); - bool valid; + bool valid, need_clear = false; unsigned int cb_break, cb_s_break, cb_v_break; int seq = 0; @@ -589,10 +589,13 @@ bool afs_check_validity(struct afs_vnode *vnode) vnode->cb_v_break != cb_v_break) { vnode->cb_s_break = cb_s_break; vnode->cb_v_break = cb_v_break; + need_clear = true; valid = false; } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { + need_clear = true; valid = false; } else if (vnode->cb_expires_at - 10 <= now) { + need_clear = true; valid = false; } else { valid = true; @@ -607,6 +610,15 @@ bool afs_check_validity(struct afs_vnode *vnode) } while (need_seqretry(&vnode->cb_lock, seq)); done_seqretry(&vnode->cb_lock, seq); + + if (need_clear) { + write_seqlock(&vnode->cb_lock); + if (cb_break == vnode->cb_break) + __afs_break_callback(vnode); + write_sequnlock(&vnode->cb_lock); + valid = false; + } + return valid; } -- cgit v1.2.3 From a38a75581e6e2f783e7b8658e9ca5d4243279f55 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 May 2019 12:29:11 +0100 Subject: 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 --- fs/afs/afs.h | 2 ++ fs/afs/dir.c | 36 +++++++++++++----------------------- fs/afs/fsclient.c | 2 ++ fs/afs/inode.c | 18 ++++++++++++++---- fs/afs/internal.h | 1 - fs/afs/yfsclient.c | 2 ++ 6 files changed, 33 insertions(+), 28 deletions(-) (limited to 'fs') 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 { struct afs_status_cb { struct afs_file_status status; struct afs_callback callback; + bool have_status; /* True if status record was retrieved */ bool have_cb; /* True if cb record was retrieved */ + bool have_error; /* True if status.abort_code indicates an error */ }; /* 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: * However, if we didn't have a callback promise outstanding, or it was * outstanding on a different server, then it won't break it either... */ -int afs_dir_remove_link(struct dentry *dentry, struct key *key, - unsigned long d_version_before, - unsigned long d_version_after) +static int afs_dir_remove_link(struct afs_vnode *dvnode, struct dentry *dentry, + struct key *key) { - bool dir_valid; int ret = 0; - /* There were no intervening changes on the server if the version - * number we got back was incremented by exactly 1. - */ - dir_valid = (d_version_after == d_version_before + 1); - if (d_really_is_positive(dentry)) { struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) { /* Already done */ - } else if (dir_valid) { + } else if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) { + write_seqlock(&vnode->cb_lock); drop_nlink(&vnode->vfs_inode); if (vnode->vfs_inode.i_nlink == 0) { set_bit(AFS_VNODE_DELETED, &vnode->flags); - clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); + __afs_break_callback(vnode); } + write_sequnlock(&vnode->cb_lock); ret = 0; } else { - clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); + afs_break_callback(vnode); if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) kdebug("AFS_VNODE_DELETED"); @@ -1348,7 +1343,6 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode = NULL; struct key *key; - unsigned long d_version = (unsigned long)dentry->d_fsdata; bool need_rehash = false; int ret; @@ -1395,20 +1389,16 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { afs_dataversion_t data_version = dvnode->status.data_version + 1; + afs_dataversion_t data_version_2 = vnode->status.data_version; while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + fc.cb_break_2 = afs_calc_vnode_cb_break(vnode); if (test_bit(AFS_SERVER_FL_IS_YFS, &fc.cbi->server->flags) && !test_bit(AFS_SERVER_FL_NO_RM2, &fc.cbi->server->flags)) { yfs_fs_remove_file2(&fc, vnode, dentry->d_name.name, &scb[0], &scb[1]); - if (fc.ac.error == 0 && - scb[1].status.abort_code == VNOVNODE) { - set_bit(AFS_VNODE_DELETED, &vnode->flags); - afs_break_callback(vnode); - } - if (fc.ac.error != -ECONNABORTED || fc.ac.abort_code != RXGEN_OPCODE) continue; @@ -1420,11 +1410,11 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); + afs_vnode_commit_status(&fc, vnode, fc.cb_break_2, + &data_version_2, &scb[1]); ret = afs_end_vnode_operation(&fc); - if (ret == 0) - ret = afs_dir_remove_link( - dentry, key, d_version, - (unsigned long)dvnode->status.data_version); + if (ret == 0 && !(scb[1].have_status || scb[1].have_error)) + ret = afs_dir_remove_link(dvnode, dentry, key); if (ret == 0 && test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) 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, * case. */ status->abort_code = abort_code; + scb->have_error = true; return 0; } @@ -127,6 +128,7 @@ static int xdr_decode_AFSFetchStatus(const __be32 **_bp, data_version = (u64)ntohl(xdr->data_version_lo); data_version |= (u64)ntohl(xdr->data_version_hi) << 32; status->data_version = data_version; + scb->have_status = true; *_bp = (const void *)*_bp + sizeof(*xdr); 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 @@ #include #include #include "internal.h" +#include "afs_fs.h" static const struct inode_operations afs_symlink_inode_operations = { .get_link = page_get_link, @@ -271,13 +272,22 @@ void afs_vnode_commit_status(struct afs_fs_cursor *fc, write_seqlock(&vnode->cb_lock); - afs_apply_status(fc, vnode, scb, expected_version); - if (scb->have_cb) - afs_apply_callback(fc, vnode, scb, cb_break); + if (scb->have_error) { + if (scb->status.abort_code == VNOVNODE) { + set_bit(AFS_VNODE_DELETED, &vnode->flags); + clear_nlink(&vnode->vfs_inode); + __afs_break_callback(vnode); + } + } else { + if (scb->have_status) + afs_apply_status(fc, vnode, scb, expected_version); + if (scb->have_cb) + afs_apply_callback(fc, vnode, scb, cb_break); + } write_sequnlock(&vnode->cb_lock); - if (fc->ac.error == 0) + if (fc->ac.error == 0 && scb->have_status) afs_cache_permit(vnode, fc->key, cb_break, scb); } 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; extern const struct dentry_operations afs_fs_dentry_operations; extern void afs_d_release(struct dentry *); -extern int afs_dir_remove_link(struct dentry *, struct key *, unsigned long, unsigned long); /* * 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, if (status->abort_code != 0) { if (status->abort_code == VNOVNODE) status->nlink = 0; + scb->have_error = true; return 0; } @@ -222,6 +223,7 @@ static int xdr_decode_YFSFetchStatus(const __be32 **_bp, status->mtime_server = xdr_to_time(xdr->mtime_server); status->size = xdr_to_u64(xdr->size); status->data_version = xdr_to_u64(xdr->data_version); + scb->have_status = true; *_bp += xdr_size(xdr); return 0; -- cgit v1.2.3 From b8359153252d4465cb74f8de6c50e8c6295cbe2e Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 May 2019 12:23:43 +0100 Subject: afs: Pass pre-fetch server and volume break counts into afs_iget5_set() Pass the server and volume break counts from before the status fetch operation that queried the attributes of a file into afs_iget5_set() so that the new vnode's break counters can be initialised appropriately. This allows detection of a volume or server break that happened whilst we were fetching the status or setting up the vnode. Fixes: c435ee34551e ("afs: Overhaul the callback handling") Signed-off-by: David Howells --- fs/afs/dir.c | 58 ++++++++++++++++++++++++++++++++++++------------------- fs/afs/inode.c | 51 +++++++++++++++++++++++++++--------------------- fs/afs/internal.h | 4 +++- fs/afs/super.c | 14 ++++++++------ 4 files changed, 78 insertions(+), 49 deletions(-) (limited to 'fs') diff --git a/fs/afs/dir.c b/fs/afs/dir.c index d1b3736a3bbd..9e42f6c75747 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -641,7 +641,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct afs_cb_interest *dcbi, *cbi = NULL; struct afs_super_info *as = dir->i_sb->s_fs_info; struct afs_status_cb *scb; - struct afs_iget_data data; + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_server *server; struct afs_vnode *dvnode = AFS_FS_I(dir); @@ -684,9 +684,12 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, goto out; /* Check to see if we already have an inode for the primary fid. */ - data.volume = dvnode->volume; - data.fid = cookie->fids[0]; - inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, afs_iget5_test, &data); + iget_data.fid = cookie->fids[0]; + iget_data.volume = dvnode->volume; + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = 0; + inode = ilookup5(dir->i_sb, cookie->fids[0].vnode, + afs_iget5_test, &iget_data); if (inode) goto out; @@ -713,6 +716,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, fc.ac.error = -ECONNABORTED; break; } + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = fc.cbi->server->cb_s_break; afs_fs_inline_bulk_status(&fc, afs_v2net(dvnode), cookie->fids, @@ -741,6 +746,8 @@ no_inline_bulk_status: inode = ERR_PTR(-ERESTARTSYS); if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { while (afs_select_fileserver(&fc)) { + iget_data.cb_v_break = dvnode->volume->cb_v_break; + iget_data.cb_s_break = fc.cbi->server->cb_s_break; scb = &cookie->statuses[0]; afs_fs_fetch_status(&fc, afs_v2net(dvnode), @@ -775,8 +782,8 @@ success: if (scb->status.abort_code != 0) continue; - ti = afs_iget(dir->i_sb, key, &cookie->fids[i], - scb, cbi, dvnode); + iget_data.fid = cookie->fids[i]; + ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); if (i == 0) { inode = ti; } else { @@ -1112,7 +1119,7 @@ void afs_d_release(struct dentry *dentry) */ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, struct dentry *new_dentry, - struct afs_fid *newfid, + struct afs_iget_data *new_data, struct afs_status_cb *new_scb) { struct afs_vnode *vnode; @@ -1122,7 +1129,7 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, return; inode = afs_iget(fc->vnode->vfs_inode.i_sb, fc->key, - newfid, new_scb, fc->cbi, fc->vnode); + new_data, new_scb, fc->cbi, fc->vnode); if (IS_ERR(inode)) { /* ENOMEM or EINTR at a really inconvenient time - just abandon * the new directory on the server. @@ -1138,15 +1145,23 @@ static void afs_vnode_new_inode(struct afs_fs_cursor *fc, d_instantiate(new_dentry, inode); } +static void afs_prep_for_new_inode(struct afs_fs_cursor *fc, + struct afs_iget_data *iget_data) +{ + iget_data->volume = fc->vnode->volume; + iget_data->cb_v_break = fc->vnode->volume->cb_v_break; + iget_data->cb_s_break = fc->cbi->server->cb_s_break; +} + /* * create a directory on an AFS filesystem */ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { + struct afs_iget_data iget_data; struct afs_status_cb *scb; struct afs_fs_cursor fc; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1172,14 +1187,15 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_create(&fc, dentry->d_name.name, mode, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1189,7 +1205,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (ret == 0 && test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_create); key_put(key); @@ -1439,10 +1455,10 @@ error: static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1472,14 +1488,15 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_create(&fc, dentry->d_name.name, mode, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1488,7 +1505,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, } if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_create); kfree(scb); @@ -1595,10 +1612,10 @@ error: static int afs_symlink(struct inode *dir, struct dentry *dentry, const char *content) { + struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_status_cb *scb; struct afs_vnode *dvnode = AFS_FS_I(dir); - struct afs_fid newfid; struct key *key; int ret; @@ -1631,14 +1648,15 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(dvnode); + afs_prep_for_new_inode(&fc, &iget_data); afs_fs_symlink(&fc, dentry->d_name.name, content, - &scb[0], &newfid, &scb[1]); + &scb[0], &iget_data.fid, &scb[1]); } afs_check_for_remote_deletion(&fc, dvnode); afs_vnode_commit_status(&fc, dvnode, fc.cb_break, &data_version, &scb[0]); - afs_vnode_new_inode(&fc, dentry, &newfid, &scb[1]); + afs_vnode_new_inode(&fc, dentry, &iget_data, &scb[1]); ret = afs_end_vnode_operation(&fc); if (ret < 0) goto error_key; @@ -1647,7 +1665,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, } if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) - afs_edit_dir_add(dvnode, &dentry->d_name, &newfid, + afs_edit_dir_add(dvnode, &dentry->d_name, &iget_data.fid, afs_edit_dir_for_symlink); key_put(key); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index e1a523d2e378..b42d9d09669c 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -347,10 +347,10 @@ int afs_fetch_status(struct afs_vnode *vnode, struct key *key, bool is_new, */ int afs_iget5_test(struct inode *inode, void *opaque) { - struct afs_iget_data *data = opaque; + struct afs_iget_data *iget_data = opaque; struct afs_vnode *vnode = AFS_FS_I(inode); - return memcmp(&vnode->fid, &data->fid, sizeof(data->fid)) == 0; + return memcmp(&vnode->fid, &iget_data->fid, sizeof(iget_data->fid)) == 0; } /* @@ -368,17 +368,19 @@ static int afs_iget5_pseudo_dir_test(struct inode *inode, void *opaque) */ static int afs_iget5_set(struct inode *inode, void *opaque) { - struct afs_iget_data *data = opaque; + struct afs_iget_data *iget_data = opaque; struct afs_vnode *vnode = AFS_FS_I(inode); - vnode->fid = data->fid; - vnode->volume = data->volume; + vnode->fid = iget_data->fid; + vnode->volume = iget_data->volume; + vnode->cb_v_break = iget_data->cb_v_break; + vnode->cb_s_break = iget_data->cb_s_break; /* YFS supports 96-bit vnode IDs, but Linux only supports * 64-bit inode numbers. */ - inode->i_ino = data->fid.vnode; - inode->i_generation = data->fid.unique; + inode->i_ino = iget_data->fid.vnode; + inode->i_generation = iget_data->fid.unique; return 0; } @@ -388,38 +390,42 @@ static int afs_iget5_set(struct inode *inode, void *opaque) */ struct inode *afs_iget_pseudo_dir(struct super_block *sb, bool root) { - struct afs_iget_data data; struct afs_super_info *as; struct afs_vnode *vnode; struct inode *inode; static atomic_t afs_autocell_ino; + struct afs_iget_data iget_data = { + .cb_v_break = 0, + .cb_s_break = 0, + }; + _enter(""); as = sb->s_fs_info; if (as->volume) { - data.volume = as->volume; - data.fid.vid = as->volume->vid; + iget_data.volume = as->volume; + iget_data.fid.vid = as->volume->vid; } if (root) { - data.fid.vnode = 1; - data.fid.unique = 1; + iget_data.fid.vnode = 1; + iget_data.fid.unique = 1; } else { - data.fid.vnode = atomic_inc_return(&afs_autocell_ino); - data.fid.unique = 0; + iget_data.fid.vnode = atomic_inc_return(&afs_autocell_ino); + iget_data.fid.unique = 0; } - inode = iget5_locked(sb, data.fid.vnode, + inode = iget5_locked(sb, iget_data.fid.vnode, afs_iget5_pseudo_dir_test, afs_iget5_set, - &data); + &iget_data); if (!inode) { _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } _debug("GOT INODE %p { ino=%lu, vl=%llx, vn=%llx, u=%x }", - inode, inode->i_ino, data.fid.vid, data.fid.vnode, - data.fid.unique); + inode, inode->i_ino, iget_data.fid.vid, iget_data.fid.vnode, + iget_data.fid.unique); vnode = AFS_FS_I(inode); @@ -490,23 +496,24 @@ static void afs_get_inode_cache(struct afs_vnode *vnode) * inode retrieval */ struct inode *afs_iget(struct super_block *sb, struct key *key, - struct afs_fid *fid, struct afs_status_cb *scb, + struct afs_iget_data *iget_data, + struct afs_status_cb *scb, struct afs_cb_interest *cbi, struct afs_vnode *parent_vnode) { - struct afs_iget_data data = { .fid = *fid }; struct afs_super_info *as; struct afs_vnode *vnode; + struct afs_fid *fid = &iget_data->fid; struct inode *inode; int ret; _enter(",{%llx:%llu.%u},,", fid->vid, fid->vnode, fid->unique); as = sb->s_fs_info; - data.volume = as->volume; + iget_data->volume = as->volume; inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, - &data); + iget_data); if (!inode) { _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f80ca638e70f..2073c1a3ab4b 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -66,6 +66,8 @@ struct afs_fs_context { struct afs_iget_data { struct afs_fid fid; struct afs_volume *volume; /* volume on which resides */ + unsigned int cb_v_break; /* Pre-fetch volume break count */ + unsigned int cb_s_break; /* Pre-fetch server break count */ }; enum afs_call_state { @@ -1023,7 +1025,7 @@ extern int afs_fetch_status(struct afs_vnode *, struct key *, bool, afs_access_t extern int afs_iget5_test(struct inode *, void *); extern struct inode *afs_iget_pseudo_dir(struct super_block *, bool); extern struct inode *afs_iget(struct super_block *, struct key *, - struct afs_fid *, struct afs_status_cb *, + struct afs_iget_data *, struct afs_status_cb *, struct afs_cb_interest *, struct afs_vnode *); extern void afs_zap_data(struct afs_vnode *); diff --git a/fs/afs/super.c b/fs/afs/super.c index f76473ad7bbb..f18911e8d770 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -426,7 +426,7 @@ static int afs_set_super(struct super_block *sb, struct fs_context *fc) static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) { struct afs_super_info *as = AFS_FS_S(sb); - struct afs_fid fid; + struct afs_iget_data iget_data; struct inode *inode = NULL; int ret; @@ -451,11 +451,13 @@ static int afs_fill_super(struct super_block *sb, struct afs_fs_context *ctx) } else { sprintf(sb->s_id, "%llu", as->volume->vid); afs_activate_volume(as->volume); - fid.vid = as->volume->vid; - fid.vnode = 1; - fid.vnode_hi = 0; - fid.unique = 1; - inode = afs_iget(sb, ctx->key, &fid, NULL, NULL, NULL); + iget_data.fid.vid = as->volume->vid; + iget_data.fid.vnode = 1; + iget_data.fid.vnode_hi = 0; + iget_data.fid.unique = 1; + iget_data.cb_v_break = as->volume->cb_v_break; + iget_data.cb_s_break = 0; + inode = afs_iget(sb, ctx->key, &iget_data, NULL, NULL, NULL); } if (IS_ERR(inode)) -- cgit v1.2.3 From 39db9815da489b47b50b8e6e4fc7566a77bd18bf Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 14 May 2019 12:33:10 +0100 Subject: afs: Fix application of the results of a inline bulk status fetch Fix afs_do_lookup() such that when it does an inline bulk status fetch op, it will update inodes that are already extant (something that afs_iget() doesn't do) and to cache permits for each inode created (thereby avoiding a follow up FS.FetchStatus call to determine this). Extant inodes need looking up in advance so that their cb_break counters before and after the operation can be compared. To this end, the inode pointers are cached so that they don't need looking up again after the op. Fixes: 5cf9dd55a0ec ("afs: Prospectively look up extra files when doing a single lookup") Signed-off-by: David Howells --- fs/afs/afs.h | 1 + fs/afs/dir.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/afs/afs.h b/fs/afs/afs.h index a7d3f902a91c..3f4e460c6655 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h @@ -150,6 +150,7 @@ struct afs_file_status { struct afs_status_cb { struct afs_file_status status; struct afs_callback callback; + unsigned int cb_break; /* Pre-op callback break counter */ bool have_status; /* True if status record was retrieved */ bool have_cb; /* True if cb record was retrieved */ bool have_error; /* True if status.abort_code indicates an error */ diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9e42f6c75747..79d93a26759a 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -103,6 +103,7 @@ struct afs_lookup_cookie { bool found; bool one_only; unsigned short nr_fids; + struct inode **inodes; struct afs_status_cb *statuses; struct afs_fid fids[50]; }; @@ -644,8 +645,8 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, struct afs_iget_data iget_data; struct afs_fs_cursor fc; struct afs_server *server; - struct afs_vnode *dvnode = AFS_FS_I(dir); - struct inode *inode = NULL; + struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode; + struct inode *inode = NULL, *ti; int ret, i; _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry); @@ -700,6 +701,27 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry, if (!cookie->statuses) goto out; + cookie->inodes = kcalloc(cookie->nr_fids, sizeof(struct inode *), + GFP_KERNEL); + if (!cookie->inodes) + goto out_s; + + for (i = 1; i < cookie->nr_fids; i++) { + scb = &cookie->statuses[i]; + + /* Find any inodes that already exist and get their + * callback counters. + */ + iget_data.fid = cookie->fids[i]; + ti = ilookup5_nowait(dir->i_sb, iget_data.fid.vnode, + afs_iget5_test, &iget_data); + if (!IS_ERR_OR_NULL(ti)) { + vnode = AFS_FS_I(ti); + scb->cb_break = afs_calc_vnode_cb_break(vnode); + cookie->inodes[i] = ti; + } + } + /* Try FS.InlineBulkStatus first. Abort codes for the individual * lookups contained therein are stored in the reply without aborting * the whole operation. @@ -742,7 +764,6 @@ no_inline_bulk_status: * any of the lookups fails - so, for the moment, revert to * FS.FetchStatus for just the primary fid. */ - cookie->nr_fids = 1; inode = ERR_PTR(-ERESTARTSYS); if (afs_begin_vnode_operation(&fc, dvnode, key, true)) { while (afs_select_fileserver(&fc)) { @@ -764,9 +785,6 @@ no_inline_bulk_status: if (IS_ERR(inode)) goto out_c; - for (i = 0; i < cookie->nr_fids; i++) - cookie->statuses[i].status.abort_code = 0; - success: /* Turn all the files into inodes and save the first one - which is the * one we actually want. @@ -777,13 +795,26 @@ success: for (i = 0; i < cookie->nr_fids; i++) { struct afs_status_cb *scb = &cookie->statuses[i]; - struct inode *ti; + + if (!scb->have_status && !scb->have_error) + continue; + + if (cookie->inodes[i]) { + afs_vnode_commit_status(&fc, AFS_FS_I(cookie->inodes[i]), + scb->cb_break, NULL, scb); + continue; + } if (scb->status.abort_code != 0) continue; iget_data.fid = cookie->fids[i]; ti = afs_iget(dir->i_sb, key, &iget_data, scb, cbi, dvnode); + if (!IS_ERR(ti)) + afs_cache_permit(AFS_FS_I(ti), key, + 0 /* Assume vnode->cb_break is 0 */ + + iget_data.cb_v_break, + scb); if (i == 0) { inode = ti; } else { @@ -794,6 +825,12 @@ success: out_c: afs_put_cb_interest(afs_v2net(dvnode), cbi); + if (cookie->inodes) { + for (i = 0; i < cookie->nr_fids; i++) + iput(cookie->inodes[i]); + kfree(cookie->inodes); + } +out_s: kvfree(cookie->statuses); out: kfree(cookie); -- cgit v1.2.3