diff options
Diffstat (limited to 'fs/afs/fsclient.c')
-rw-r--r-- | fs/afs/fsclient.c | 673 |
1 files changed, 230 insertions, 443 deletions
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 388750d80cab..48298408d6ac 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -60,78 +60,17 @@ static void xdr_dump_bad(const __be32 *bp) } /* - * 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); @@ -144,6 +83,7 @@ static int xdr_decode_AFSFetchStatus(struct afs_call *call, * case. */ status->abort_code = abort_code; + scb->have_error = true; return 0; } @@ -161,44 +101,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 +127,10 @@ 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; + scb->have_status = true; *_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,78 +138,26 @@ 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++); + bp++; /* version */ cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++)); - cb->type = ntohl(*bp++); + bp++; /* type */ + 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 */ static void xdr_decode_AFSVolSync(const __be32 **_bp, @@ -392,7 +246,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->reply[0]; const __be32 *bp; int ret; @@ -400,16 +253,13 @@ 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_AFSVolSync(&bp, call->reply[1]); + xdr_decode_AFSCallBack(&bp, call, call->out_scb); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -428,8 +278,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 +287,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,10 +300,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->expected_version = new_inode ? 1 : vnode->status.data_version; - call->want_reply_time = true; + call->out_scb = scb; + call->out_volsync = volsync; /* marshall the parameters */ bp = call->request; @@ -462,7 +310,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); @@ -476,8 +323,7 @@ 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_read *req = call->read_request; const __be32 *bp; unsigned int size; int ret; @@ -539,7 +385,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; @@ -573,12 +419,14 @@ 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_AFSVolSync(&bp, call->reply[1]); + 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++; @@ -591,7 +439,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; } @@ -601,7 +449,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); @@ -627,7 +475,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; @@ -641,11 +491,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->expected_version = vnode->status.data_version; - call->want_reply_time = true; + call->out_scb = scb; + call->out_volsync = NULL; + call->read_request = req; /* marshall the parameters */ bp = call->request; @@ -659,7 +507,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); @@ -670,7 +517,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; @@ -678,12 +527,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(""); @@ -692,11 +541,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->expected_version = vnode->status.data_version; - call->want_reply_time = true; + call->out_scb = scb; + call->out_volsync = NULL; + call->read_request = req; /* marshall the parameters */ bp = call->request; @@ -708,7 +555,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); @@ -721,28 +567,24 @@ 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]; 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; - 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 = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &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->reply[3], &bp); - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSCallBack(&bp, call, call->out_scb); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -771,24 +613,23 @@ 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 *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; 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(""); @@ -804,19 +645,16 @@ 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->expected_version = current_data_version + 1; - call->want_reply_time = true; + call->out_dir_scb = dvnode_scb; + call->out_fid = newfid; + call->out_scb = new_scb; /* 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,42 +663,38 @@ 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]; 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_dir_scb); 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 +706,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, }; @@ -887,7 +721,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; @@ -896,7 +730,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(""); @@ -911,9 +745,7 @@ 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->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; /* marshall the parameters */ bp = call->request; @@ -941,7 +773,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->reply[0], *vnode = call->reply[1]; const __be32 *bp; int ret; @@ -953,14 +784,13 @@ 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->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -980,7 +810,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; @@ -989,7 +821,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(""); @@ -1002,9 +834,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->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; + call->out_scb = vnode_scb; /* marshall the parameters */ bp = call->request; @@ -1035,7 +866,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 *vnode = call->reply[0]; const __be32 *bp; int ret; @@ -1047,15 +877,14 @@ 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 = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb); if (ret < 0) return ret; - ret = afs_decode_status(call, &bp, &vnode->status, vnode, - &call->expected_version, NULL); + ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb); if (ret < 0) return ret; - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1077,19 +906,19 @@ 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 *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; 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(""); @@ -1107,17 +936,16 @@ 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->expected_version = current_data_version + 1; + call->out_dir_scb = dvnode_scb; + call->out_fid = newfid; + call->out_scb = new_scb; /* 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 +961,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,29 +979,24 @@ 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]; 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; } - /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1190,14 +1013,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; @@ -1208,8 +1031,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(""); @@ -1229,10 +1052,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->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; @@ -1271,7 +1092,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->reply[0]; const __be32 *bp; int ret; @@ -1283,13 +1103,10 @@ 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->reply[X]); */ - - afs_pages_written_back(vnode, call); + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1319,7 +1136,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; @@ -1337,13 +1155,12 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc, call->key = fc->key; call->mapping = mapping; - call->reply[0] = 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; @@ -1377,7 +1194,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; @@ -1386,7 +1204,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); @@ -1407,7 +1225,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, @@ -1417,13 +1235,12 @@ 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->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,7 +1272,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->reply[0]; const __be32 *bp; int ret; @@ -1467,11 +1283,10 @@ 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->reply[X]); */ + xdr_decode_AFSVolSync(&bp, call->out_volsync); _leave(" = 0 [done]"); return 0; @@ -1505,7 +1320,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; @@ -1524,8 +1340,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->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1554,7 +1369,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; @@ -1566,7 +1382,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, @@ -1575,8 +1391,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->expected_version = vnode->status.data_version + 1; + call->out_scb = scb; /* marshall the parameters */ bp = call->request; @@ -1602,7 +1417,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; @@ -1610,10 +1426,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 |