diff options
author | David Howells <dhowells@redhat.com> | 2019-05-09 17:16:10 +0300 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-16 18:25:21 +0300 |
commit | a58823ac458968f9fb3dbf97ee2749a62be12807 (patch) | |
tree | 97a455815d4ff7da8b946704604fe63aa1836b14 /fs/afs/yfsclient.c | |
parent | 4571577f16c82f8db8133b228cdca5fd61042c77 (diff) | |
download | linux-a58823ac458968f9fb3dbf97ee2749a62be12807.tar.xz |
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 <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/yfsclient.c')
-rw-r--r-- | fs/afs/yfsclient.c | 534 |
1 files changed, 149 insertions, 385 deletions
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,41 +247,11 @@ 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 */ static void xdr_decode_YFSVolSync(const __be32 **_bp, @@ -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; @@ -1348,41 +1231,12 @@ int yfs_fs_rename(struct afs_fs_cursor *fc, } /* - * 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; @@ -1456,46 +1310,19 @@ int yfs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, } /* - * 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; @@ -1764,34 +1591,6 @@ int yfs_fs_get_volume_status(struct afs_fs_cursor *fc, } /* - * 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 */ static const struct afs_call_type yfs_RXYFSSetLock = { @@ -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; @@ -1937,42 +1740,12 @@ int yfs_fs_release_lock(struct afs_fs_cursor *fc) } /* - * 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 */ |