12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 208e0e7c8SDavid Howells /* AFS File Server client stubs 31da177e4SLinus Torvalds * 408e0e7c8SDavid Howells * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 51da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds #include <linux/init.h> 95a0e3ad6STejun Heo #include <linux/slab.h> 101da177e4SLinus Torvalds #include <linux/sched.h> 1108e0e7c8SDavid Howells #include <linux/circ_buf.h> 12a01179e6SJeff Layton #include <linux/iversion.h> 135cbf0398SDavid Howells #include <linux/netfs.h> 141da177e4SLinus Torvalds #include "internal.h" 1508e0e7c8SDavid Howells #include "afs_fs.h" 16dd9fbcb8SDavid Howells #include "xdr_fs.h" 17c435ee34SDavid Howells 186db3ac3cSDavid Howells /* 19260a9803SDavid Howells * decode an AFSFid block 20260a9803SDavid Howells */ 21260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 22260a9803SDavid Howells { 23260a9803SDavid Howells const __be32 *bp = *_bp; 24260a9803SDavid Howells 25260a9803SDavid Howells fid->vid = ntohl(*bp++); 26260a9803SDavid Howells fid->vnode = ntohl(*bp++); 27260a9803SDavid Howells fid->unique = ntohl(*bp++); 28260a9803SDavid Howells *_bp = bp; 29260a9803SDavid Howells } 30260a9803SDavid Howells 31260a9803SDavid Howells /* 32888b3384SDavid Howells * Dump a bad file status record. 33888b3384SDavid Howells */ 34888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp) 35888b3384SDavid Howells { 36888b3384SDavid Howells __be32 x[4]; 37888b3384SDavid Howells int i; 38888b3384SDavid Howells 39888b3384SDavid Howells pr_notice("AFS XDR: Bad status record\n"); 40888b3384SDavid Howells for (i = 0; i < 5 * 4 * 4; i += 16) { 41888b3384SDavid Howells memcpy(x, bp, 16); 42888b3384SDavid Howells bp += 4; 43888b3384SDavid Howells pr_notice("%03x: %08x %08x %08x %08x\n", 44888b3384SDavid Howells i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); 45888b3384SDavid Howells } 46888b3384SDavid Howells 47888b3384SDavid Howells memcpy(x, bp, 4); 48888b3384SDavid Howells pr_notice("0x50: %08x\n", ntohl(x[0])); 49888b3384SDavid Howells } 50888b3384SDavid Howells 51888b3384SDavid Howells /* 52dd9fbcb8SDavid Howells * decode an AFSFetchStatus block 53dd9fbcb8SDavid Howells */ 5438355eecSDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 55a58823acSDavid Howells struct afs_call *call, 56a58823acSDavid Howells struct afs_status_cb *scb) 57dd9fbcb8SDavid Howells { 58dd9fbcb8SDavid Howells const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; 59a58823acSDavid Howells struct afs_file_status *status = &scb->status; 60684b0f68SDavid Howells bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); 61dd9fbcb8SDavid Howells u64 data_version, size; 62dd9fbcb8SDavid Howells u32 type, abort_code; 63dd9fbcb8SDavid Howells 64684b0f68SDavid Howells abort_code = ntohl(xdr->abort_code); 65684b0f68SDavid Howells 66dd9fbcb8SDavid Howells if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { 67684b0f68SDavid Howells if (xdr->if_version == htonl(0) && 68684b0f68SDavid Howells abort_code != 0 && 69684b0f68SDavid Howells inline_error) { 70684b0f68SDavid Howells /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus 71684b0f68SDavid Howells * whereby it doesn't set the interface version in the error 72684b0f68SDavid Howells * case. 73684b0f68SDavid Howells */ 74684b0f68SDavid Howells status->abort_code = abort_code; 75a38a7558SDavid Howells scb->have_error = true; 7638355eecSDavid Howells goto advance; 77684b0f68SDavid Howells } 78684b0f68SDavid Howells 79dd9fbcb8SDavid Howells pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); 80dd9fbcb8SDavid Howells goto bad; 81dd9fbcb8SDavid Howells } 82dd9fbcb8SDavid Howells 83684b0f68SDavid Howells if (abort_code != 0 && inline_error) { 84684b0f68SDavid Howells status->abort_code = abort_code; 853e0d9892SDavid Howells scb->have_error = true; 8638355eecSDavid Howells goto advance; 87684b0f68SDavid Howells } 88684b0f68SDavid Howells 89dd9fbcb8SDavid Howells type = ntohl(xdr->type); 90dd9fbcb8SDavid Howells switch (type) { 91dd9fbcb8SDavid Howells case AFS_FTYPE_FILE: 92dd9fbcb8SDavid Howells case AFS_FTYPE_DIR: 93dd9fbcb8SDavid Howells case AFS_FTYPE_SYMLINK: 94dd9fbcb8SDavid Howells status->type = type; 95dd9fbcb8SDavid Howells break; 96dd9fbcb8SDavid Howells default: 97dd9fbcb8SDavid Howells goto bad; 98dd9fbcb8SDavid Howells } 99dd9fbcb8SDavid Howells 100a58823acSDavid Howells status->nlink = ntohl(xdr->nlink); 101a58823acSDavid Howells status->author = ntohl(xdr->author); 102a58823acSDavid Howells status->owner = ntohl(xdr->owner); 103a58823acSDavid Howells status->caller_access = ntohl(xdr->caller_access); /* Ticket dependent */ 104a58823acSDavid Howells status->anon_access = ntohl(xdr->anon_access); 105a58823acSDavid Howells status->mode = ntohl(xdr->mode) & S_IALLUGO; 106a58823acSDavid Howells status->group = ntohl(xdr->group); 107a58823acSDavid Howells status->lock_count = ntohl(xdr->lock_count); 108dd9fbcb8SDavid Howells 109d4936803SDavid Howells status->mtime_client.tv_sec = ntohl(xdr->mtime_client); 110d4936803SDavid Howells status->mtime_client.tv_nsec = 0; 111d4936803SDavid Howells status->mtime_server.tv_sec = ntohl(xdr->mtime_server); 112d4936803SDavid Howells status->mtime_server.tv_nsec = 0; 113dd9fbcb8SDavid Howells 114dd9fbcb8SDavid Howells size = (u64)ntohl(xdr->size_lo); 115dd9fbcb8SDavid Howells size |= (u64)ntohl(xdr->size_hi) << 32; 116dd9fbcb8SDavid Howells status->size = size; 117dd9fbcb8SDavid Howells 118dd9fbcb8SDavid Howells data_version = (u64)ntohl(xdr->data_version_lo); 119dd9fbcb8SDavid Howells data_version |= (u64)ntohl(xdr->data_version_hi) << 32; 120dd9fbcb8SDavid Howells status->data_version = data_version; 121a38a7558SDavid Howells scb->have_status = true; 122c72057b5SDavid Howells advance: 123dd9fbcb8SDavid Howells *_bp = (const void *)*_bp + sizeof(*xdr); 12438355eecSDavid Howells return; 125dd9fbcb8SDavid Howells 126dd9fbcb8SDavid Howells bad: 127dd9fbcb8SDavid Howells xdr_dump_bad(*_bp); 1287126ead9SDavid Howells afs_protocol_error(call, afs_eproto_bad_status); 129c72057b5SDavid Howells goto advance; 130c875c76aSDavid Howells } 131c875c76aSDavid Howells 13278107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry) 13378107055SDavid Howells { 13478107055SDavid Howells return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry; 13578107055SDavid Howells } 13678107055SDavid Howells 137a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, 138a58823acSDavid Howells struct afs_call *call, 139a58823acSDavid Howells struct afs_status_cb *scb) 14078107055SDavid Howells { 141a58823acSDavid Howells struct afs_callback *cb = &scb->callback; 14278107055SDavid Howells const __be32 *bp = *_bp; 14378107055SDavid Howells 1447c712458SDavid Howells bp++; /* version */ 14578107055SDavid Howells cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++)); 1467c712458SDavid Howells bp++; /* type */ 147a58823acSDavid Howells scb->have_cb = true; 14878107055SDavid Howells *_bp = bp; 14978107055SDavid Howells } 15078107055SDavid Howells 1511da177e4SLinus Torvalds /* 15208e0e7c8SDavid Howells * decode an AFSVolSync block 1531da177e4SLinus Torvalds */ 15408e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 15508e0e7c8SDavid Howells struct afs_volsync *volsync) 1561da177e4SLinus Torvalds { 15708e0e7c8SDavid Howells const __be32 *bp = *_bp; 15830062bd1SDavid Howells u32 creation; 1591da177e4SLinus Torvalds 16030062bd1SDavid Howells creation = ntohl(*bp++); 16108e0e7c8SDavid Howells bp++; /* spare2 */ 16208e0e7c8SDavid Howells bp++; /* spare3 */ 16308e0e7c8SDavid Howells bp++; /* spare4 */ 16408e0e7c8SDavid Howells bp++; /* spare5 */ 16508e0e7c8SDavid Howells bp++; /* spare6 */ 16608e0e7c8SDavid Howells *_bp = bp; 16730062bd1SDavid Howells 16830062bd1SDavid Howells if (volsync) 16930062bd1SDavid Howells volsync->creation = creation; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 17208e0e7c8SDavid Howells /* 17331143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 17431143d5dSDavid Howells */ 17531143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 17631143d5dSDavid Howells { 17731143d5dSDavid Howells __be32 *bp = *_bp; 17831143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 17931143d5dSDavid Howells 18031143d5dSDavid Howells mask = 0; 18131143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 18231143d5dSDavid Howells mask |= AFS_SET_MTIME; 18331143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 18431143d5dSDavid Howells } 18531143d5dSDavid Howells 18631143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 18731143d5dSDavid Howells mask |= AFS_SET_OWNER; 188a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 18931143d5dSDavid Howells } 19031143d5dSDavid Howells 19131143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 19231143d5dSDavid Howells mask |= AFS_SET_GROUP; 193a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 19431143d5dSDavid Howells } 19531143d5dSDavid Howells 19631143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 19731143d5dSDavid Howells mask |= AFS_SET_MODE; 19831143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 19931143d5dSDavid Howells } 20031143d5dSDavid Howells 20131143d5dSDavid Howells *bp++ = htonl(mask); 20231143d5dSDavid Howells *bp++ = htonl(mtime); 20331143d5dSDavid Howells *bp++ = htonl(owner); 20431143d5dSDavid Howells *bp++ = htonl(group); 20531143d5dSDavid Howells *bp++ = htonl(mode); 20631143d5dSDavid Howells *bp++ = 0; /* segment size */ 20731143d5dSDavid Howells *_bp = bp; 20831143d5dSDavid Howells } 20931143d5dSDavid Howells 21031143d5dSDavid Howells /* 21145222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 21245222b9eSDavid Howells */ 21345222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 21445222b9eSDavid Howells struct afs_volume_status *vs) 21545222b9eSDavid Howells { 21645222b9eSDavid Howells const __be32 *bp = *_bp; 21745222b9eSDavid Howells 21845222b9eSDavid Howells vs->vid = ntohl(*bp++); 21945222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 22045222b9eSDavid Howells vs->online = ntohl(*bp++); 22145222b9eSDavid Howells vs->in_service = ntohl(*bp++); 22245222b9eSDavid Howells vs->blessed = ntohl(*bp++); 22345222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 22445222b9eSDavid Howells vs->type = ntohl(*bp++); 22545222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 22645222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 22745222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 22845222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 22945222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 23030062bd1SDavid Howells vs->vol_copy_date = 0; 23130062bd1SDavid Howells vs->vol_backup_date = 0; 23245222b9eSDavid Howells *_bp = bp; 23345222b9eSDavid Howells } 23445222b9eSDavid Howells 23545222b9eSDavid Howells /* 23608e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 23708e0e7c8SDavid Howells */ 238e49c7b2fSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call) 23908e0e7c8SDavid Howells { 240e49c7b2fSDavid Howells struct afs_operation *op = call->op; 241e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; 24208e0e7c8SDavid Howells const __be32 *bp; 243372ee163SDavid Howells int ret; 2441da177e4SLinus Torvalds 245d001648eSDavid Howells ret = afs_transfer_reply(call); 246372ee163SDavid Howells if (ret < 0) 247372ee163SDavid Howells return ret; 2481da177e4SLinus Torvalds 24908e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 25008e0e7c8SDavid Howells bp = call->buffer; 251e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 252e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 253e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 2541da177e4SLinus Torvalds 25508e0e7c8SDavid Howells _leave(" = 0 [done]"); 25608e0e7c8SDavid Howells return 0; 257ec26815aSDavid Howells } 25808e0e7c8SDavid Howells 25908e0e7c8SDavid Howells /* 26008e0e7c8SDavid Howells * FS.FetchStatus operation type 26108e0e7c8SDavid Howells */ 262e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 263e49c7b2fSDavid Howells .name = "FS.FetchStatus", 264025db80cSDavid Howells .op = afs_FS_FetchStatus, 265e49c7b2fSDavid Howells .deliver = afs_deliver_fs_fetch_status, 26608e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 26708e0e7c8SDavid Howells }; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds /* 2701da177e4SLinus Torvalds * fetch the status information for a file 2711da177e4SLinus Torvalds */ 272e49c7b2fSDavid Howells void afs_fs_fetch_status(struct afs_operation *op) 2731da177e4SLinus Torvalds { 274e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; 27508e0e7c8SDavid Howells struct afs_call *call; 2761da177e4SLinus Torvalds __be32 *bp; 2771da177e4SLinus Torvalds 2783b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 279e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2801da177e4SLinus Torvalds 281e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchStatus, 2825cf9dd55SDavid Howells 16, (21 + 3 + 6) * 4); 283e49c7b2fSDavid Howells if (!call) 284e49c7b2fSDavid Howells return afs_op_nomem(op); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds /* marshall the parameters */ 28708e0e7c8SDavid Howells bp = call->request; 2881da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 289e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 290e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 291e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2921da177e4SLinus Torvalds 293e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 294e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 295ec26815aSDavid Howells } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* 29808e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 2991da177e4SLinus Torvalds */ 300d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call) 3011da177e4SLinus Torvalds { 302e49c7b2fSDavid Howells struct afs_operation *op = call->op; 303e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 304e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 30508e0e7c8SDavid Howells const __be32 *bp; 3061da177e4SLinus Torvalds int ret; 3071da177e4SLinus Torvalds 308f105da1aSDavid Howells _enter("{%u,%zu,%zu/%llu}", 309f105da1aSDavid Howells call->unmarshall, call->iov_len, iov_iter_count(call->iter), 310f105da1aSDavid Howells req->actual_len); 3111da177e4SLinus Torvalds 31208e0e7c8SDavid Howells switch (call->unmarshall) { 31308e0e7c8SDavid Howells case 0: 314196ee9cdSDavid Howells req->actual_len = 0; 31508e0e7c8SDavid Howells call->unmarshall++; 31612bdcf33SDavid Howells if (call->operation_ID == FSFETCHDATA64) { 31712bdcf33SDavid Howells afs_extract_to_tmp64(call); 31812bdcf33SDavid Howells } else { 31912bdcf33SDavid Howells call->tmp_u = htonl(0); 32012bdcf33SDavid Howells afs_extract_to_tmp(call); 321b9b1f8d5SDavid Howells } 322df561f66SGustavo A. R. Silva fallthrough; 3231da177e4SLinus Torvalds 324c4508464SDavid Howells /* Extract the returned data length into 325c4508464SDavid Howells * ->actual_len. This may indicate more or less data than was 326c4508464SDavid Howells * requested will be returned. 327c4508464SDavid Howells */ 32812bdcf33SDavid Howells case 1: 32908e0e7c8SDavid Howells _debug("extract data length"); 33012bdcf33SDavid Howells ret = afs_extract_data(call, true); 331372ee163SDavid Howells if (ret < 0) 332372ee163SDavid Howells return ret; 3331da177e4SLinus Torvalds 33412bdcf33SDavid Howells req->actual_len = be64_to_cpu(call->tmp64); 335196ee9cdSDavid Howells _debug("DATA length: %llu", req->actual_len); 336c4508464SDavid Howells 337c4508464SDavid Howells if (req->actual_len == 0) 338196ee9cdSDavid Howells goto no_more_data; 33912bdcf33SDavid Howells 340c4508464SDavid Howells call->iter = req->iter; 341c4508464SDavid Howells call->iov_len = min(req->actual_len, req->len); 34208e0e7c8SDavid Howells call->unmarshall++; 343df561f66SGustavo A. R. Silva fallthrough; 344196ee9cdSDavid Howells 34529881608SGustavo A. R. Silva /* extract the returned data */ 34612bdcf33SDavid Howells case 2: 34712bdcf33SDavid Howells _debug("extract data %zu/%llu", 348c4508464SDavid Howells iov_iter_count(call->iter), req->actual_len); 349196ee9cdSDavid Howells 35012bdcf33SDavid Howells ret = afs_extract_data(call, true); 351372ee163SDavid Howells if (ret < 0) 352372ee163SDavid Howells return ret; 35312bdcf33SDavid Howells 354c4508464SDavid Howells call->iter = &call->def_iter; 35512bdcf33SDavid Howells if (req->actual_len <= req->len) 3566db3ac3cSDavid Howells goto no_more_data; 3576db3ac3cSDavid Howells 3586db3ac3cSDavid Howells /* Discard any excess data the server gave us */ 35923a28913SDavid Howells afs_extract_discard(call, req->actual_len - req->len); 36012bdcf33SDavid Howells call->unmarshall = 3; 361df561f66SGustavo A. R. Silva fallthrough; 36229881608SGustavo A. R. Silva 36312bdcf33SDavid Howells case 3: 36412bdcf33SDavid Howells _debug("extract discard %zu/%llu", 365fc276122SDavid Howells iov_iter_count(call->iter), req->actual_len - req->len); 3666db3ac3cSDavid Howells 36712bdcf33SDavid Howells ret = afs_extract_data(call, true); 3686db3ac3cSDavid Howells if (ret < 0) 3696db3ac3cSDavid Howells return ret; 3701da177e4SLinus Torvalds 371196ee9cdSDavid Howells no_more_data: 37212bdcf33SDavid Howells call->unmarshall = 4; 37312bdcf33SDavid Howells afs_extract_to_buf(call, (21 + 3 + 6) * 4); 374df561f66SGustavo A. R. Silva fallthrough; 37508e0e7c8SDavid Howells 37629881608SGustavo A. R. Silva /* extract the metadata */ 37712bdcf33SDavid Howells case 4: 37812bdcf33SDavid Howells ret = afs_extract_data(call, false); 379372ee163SDavid Howells if (ret < 0) 380372ee163SDavid Howells return ret; 3811da177e4SLinus Torvalds 38208e0e7c8SDavid Howells bp = call->buffer; 383e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 384e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 385e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 3861da177e4SLinus Torvalds 387e49c7b2fSDavid Howells req->data_version = vp->scb.status.data_version; 388e49c7b2fSDavid Howells req->file_size = vp->scb.status.size; 389a58823acSDavid Howells 39008e0e7c8SDavid Howells call->unmarshall++; 391*b2db6c35SGustavo A. R. Silva fallthrough; 3921da177e4SLinus Torvalds 39312bdcf33SDavid Howells case 5: 3941da177e4SLinus Torvalds break; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 39708e0e7c8SDavid Howells _leave(" = 0 [done]"); 39808e0e7c8SDavid Howells return 0; 399ec26815aSDavid Howells } 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* 40208e0e7c8SDavid Howells * FS.FetchData operation type 4031da177e4SLinus Torvalds */ 40408e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 40500d3b7a4SDavid Howells .name = "FS.FetchData", 406025db80cSDavid Howells .op = afs_FS_FetchData, 40708e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 408e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 40908e0e7c8SDavid Howells }; 41008e0e7c8SDavid Howells 411b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 412b9b1f8d5SDavid Howells .name = "FS.FetchData64", 413025db80cSDavid Howells .op = afs_FS_FetchData64, 414b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 415e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 416b9b1f8d5SDavid Howells }; 417b9b1f8d5SDavid Howells 418b9b1f8d5SDavid Howells /* 419b9b1f8d5SDavid Howells * fetch data from a very large file 420b9b1f8d5SDavid Howells */ 421e49c7b2fSDavid Howells static void afs_fs_fetch_data64(struct afs_operation *op) 422b9b1f8d5SDavid Howells { 423e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 424e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 425b9b1f8d5SDavid Howells struct afs_call *call; 426b9b1f8d5SDavid Howells __be32 *bp; 427b9b1f8d5SDavid Howells 428b9b1f8d5SDavid Howells _enter(""); 429b9b1f8d5SDavid Howells 430e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 431b9b1f8d5SDavid Howells if (!call) 432e49c7b2fSDavid Howells return afs_op_nomem(op); 433b9b1f8d5SDavid Howells 434b9b1f8d5SDavid Howells /* marshall the parameters */ 435b9b1f8d5SDavid Howells bp = call->request; 436b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 437e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 438e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 439e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 440196ee9cdSDavid Howells bp[4] = htonl(upper_32_bits(req->pos)); 441196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->pos)); 442b9b1f8d5SDavid Howells bp[6] = 0; 443196ee9cdSDavid Howells bp[7] = htonl(lower_32_bits(req->len)); 444b9b1f8d5SDavid Howells 445e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 446e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 447b9b1f8d5SDavid Howells } 448b9b1f8d5SDavid Howells 44908e0e7c8SDavid Howells /* 45008e0e7c8SDavid Howells * fetch data from a file 45108e0e7c8SDavid Howells */ 452e49c7b2fSDavid Howells void afs_fs_fetch_data(struct afs_operation *op) 4531da177e4SLinus Torvalds { 454e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 45508e0e7c8SDavid Howells struct afs_call *call; 456e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 45708e0e7c8SDavid Howells __be32 *bp; 4581da177e4SLinus Torvalds 459196ee9cdSDavid Howells if (upper_32_bits(req->pos) || 460196ee9cdSDavid Howells upper_32_bits(req->len) || 461196ee9cdSDavid Howells upper_32_bits(req->pos + req->len)) 462e49c7b2fSDavid Howells return afs_fs_fetch_data64(op); 463b9b1f8d5SDavid Howells 46408e0e7c8SDavid Howells _enter(""); 4651da177e4SLinus Torvalds 466e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 46708e0e7c8SDavid Howells if (!call) 468e49c7b2fSDavid Howells return afs_op_nomem(op); 4691da177e4SLinus Torvalds 470c4508464SDavid Howells req->call_debug_id = call->debug_id; 471c4508464SDavid Howells 4721da177e4SLinus Torvalds /* marshall the parameters */ 47308e0e7c8SDavid Howells bp = call->request; 47408e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 475e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 476e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 477e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 478196ee9cdSDavid Howells bp[4] = htonl(lower_32_bits(req->pos)); 479196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->len)); 4801da177e4SLinus Torvalds 481e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 482e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 48308e0e7c8SDavid Howells } 484260a9803SDavid Howells 485260a9803SDavid Howells /* 486260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 487260a9803SDavid Howells */ 488d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call) 489260a9803SDavid Howells { 490e49c7b2fSDavid Howells struct afs_operation *op = call->op; 491e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 492e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 493260a9803SDavid Howells const __be32 *bp; 494372ee163SDavid Howells int ret; 495260a9803SDavid Howells 496d001648eSDavid Howells ret = afs_transfer_reply(call); 497372ee163SDavid Howells if (ret < 0) 498372ee163SDavid Howells return ret; 499260a9803SDavid Howells 500260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 501260a9803SDavid Howells bp = call->buffer; 502e49c7b2fSDavid Howells xdr_decode_AFSFid(&bp, &op->file[1].fid); 503e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 504e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 505e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 506e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 507260a9803SDavid Howells 508260a9803SDavid Howells _leave(" = 0 [done]"); 509260a9803SDavid Howells return 0; 510260a9803SDavid Howells } 511260a9803SDavid Howells 512260a9803SDavid Howells /* 513260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 514260a9803SDavid Howells */ 515025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = { 516025db80cSDavid Howells .name = "FS.CreateFile", 517025db80cSDavid Howells .op = afs_FS_CreateFile, 518025db80cSDavid Howells .deliver = afs_deliver_fs_create_vnode, 519025db80cSDavid Howells .destructor = afs_flat_call_destructor, 520025db80cSDavid Howells }; 521025db80cSDavid Howells 522e49c7b2fSDavid Howells /* 523e49c7b2fSDavid Howells * Create a file. 524e49c7b2fSDavid Howells */ 525e49c7b2fSDavid Howells void afs_fs_create_file(struct afs_operation *op) 526e49c7b2fSDavid Howells { 527e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 528e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 529e49c7b2fSDavid Howells struct afs_call *call; 530e49c7b2fSDavid Howells size_t namesz, reqsz, padsz; 531e49c7b2fSDavid Howells __be32 *bp; 532e49c7b2fSDavid Howells 533e49c7b2fSDavid Howells _enter(""); 534e49c7b2fSDavid Howells 535e49c7b2fSDavid Howells namesz = name->len; 536e49c7b2fSDavid Howells padsz = (4 - (namesz & 3)) & 3; 537e49c7b2fSDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 538e49c7b2fSDavid Howells 539e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, 540e49c7b2fSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 541e49c7b2fSDavid Howells if (!call) 542e49c7b2fSDavid Howells return afs_op_nomem(op); 543e49c7b2fSDavid Howells 544e49c7b2fSDavid Howells /* marshall the parameters */ 545e49c7b2fSDavid Howells bp = call->request; 546e49c7b2fSDavid Howells *bp++ = htonl(FSCREATEFILE); 547e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 548e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 549e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 550e49c7b2fSDavid Howells *bp++ = htonl(namesz); 551e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 552e49c7b2fSDavid Howells bp = (void *) bp + namesz; 553e49c7b2fSDavid Howells if (padsz > 0) { 554e49c7b2fSDavid Howells memset(bp, 0, padsz); 555e49c7b2fSDavid Howells bp = (void *) bp + padsz; 556e49c7b2fSDavid Howells } 557e49c7b2fSDavid Howells *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 558e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 559e49c7b2fSDavid Howells *bp++ = 0; /* owner */ 560e49c7b2fSDavid Howells *bp++ = 0; /* group */ 561e49c7b2fSDavid Howells *bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */ 562e49c7b2fSDavid Howells *bp++ = 0; /* segment size */ 563e49c7b2fSDavid Howells 564e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 565e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 566e49c7b2fSDavid Howells } 567e49c7b2fSDavid Howells 568025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = { 569025db80cSDavid Howells .name = "FS.MakeDir", 570025db80cSDavid Howells .op = afs_FS_MakeDir, 571260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 572260a9803SDavid Howells .destructor = afs_flat_call_destructor, 573260a9803SDavid Howells }; 574260a9803SDavid Howells 575260a9803SDavid Howells /* 576e49c7b2fSDavid Howells * Create a new directory 577260a9803SDavid Howells */ 578e49c7b2fSDavid Howells void afs_fs_make_dir(struct afs_operation *op) 579260a9803SDavid Howells { 580e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 581e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 582260a9803SDavid Howells struct afs_call *call; 583260a9803SDavid Howells size_t namesz, reqsz, padsz; 584260a9803SDavid Howells __be32 *bp; 585260a9803SDavid Howells 586260a9803SDavid Howells _enter(""); 587260a9803SDavid Howells 588e49c7b2fSDavid Howells namesz = name->len; 589260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 590260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 591260a9803SDavid Howells 592e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir, 593025db80cSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 594260a9803SDavid Howells if (!call) 595e49c7b2fSDavid Howells return afs_op_nomem(op); 596260a9803SDavid Howells 597260a9803SDavid Howells /* marshall the parameters */ 598260a9803SDavid Howells bp = call->request; 599e49c7b2fSDavid Howells *bp++ = htonl(FSMAKEDIR); 600e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 601e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 602e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 603260a9803SDavid Howells *bp++ = htonl(namesz); 604e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 605260a9803SDavid Howells bp = (void *) bp + namesz; 606260a9803SDavid Howells if (padsz > 0) { 607260a9803SDavid Howells memset(bp, 0, padsz); 608260a9803SDavid Howells bp = (void *) bp + padsz; 609260a9803SDavid Howells } 610ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 611e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 612260a9803SDavid Howells *bp++ = 0; /* owner */ 613260a9803SDavid Howells *bp++ = 0; /* group */ 614e49c7b2fSDavid Howells *bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */ 615260a9803SDavid Howells *bp++ = 0; /* segment size */ 616260a9803SDavid Howells 617e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 618e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 619260a9803SDavid Howells } 620260a9803SDavid Howells 621260a9803SDavid Howells /* 622e49c7b2fSDavid Howells * Deliver reply data to any operation that returns status and volume sync. 623260a9803SDavid Howells */ 624e49c7b2fSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call) 625260a9803SDavid Howells { 626e49c7b2fSDavid Howells struct afs_operation *op = call->op; 627e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 628260a9803SDavid Howells const __be32 *bp; 629372ee163SDavid Howells int ret; 630260a9803SDavid Howells 631d001648eSDavid Howells ret = afs_transfer_reply(call); 632372ee163SDavid Howells if (ret < 0) 633372ee163SDavid Howells return ret; 634260a9803SDavid Howells 635260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 636260a9803SDavid Howells bp = call->buffer; 637e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 638e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 639260a9803SDavid Howells 640260a9803SDavid Howells _leave(" = 0 [done]"); 641260a9803SDavid Howells return 0; 642260a9803SDavid Howells } 643260a9803SDavid Howells 644260a9803SDavid Howells /* 645e49c7b2fSDavid Howells * FS.RemoveFile operation type 646260a9803SDavid Howells */ 647025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = { 648025db80cSDavid Howells .name = "FS.RemoveFile", 649025db80cSDavid Howells .op = afs_FS_RemoveFile, 650e49c7b2fSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 651260a9803SDavid Howells .destructor = afs_flat_call_destructor, 652260a9803SDavid Howells }; 653260a9803SDavid Howells 654260a9803SDavid Howells /* 655e49c7b2fSDavid Howells * Remove a file. 656260a9803SDavid Howells */ 657e49c7b2fSDavid Howells void afs_fs_remove_file(struct afs_operation *op) 658260a9803SDavid Howells { 659e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 660e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 661260a9803SDavid Howells struct afs_call *call; 662260a9803SDavid Howells size_t namesz, reqsz, padsz; 663260a9803SDavid Howells __be32 *bp; 664260a9803SDavid Howells 665260a9803SDavid Howells _enter(""); 666260a9803SDavid Howells 667e49c7b2fSDavid Howells namesz = name->len; 668260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 669260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 670260a9803SDavid Howells 671e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile, 672025db80cSDavid Howells reqsz, (21 + 6) * 4); 673260a9803SDavid Howells if (!call) 674e49c7b2fSDavid Howells return afs_op_nomem(op); 675260a9803SDavid Howells 676260a9803SDavid Howells /* marshall the parameters */ 677260a9803SDavid Howells bp = call->request; 678e49c7b2fSDavid Howells *bp++ = htonl(FSREMOVEFILE); 679e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 680e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 681e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 682260a9803SDavid Howells *bp++ = htonl(namesz); 683e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 684260a9803SDavid Howells bp = (void *) bp + namesz; 685260a9803SDavid Howells if (padsz > 0) { 686260a9803SDavid Howells memset(bp, 0, padsz); 687260a9803SDavid Howells bp = (void *) bp + padsz; 688260a9803SDavid Howells } 689260a9803SDavid Howells 690e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 691e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 692e49c7b2fSDavid Howells } 693e49c7b2fSDavid Howells 694e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = { 695e49c7b2fSDavid Howells .name = "FS.RemoveDir", 696e49c7b2fSDavid Howells .op = afs_FS_RemoveDir, 697e49c7b2fSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 698e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 699e49c7b2fSDavid Howells }; 700e49c7b2fSDavid Howells 701e49c7b2fSDavid Howells /* 702e49c7b2fSDavid Howells * Remove a directory. 703e49c7b2fSDavid Howells */ 704e49c7b2fSDavid Howells void afs_fs_remove_dir(struct afs_operation *op) 705e49c7b2fSDavid Howells { 706e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 707e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 708e49c7b2fSDavid Howells struct afs_call *call; 709e49c7b2fSDavid Howells size_t namesz, reqsz, padsz; 710e49c7b2fSDavid Howells __be32 *bp; 711e49c7b2fSDavid Howells 712e49c7b2fSDavid Howells _enter(""); 713e49c7b2fSDavid Howells 714e49c7b2fSDavid Howells namesz = name->len; 715e49c7b2fSDavid Howells padsz = (4 - (namesz & 3)) & 3; 716e49c7b2fSDavid Howells reqsz = (5 * 4) + namesz + padsz; 717e49c7b2fSDavid Howells 718e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir, 719e49c7b2fSDavid Howells reqsz, (21 + 6) * 4); 720e49c7b2fSDavid Howells if (!call) 721e49c7b2fSDavid Howells return afs_op_nomem(op); 722e49c7b2fSDavid Howells 723e49c7b2fSDavid Howells /* marshall the parameters */ 724e49c7b2fSDavid Howells bp = call->request; 725e49c7b2fSDavid Howells *bp++ = htonl(FSREMOVEDIR); 726e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 727e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 728e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 729e49c7b2fSDavid Howells *bp++ = htonl(namesz); 730e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 731e49c7b2fSDavid Howells bp = (void *) bp + namesz; 732e49c7b2fSDavid Howells if (padsz > 0) { 733e49c7b2fSDavid Howells memset(bp, 0, padsz); 734e49c7b2fSDavid Howells bp = (void *) bp + padsz; 735e49c7b2fSDavid Howells } 736e49c7b2fSDavid Howells 737e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 738e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 739260a9803SDavid Howells } 740260a9803SDavid Howells 741260a9803SDavid Howells /* 742260a9803SDavid Howells * deliver reply data to an FS.Link 743260a9803SDavid Howells */ 744d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call) 745260a9803SDavid Howells { 746e49c7b2fSDavid Howells struct afs_operation *op = call->op; 747e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 748e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 749260a9803SDavid Howells const __be32 *bp; 750372ee163SDavid Howells int ret; 751260a9803SDavid Howells 752d001648eSDavid Howells _enter("{%u}", call->unmarshall); 753260a9803SDavid Howells 754d001648eSDavid Howells ret = afs_transfer_reply(call); 755372ee163SDavid Howells if (ret < 0) 756372ee163SDavid Howells return ret; 757260a9803SDavid Howells 758260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 759260a9803SDavid Howells bp = call->buffer; 760e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 761e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 762e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 763260a9803SDavid Howells 764260a9803SDavid Howells _leave(" = 0 [done]"); 765260a9803SDavid Howells return 0; 766260a9803SDavid Howells } 767260a9803SDavid Howells 768260a9803SDavid Howells /* 769260a9803SDavid Howells * FS.Link operation type 770260a9803SDavid Howells */ 771260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 772260a9803SDavid Howells .name = "FS.Link", 773025db80cSDavid Howells .op = afs_FS_Link, 774260a9803SDavid Howells .deliver = afs_deliver_fs_link, 775260a9803SDavid Howells .destructor = afs_flat_call_destructor, 776260a9803SDavid Howells }; 777260a9803SDavid Howells 778260a9803SDavid Howells /* 779260a9803SDavid Howells * make a hard link 780260a9803SDavid Howells */ 781e49c7b2fSDavid Howells void afs_fs_link(struct afs_operation *op) 782260a9803SDavid Howells { 783e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 784e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 785e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 786260a9803SDavid Howells struct afs_call *call; 787260a9803SDavid Howells size_t namesz, reqsz, padsz; 788260a9803SDavid Howells __be32 *bp; 789260a9803SDavid Howells 790260a9803SDavid Howells _enter(""); 791260a9803SDavid Howells 792e49c7b2fSDavid Howells namesz = name->len; 793260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 794260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 795260a9803SDavid Howells 796e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 797260a9803SDavid Howells if (!call) 798e49c7b2fSDavid Howells return afs_op_nomem(op); 799260a9803SDavid Howells 800260a9803SDavid Howells /* marshall the parameters */ 801260a9803SDavid Howells bp = call->request; 802260a9803SDavid Howells *bp++ = htonl(FSLINK); 803e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 804e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 805e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 806260a9803SDavid Howells *bp++ = htonl(namesz); 807e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 808260a9803SDavid Howells bp = (void *) bp + namesz; 809260a9803SDavid Howells if (padsz > 0) { 810260a9803SDavid Howells memset(bp, 0, padsz); 811260a9803SDavid Howells bp = (void *) bp + padsz; 812260a9803SDavid Howells } 813e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 814e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 815e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 816260a9803SDavid Howells 817e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &vp->fid, name); 818e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 819260a9803SDavid Howells } 820260a9803SDavid Howells 821260a9803SDavid Howells /* 822260a9803SDavid Howells * deliver reply data to an FS.Symlink 823260a9803SDavid Howells */ 824d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call) 825260a9803SDavid Howells { 826e49c7b2fSDavid Howells struct afs_operation *op = call->op; 827e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 828e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 829260a9803SDavid Howells const __be32 *bp; 830372ee163SDavid Howells int ret; 831260a9803SDavid Howells 832d001648eSDavid Howells _enter("{%u}", call->unmarshall); 833260a9803SDavid Howells 834d001648eSDavid Howells ret = afs_transfer_reply(call); 835372ee163SDavid Howells if (ret < 0) 836372ee163SDavid Howells return ret; 837260a9803SDavid Howells 838260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 839260a9803SDavid Howells bp = call->buffer; 840e49c7b2fSDavid Howells xdr_decode_AFSFid(&bp, &vp->fid); 841e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 842e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 843e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 844260a9803SDavid Howells 845260a9803SDavid Howells _leave(" = 0 [done]"); 846260a9803SDavid Howells return 0; 847260a9803SDavid Howells } 848260a9803SDavid Howells 849260a9803SDavid Howells /* 850260a9803SDavid Howells * FS.Symlink operation type 851260a9803SDavid Howells */ 852260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 853260a9803SDavid Howells .name = "FS.Symlink", 854025db80cSDavid Howells .op = afs_FS_Symlink, 855260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 856260a9803SDavid Howells .destructor = afs_flat_call_destructor, 857260a9803SDavid Howells }; 858260a9803SDavid Howells 859260a9803SDavid Howells /* 860260a9803SDavid Howells * create a symbolic link 861260a9803SDavid Howells */ 862e49c7b2fSDavid Howells void afs_fs_symlink(struct afs_operation *op) 863260a9803SDavid Howells { 864e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 865e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 866260a9803SDavid Howells struct afs_call *call; 867260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 868260a9803SDavid Howells __be32 *bp; 869260a9803SDavid Howells 870260a9803SDavid Howells _enter(""); 871260a9803SDavid Howells 872e49c7b2fSDavid Howells namesz = name->len; 873260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 874260a9803SDavid Howells 875e49c7b2fSDavid Howells c_namesz = strlen(op->create.symlink); 876260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 877260a9803SDavid Howells 878260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 879260a9803SDavid Howells 880e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz, 881260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 882260a9803SDavid Howells if (!call) 883e49c7b2fSDavid Howells return afs_op_nomem(op); 884260a9803SDavid Howells 885260a9803SDavid Howells /* marshall the parameters */ 886260a9803SDavid Howells bp = call->request; 887260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 888e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 889e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 890e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 891260a9803SDavid Howells *bp++ = htonl(namesz); 892e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 893260a9803SDavid Howells bp = (void *) bp + namesz; 894260a9803SDavid Howells if (padsz > 0) { 895260a9803SDavid Howells memset(bp, 0, padsz); 896260a9803SDavid Howells bp = (void *) bp + padsz; 897260a9803SDavid Howells } 898260a9803SDavid Howells *bp++ = htonl(c_namesz); 899e49c7b2fSDavid Howells memcpy(bp, op->create.symlink, c_namesz); 900260a9803SDavid Howells bp = (void *) bp + c_namesz; 901260a9803SDavid Howells if (c_padsz > 0) { 902260a9803SDavid Howells memset(bp, 0, c_padsz); 903260a9803SDavid Howells bp = (void *) bp + c_padsz; 904260a9803SDavid Howells } 905ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 906e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 907260a9803SDavid Howells *bp++ = 0; /* owner */ 908260a9803SDavid Howells *bp++ = 0; /* group */ 909260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 910260a9803SDavid Howells *bp++ = 0; /* segment size */ 911260a9803SDavid Howells 912e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 913e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 914260a9803SDavid Howells } 915260a9803SDavid Howells 916260a9803SDavid Howells /* 917260a9803SDavid Howells * deliver reply data to an FS.Rename 918260a9803SDavid Howells */ 919d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call) 920260a9803SDavid Howells { 921e49c7b2fSDavid Howells struct afs_operation *op = call->op; 922e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 923e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 924260a9803SDavid Howells const __be32 *bp; 925372ee163SDavid Howells int ret; 926260a9803SDavid Howells 927d001648eSDavid Howells ret = afs_transfer_reply(call); 928372ee163SDavid Howells if (ret < 0) 929372ee163SDavid Howells return ret; 930260a9803SDavid Howells 93138355eecSDavid Howells bp = call->buffer; 932b98f0ec9SDavid Howells /* If the two dirs are the same, we have two copies of the same status 933b98f0ec9SDavid Howells * report, so we just decode it twice. 934b98f0ec9SDavid Howells */ 935e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb); 936e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb); 937e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 938260a9803SDavid Howells 939260a9803SDavid Howells _leave(" = 0 [done]"); 940260a9803SDavid Howells return 0; 941260a9803SDavid Howells } 942260a9803SDavid Howells 943260a9803SDavid Howells /* 944260a9803SDavid Howells * FS.Rename operation type 945260a9803SDavid Howells */ 946260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 947260a9803SDavid Howells .name = "FS.Rename", 948025db80cSDavid Howells .op = afs_FS_Rename, 949260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 950260a9803SDavid Howells .destructor = afs_flat_call_destructor, 951260a9803SDavid Howells }; 952260a9803SDavid Howells 953260a9803SDavid Howells /* 954a58823acSDavid Howells * Rename/move a file or directory. 955260a9803SDavid Howells */ 956e49c7b2fSDavid Howells void afs_fs_rename(struct afs_operation *op) 957260a9803SDavid Howells { 958e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 959e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 960e49c7b2fSDavid Howells const struct qstr *orig_name = &op->dentry->d_name; 961e49c7b2fSDavid Howells const struct qstr *new_name = &op->dentry_2->d_name; 962260a9803SDavid Howells struct afs_call *call; 963260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 964260a9803SDavid Howells __be32 *bp; 965260a9803SDavid Howells 966260a9803SDavid Howells _enter(""); 967260a9803SDavid Howells 968e49c7b2fSDavid Howells o_namesz = orig_name->len; 969260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 970260a9803SDavid Howells 971e49c7b2fSDavid Howells n_namesz = new_name->len; 972260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 973260a9803SDavid Howells 974260a9803SDavid Howells reqsz = (4 * 4) + 975260a9803SDavid Howells 4 + o_namesz + o_padsz + 976260a9803SDavid Howells (3 * 4) + 977260a9803SDavid Howells 4 + n_namesz + n_padsz; 978260a9803SDavid Howells 979e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 980260a9803SDavid Howells if (!call) 981e49c7b2fSDavid Howells return afs_op_nomem(op); 982260a9803SDavid Howells 983260a9803SDavid Howells /* marshall the parameters */ 984260a9803SDavid Howells bp = call->request; 985260a9803SDavid Howells *bp++ = htonl(FSRENAME); 986e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.vid); 987e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.vnode); 988e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.unique); 989260a9803SDavid Howells *bp++ = htonl(o_namesz); 990e49c7b2fSDavid Howells memcpy(bp, orig_name->name, o_namesz); 991260a9803SDavid Howells bp = (void *) bp + o_namesz; 992260a9803SDavid Howells if (o_padsz > 0) { 993260a9803SDavid Howells memset(bp, 0, o_padsz); 994260a9803SDavid Howells bp = (void *) bp + o_padsz; 995260a9803SDavid Howells } 996260a9803SDavid Howells 997e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.vid); 998e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.vnode); 999e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.unique); 1000260a9803SDavid Howells *bp++ = htonl(n_namesz); 1001e49c7b2fSDavid Howells memcpy(bp, new_name->name, n_namesz); 1002260a9803SDavid Howells bp = (void *) bp + n_namesz; 1003260a9803SDavid Howells if (n_padsz > 0) { 1004260a9803SDavid Howells memset(bp, 0, n_padsz); 1005260a9803SDavid Howells bp = (void *) bp + n_padsz; 1006260a9803SDavid Howells } 1007260a9803SDavid Howells 1008e49c7b2fSDavid Howells trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name); 1009e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1010260a9803SDavid Howells } 101131143d5dSDavid Howells 101231143d5dSDavid Howells /* 1013e49c7b2fSDavid Howells * Deliver reply data to FS.StoreData or FS.StoreStatus 101431143d5dSDavid Howells */ 1015d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call) 101631143d5dSDavid Howells { 1017e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1018e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 101931143d5dSDavid Howells const __be32 *bp; 1020372ee163SDavid Howells int ret; 102131143d5dSDavid Howells 1022d001648eSDavid Howells _enter(""); 102331143d5dSDavid Howells 1024d001648eSDavid Howells ret = afs_transfer_reply(call); 1025372ee163SDavid Howells if (ret < 0) 1026372ee163SDavid Howells return ret; 102731143d5dSDavid Howells 102831143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 102931143d5dSDavid Howells bp = call->buffer; 1030e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 1031e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 103231143d5dSDavid Howells 103331143d5dSDavid Howells _leave(" = 0 [done]"); 103431143d5dSDavid Howells return 0; 103531143d5dSDavid Howells } 103631143d5dSDavid Howells 103731143d5dSDavid Howells /* 103831143d5dSDavid Howells * FS.StoreData operation type 103931143d5dSDavid Howells */ 104031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 104131143d5dSDavid Howells .name = "FS.StoreData", 1042025db80cSDavid Howells .op = afs_FS_StoreData, 104331143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 104431143d5dSDavid Howells .destructor = afs_flat_call_destructor, 104531143d5dSDavid Howells }; 104631143d5dSDavid Howells 1047b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1048b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1049025db80cSDavid Howells .op = afs_FS_StoreData64, 1050b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1051b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1052b9b1f8d5SDavid Howells }; 1053b9b1f8d5SDavid Howells 1054b9b1f8d5SDavid Howells /* 1055b9b1f8d5SDavid Howells * store a set of pages to a very large file 1056b9b1f8d5SDavid Howells */ 1057bd80d8a8SDavid Howells static void afs_fs_store_data64(struct afs_operation *op) 1058b9b1f8d5SDavid Howells { 1059e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1060b9b1f8d5SDavid Howells struct afs_call *call; 1061b9b1f8d5SDavid Howells __be32 *bp; 1062b9b1f8d5SDavid Howells 10633b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1064e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 1065b9b1f8d5SDavid Howells 1066e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64, 1067b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1068b9b1f8d5SDavid Howells (21 + 6) * 4); 1069b9b1f8d5SDavid Howells if (!call) 1070e49c7b2fSDavid Howells return afs_op_nomem(op); 1071b9b1f8d5SDavid Howells 1072bd80d8a8SDavid Howells call->write_iter = op->store.write_iter; 1073b9b1f8d5SDavid Howells 1074b9b1f8d5SDavid Howells /* marshall the parameters */ 1075b9b1f8d5SDavid Howells bp = call->request; 1076b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1077e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1078e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1079e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1080b9b1f8d5SDavid Howells 1081ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1082e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 1083b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1084b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1085b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1086b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1087b9b1f8d5SDavid Howells 1088bd80d8a8SDavid Howells *bp++ = htonl(upper_32_bits(op->store.pos)); 1089bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.pos)); 1090bd80d8a8SDavid Howells *bp++ = htonl(upper_32_bits(op->store.size)); 1091bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.size)); 1092bd80d8a8SDavid Howells *bp++ = htonl(upper_32_bits(op->store.i_size)); 1093bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.i_size)); 1094b9b1f8d5SDavid Howells 1095e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1096e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1097b9b1f8d5SDavid Howells } 1098b9b1f8d5SDavid Howells 109931143d5dSDavid Howells /* 1100bd80d8a8SDavid Howells * Write data to a file on the server. 110131143d5dSDavid Howells */ 1102e49c7b2fSDavid Howells void afs_fs_store_data(struct afs_operation *op) 110331143d5dSDavid Howells { 1104e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 110531143d5dSDavid Howells struct afs_call *call; 110631143d5dSDavid Howells __be32 *bp; 110731143d5dSDavid Howells 11083b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1109e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 111031143d5dSDavid Howells 111131143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 1112bd80d8a8SDavid Howells (unsigned long long)op->store.size, 1113bd80d8a8SDavid Howells (unsigned long long)op->store.pos, 1114bd80d8a8SDavid Howells (unsigned long long)op->store.i_size); 111531143d5dSDavid Howells 1116bd80d8a8SDavid Howells if (upper_32_bits(op->store.pos) || 1117bd80d8a8SDavid Howells upper_32_bits(op->store.size) || 1118bd80d8a8SDavid Howells upper_32_bits(op->store.i_size)) 1119bd80d8a8SDavid Howells return afs_fs_store_data64(op); 112031143d5dSDavid Howells 1121e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData, 112231143d5dSDavid Howells (4 + 6 + 3) * 4, 112331143d5dSDavid Howells (21 + 6) * 4); 112431143d5dSDavid Howells if (!call) 1125e49c7b2fSDavid Howells return afs_op_nomem(op); 112631143d5dSDavid Howells 1127bd80d8a8SDavid Howells call->write_iter = op->store.write_iter; 112831143d5dSDavid Howells 112931143d5dSDavid Howells /* marshall the parameters */ 113031143d5dSDavid Howells bp = call->request; 113131143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 1132e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1133e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1134e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 113531143d5dSDavid Howells 1136ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1137e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 113831143d5dSDavid Howells *bp++ = 0; /* owner */ 113931143d5dSDavid Howells *bp++ = 0; /* group */ 114031143d5dSDavid Howells *bp++ = 0; /* unix mode */ 114131143d5dSDavid Howells *bp++ = 0; /* segment size */ 114231143d5dSDavid Howells 1143bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.pos)); 1144bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.size)); 1145bd80d8a8SDavid Howells *bp++ = htonl(lower_32_bits(op->store.i_size)); 114631143d5dSDavid Howells 1147e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1148e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 114931143d5dSDavid Howells } 115031143d5dSDavid Howells 115131143d5dSDavid Howells /* 115231143d5dSDavid Howells * FS.StoreStatus operation type 115331143d5dSDavid Howells */ 115431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 115531143d5dSDavid Howells .name = "FS.StoreStatus", 1156025db80cSDavid Howells .op = afs_FS_StoreStatus, 1157e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 115831143d5dSDavid Howells .destructor = afs_flat_call_destructor, 115931143d5dSDavid Howells }; 116031143d5dSDavid Howells 116131143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 116231143d5dSDavid Howells .name = "FS.StoreData", 1163025db80cSDavid Howells .op = afs_FS_StoreData, 1164e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 116531143d5dSDavid Howells .destructor = afs_flat_call_destructor, 116631143d5dSDavid Howells }; 116731143d5dSDavid Howells 1168b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1169b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1170025db80cSDavid Howells .op = afs_FS_StoreData64, 1171e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 1172b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1173b9b1f8d5SDavid Howells }; 1174b9b1f8d5SDavid Howells 1175b9b1f8d5SDavid Howells /* 1176b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1177b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1178b9b1f8d5SDavid Howells */ 1179e49c7b2fSDavid Howells static void afs_fs_setattr_size64(struct afs_operation *op) 1180b9b1f8d5SDavid Howells { 1181e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1182b9b1f8d5SDavid Howells struct afs_call *call; 1183e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 1184b9b1f8d5SDavid Howells __be32 *bp; 1185b9b1f8d5SDavid Howells 11863b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1187e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 1188b9b1f8d5SDavid Howells 1189b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1190b9b1f8d5SDavid Howells 1191e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status, 1192b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1193b9b1f8d5SDavid Howells (21 + 6) * 4); 1194b9b1f8d5SDavid Howells if (!call) 1195e49c7b2fSDavid Howells return afs_op_nomem(op); 1196b9b1f8d5SDavid Howells 1197b9b1f8d5SDavid Howells /* marshall the parameters */ 1198b9b1f8d5SDavid Howells bp = call->request; 1199b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1200e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1201e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1202e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1203b9b1f8d5SDavid Howells 1204b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1205b9b1f8d5SDavid Howells 1206e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(attr->ia_size)); /* position of start of write */ 1207e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(attr->ia_size)); 1208b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1209b9b1f8d5SDavid Howells *bp++ = 0; 1210e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(attr->ia_size)); /* new file length */ 1211e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(attr->ia_size)); 1212b9b1f8d5SDavid Howells 1213e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1214e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1215b9b1f8d5SDavid Howells } 1216b9b1f8d5SDavid Howells 121731143d5dSDavid Howells /* 121831143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 121931143d5dSDavid Howells * so as to alter the file size also 122031143d5dSDavid Howells */ 1221e49c7b2fSDavid Howells static void afs_fs_setattr_size(struct afs_operation *op) 122231143d5dSDavid Howells { 1223e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 122431143d5dSDavid Howells struct afs_call *call; 1225e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 122631143d5dSDavid Howells __be32 *bp; 122731143d5dSDavid Howells 12283b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1229e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 123031143d5dSDavid Howells 123131143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1232e49c7b2fSDavid Howells if (upper_32_bits(attr->ia_size)) 1233e49c7b2fSDavid Howells return afs_fs_setattr_size64(op); 123431143d5dSDavid Howells 1235e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status, 123631143d5dSDavid Howells (4 + 6 + 3) * 4, 123731143d5dSDavid Howells (21 + 6) * 4); 123831143d5dSDavid Howells if (!call) 1239e49c7b2fSDavid Howells return afs_op_nomem(op); 124031143d5dSDavid Howells 124131143d5dSDavid Howells /* marshall the parameters */ 124231143d5dSDavid Howells bp = call->request; 124331143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 1244e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1245e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1246e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 124731143d5dSDavid Howells 124831143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 124931143d5dSDavid Howells 12508c7ae38dSDavid Howells *bp++ = htonl(attr->ia_size); /* position of start of write */ 125131143d5dSDavid Howells *bp++ = 0; /* size of write */ 125231143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 125331143d5dSDavid Howells 1254e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1255e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 125631143d5dSDavid Howells } 125731143d5dSDavid Howells 125831143d5dSDavid Howells /* 125931143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 126031143d5dSDavid Howells * size, and FS.StoreStatus otherwise 126131143d5dSDavid Howells */ 1262e49c7b2fSDavid Howells void afs_fs_setattr(struct afs_operation *op) 126331143d5dSDavid Howells { 1264e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 126531143d5dSDavid Howells struct afs_call *call; 1266e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 126731143d5dSDavid Howells __be32 *bp; 126831143d5dSDavid Howells 126931143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 1270e49c7b2fSDavid Howells return afs_fs_setattr_size(op); 127131143d5dSDavid Howells 12723b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1273e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 127431143d5dSDavid Howells 1275e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus, 127631143d5dSDavid Howells (4 + 6) * 4, 127731143d5dSDavid Howells (21 + 6) * 4); 127831143d5dSDavid Howells if (!call) 1279e49c7b2fSDavid Howells return afs_op_nomem(op); 128031143d5dSDavid Howells 128131143d5dSDavid Howells /* marshall the parameters */ 128231143d5dSDavid Howells bp = call->request; 128331143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 1284e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1285e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1286e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 128731143d5dSDavid Howells 1288e49c7b2fSDavid Howells xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr); 128931143d5dSDavid Howells 1290e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1291e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 129231143d5dSDavid Howells } 129345222b9eSDavid Howells 129445222b9eSDavid Howells /* 129545222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 129645222b9eSDavid Howells */ 1297d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call) 129845222b9eSDavid Howells { 1299e49c7b2fSDavid Howells struct afs_operation *op = call->op; 130045222b9eSDavid Howells const __be32 *bp; 130145222b9eSDavid Howells char *p; 130212bdcf33SDavid Howells u32 size; 130345222b9eSDavid Howells int ret; 130445222b9eSDavid Howells 1305d001648eSDavid Howells _enter("{%u}", call->unmarshall); 130645222b9eSDavid Howells 130745222b9eSDavid Howells switch (call->unmarshall) { 130845222b9eSDavid Howells case 0: 130945222b9eSDavid Howells call->unmarshall++; 131012bdcf33SDavid Howells afs_extract_to_buf(call, 12 * 4); 1311df561f66SGustavo A. R. Silva fallthrough; 131245222b9eSDavid Howells 131329881608SGustavo A. R. Silva /* extract the returned status record */ 131445222b9eSDavid Howells case 1: 131545222b9eSDavid Howells _debug("extract status"); 131612bdcf33SDavid Howells ret = afs_extract_data(call, true); 1317372ee163SDavid Howells if (ret < 0) 1318372ee163SDavid Howells return ret; 131945222b9eSDavid Howells 132045222b9eSDavid Howells bp = call->buffer; 1321e49c7b2fSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs); 132245222b9eSDavid Howells call->unmarshall++; 132312bdcf33SDavid Howells afs_extract_to_tmp(call); 1324df561f66SGustavo A. R. Silva fallthrough; 132545222b9eSDavid Howells 132629881608SGustavo A. R. Silva /* extract the volume name length */ 132745222b9eSDavid Howells case 2: 132812bdcf33SDavid Howells ret = afs_extract_data(call, true); 1329372ee163SDavid Howells if (ret < 0) 1330372ee163SDavid Howells return ret; 133145222b9eSDavid Howells 133245222b9eSDavid Howells call->count = ntohl(call->tmp); 133345222b9eSDavid Howells _debug("volname length: %u", call->count); 133445222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 13357126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_volname_len); 133612bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1337ffba718eSDavid Howells afs_extract_to_buf(call, size); 133845222b9eSDavid Howells call->unmarshall++; 1339df561f66SGustavo A. R. Silva fallthrough; 134045222b9eSDavid Howells 134129881608SGustavo A. R. Silva /* extract the volume name */ 134245222b9eSDavid Howells case 3: 134345222b9eSDavid Howells _debug("extract volname"); 134412bdcf33SDavid Howells ret = afs_extract_data(call, true); 1345372ee163SDavid Howells if (ret < 0) 1346372ee163SDavid Howells return ret; 134745222b9eSDavid Howells 1348ffba718eSDavid Howells p = call->buffer; 134945222b9eSDavid Howells p[call->count] = 0; 135045222b9eSDavid Howells _debug("volname '%s'", p); 135112bdcf33SDavid Howells afs_extract_to_tmp(call); 135245222b9eSDavid Howells call->unmarshall++; 1353df561f66SGustavo A. R. Silva fallthrough; 135445222b9eSDavid Howells 135529881608SGustavo A. R. Silva /* extract the offline message length */ 135612bdcf33SDavid Howells case 4: 135712bdcf33SDavid Howells ret = afs_extract_data(call, true); 1358372ee163SDavid Howells if (ret < 0) 1359372ee163SDavid Howells return ret; 136045222b9eSDavid Howells 136145222b9eSDavid Howells call->count = ntohl(call->tmp); 136245222b9eSDavid Howells _debug("offline msg length: %u", call->count); 136345222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 13647126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_offline_msg_len); 136512bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1366ffba718eSDavid Howells afs_extract_to_buf(call, size); 136745222b9eSDavid Howells call->unmarshall++; 1368df561f66SGustavo A. R. Silva fallthrough; 136945222b9eSDavid Howells 137029881608SGustavo A. R. Silva /* extract the offline message */ 137112bdcf33SDavid Howells case 5: 137245222b9eSDavid Howells _debug("extract offline"); 137312bdcf33SDavid Howells ret = afs_extract_data(call, true); 1374372ee163SDavid Howells if (ret < 0) 1375372ee163SDavid Howells return ret; 137645222b9eSDavid Howells 1377ffba718eSDavid Howells p = call->buffer; 137845222b9eSDavid Howells p[call->count] = 0; 137945222b9eSDavid Howells _debug("offline '%s'", p); 138045222b9eSDavid Howells 138112bdcf33SDavid Howells afs_extract_to_tmp(call); 138245222b9eSDavid Howells call->unmarshall++; 1383df561f66SGustavo A. R. Silva fallthrough; 138445222b9eSDavid Howells 138529881608SGustavo A. R. Silva /* extract the message of the day length */ 138612bdcf33SDavid Howells case 6: 138712bdcf33SDavid Howells ret = afs_extract_data(call, true); 1388372ee163SDavid Howells if (ret < 0) 1389372ee163SDavid Howells return ret; 139045222b9eSDavid Howells 139145222b9eSDavid Howells call->count = ntohl(call->tmp); 139245222b9eSDavid Howells _debug("motd length: %u", call->count); 139345222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 13947126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_motd_len); 139512bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1396ffba718eSDavid Howells afs_extract_to_buf(call, size); 139745222b9eSDavid Howells call->unmarshall++; 1398df561f66SGustavo A. R. Silva fallthrough; 139945222b9eSDavid Howells 140029881608SGustavo A. R. Silva /* extract the message of the day */ 140112bdcf33SDavid Howells case 7: 140245222b9eSDavid Howells _debug("extract motd"); 140312bdcf33SDavid Howells ret = afs_extract_data(call, false); 1404372ee163SDavid Howells if (ret < 0) 1405372ee163SDavid Howells return ret; 140645222b9eSDavid Howells 1407ffba718eSDavid Howells p = call->buffer; 140845222b9eSDavid Howells p[call->count] = 0; 140945222b9eSDavid Howells _debug("motd '%s'", p); 141045222b9eSDavid Howells 141145222b9eSDavid Howells call->unmarshall++; 1412*b2db6c35SGustavo A. R. Silva fallthrough; 141345222b9eSDavid Howells 141412bdcf33SDavid Howells case 8: 141545222b9eSDavid Howells break; 141645222b9eSDavid Howells } 141745222b9eSDavid Howells 141845222b9eSDavid Howells _leave(" = 0 [done]"); 141945222b9eSDavid Howells return 0; 142045222b9eSDavid Howells } 142145222b9eSDavid Howells 142245222b9eSDavid Howells /* 142345222b9eSDavid Howells * FS.GetVolumeStatus operation type 142445222b9eSDavid Howells */ 142545222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 142645222b9eSDavid Howells .name = "FS.GetVolumeStatus", 1427025db80cSDavid Howells .op = afs_FS_GetVolumeStatus, 142845222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 1429ffba718eSDavid Howells .destructor = afs_flat_call_destructor, 143045222b9eSDavid Howells }; 143145222b9eSDavid Howells 143245222b9eSDavid Howells /* 143345222b9eSDavid Howells * fetch the status of a volume 143445222b9eSDavid Howells */ 1435e49c7b2fSDavid Howells void afs_fs_get_volume_status(struct afs_operation *op) 143645222b9eSDavid Howells { 1437e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 143845222b9eSDavid Howells struct afs_call *call; 143945222b9eSDavid Howells __be32 *bp; 144045222b9eSDavid Howells 144145222b9eSDavid Howells _enter(""); 144245222b9eSDavid Howells 1443e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4, 1444ffba718eSDavid Howells max(12 * 4, AFSOPAQUEMAX + 1)); 1445ffba718eSDavid Howells if (!call) 1446e49c7b2fSDavid Howells return afs_op_nomem(op); 144745222b9eSDavid Howells 144845222b9eSDavid Howells /* marshall the parameters */ 144945222b9eSDavid Howells bp = call->request; 145045222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 1451e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 145245222b9eSDavid Howells 1453e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1454e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 145545222b9eSDavid Howells } 1456e8d6c554SDavid Howells 1457e8d6c554SDavid Howells /* 1458e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1459e8d6c554SDavid Howells */ 1460d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call) 1461e8d6c554SDavid Howells { 1462e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1463e8d6c554SDavid Howells const __be32 *bp; 1464372ee163SDavid Howells int ret; 1465e8d6c554SDavid Howells 1466d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1467e8d6c554SDavid Howells 1468d001648eSDavid Howells ret = afs_transfer_reply(call); 1469372ee163SDavid Howells if (ret < 0) 1470372ee163SDavid Howells return ret; 1471e8d6c554SDavid Howells 1472e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1473e8d6c554SDavid Howells bp = call->buffer; 1474e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 1475e8d6c554SDavid Howells 1476e8d6c554SDavid Howells _leave(" = 0 [done]"); 1477e8d6c554SDavid Howells return 0; 1478e8d6c554SDavid Howells } 1479e8d6c554SDavid Howells 1480e8d6c554SDavid Howells /* 1481e8d6c554SDavid Howells * FS.SetLock operation type 1482e8d6c554SDavid Howells */ 1483e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1484e8d6c554SDavid Howells .name = "FS.SetLock", 1485025db80cSDavid Howells .op = afs_FS_SetLock, 1486e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1487a690f60aSDavid Howells .done = afs_lock_op_done, 1488e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1489e8d6c554SDavid Howells }; 1490e8d6c554SDavid Howells 1491e8d6c554SDavid Howells /* 1492e8d6c554SDavid Howells * FS.ExtendLock operation type 1493e8d6c554SDavid Howells */ 1494e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1495e8d6c554SDavid Howells .name = "FS.ExtendLock", 1496025db80cSDavid Howells .op = afs_FS_ExtendLock, 1497e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1498a690f60aSDavid Howells .done = afs_lock_op_done, 1499e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1500e8d6c554SDavid Howells }; 1501e8d6c554SDavid Howells 1502e8d6c554SDavid Howells /* 1503e8d6c554SDavid Howells * FS.ReleaseLock operation type 1504e8d6c554SDavid Howells */ 1505e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1506e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1507025db80cSDavid Howells .op = afs_FS_ReleaseLock, 1508e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1509e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1510e8d6c554SDavid Howells }; 1511e8d6c554SDavid Howells 1512e8d6c554SDavid Howells /* 1513d2ddc776SDavid Howells * Set a lock on a file 1514e8d6c554SDavid Howells */ 1515e49c7b2fSDavid Howells void afs_fs_set_lock(struct afs_operation *op) 1516e8d6c554SDavid Howells { 1517e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1518e8d6c554SDavid Howells struct afs_call *call; 1519e8d6c554SDavid Howells __be32 *bp; 1520e8d6c554SDavid Howells 1521e8d6c554SDavid Howells _enter(""); 1522e8d6c554SDavid Howells 1523e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4); 1524e8d6c554SDavid Howells if (!call) 1525e49c7b2fSDavid Howells return afs_op_nomem(op); 1526e8d6c554SDavid Howells 1527e8d6c554SDavid Howells /* marshall the parameters */ 1528e8d6c554SDavid Howells bp = call->request; 1529e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1530e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1531e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1532e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1533e49c7b2fSDavid Howells *bp++ = htonl(op->lock.type); 1534e8d6c554SDavid Howells 1535e49c7b2fSDavid Howells trace_afs_make_fs_calli(call, &vp->fid, op->lock.type); 1536e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1537e8d6c554SDavid Howells } 1538e8d6c554SDavid Howells 1539e8d6c554SDavid Howells /* 1540e8d6c554SDavid Howells * extend a lock on a file 1541e8d6c554SDavid Howells */ 1542e49c7b2fSDavid Howells void afs_fs_extend_lock(struct afs_operation *op) 1543e8d6c554SDavid Howells { 1544e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1545e8d6c554SDavid Howells struct afs_call *call; 1546e8d6c554SDavid Howells __be32 *bp; 1547e8d6c554SDavid Howells 1548e8d6c554SDavid Howells _enter(""); 1549e8d6c554SDavid Howells 1550e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); 1551e8d6c554SDavid Howells if (!call) 1552e49c7b2fSDavid Howells return afs_op_nomem(op); 1553e8d6c554SDavid Howells 1554e8d6c554SDavid Howells /* marshall the parameters */ 1555e8d6c554SDavid Howells bp = call->request; 1556e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1557e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1558e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1559e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1560e8d6c554SDavid Howells 1561e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1562e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1563e8d6c554SDavid Howells } 1564e8d6c554SDavid Howells 1565e8d6c554SDavid Howells /* 1566e8d6c554SDavid Howells * release a lock on a file 1567e8d6c554SDavid Howells */ 1568e49c7b2fSDavid Howells void afs_fs_release_lock(struct afs_operation *op) 1569e8d6c554SDavid Howells { 1570e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1571e8d6c554SDavid Howells struct afs_call *call; 1572e8d6c554SDavid Howells __be32 *bp; 1573e8d6c554SDavid Howells 1574e8d6c554SDavid Howells _enter(""); 1575e8d6c554SDavid Howells 1576e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1577e8d6c554SDavid Howells if (!call) 1578e49c7b2fSDavid Howells return afs_op_nomem(op); 1579e8d6c554SDavid Howells 1580e8d6c554SDavid Howells /* marshall the parameters */ 1581e8d6c554SDavid Howells bp = call->request; 1582e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1583e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1584e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1585e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1586e8d6c554SDavid Howells 1587e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1588e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1589c435ee34SDavid Howells } 1590c435ee34SDavid Howells 1591c435ee34SDavid Howells /* 1592c435ee34SDavid Howells * Deliver reply data to an FS.GiveUpAllCallBacks operation. 1593c435ee34SDavid Howells */ 1594c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call) 1595c435ee34SDavid Howells { 1596c435ee34SDavid Howells return afs_transfer_reply(call); 1597c435ee34SDavid Howells } 1598c435ee34SDavid Howells 1599c435ee34SDavid Howells /* 1600c435ee34SDavid Howells * FS.GiveUpAllCallBacks operation type 1601c435ee34SDavid Howells */ 1602c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = { 1603c435ee34SDavid Howells .name = "FS.GiveUpAllCallBacks", 1604025db80cSDavid Howells .op = afs_FS_GiveUpAllCallBacks, 1605c435ee34SDavid Howells .deliver = afs_deliver_fs_give_up_all_callbacks, 1606c435ee34SDavid Howells .destructor = afs_flat_call_destructor, 1607c435ee34SDavid Howells }; 1608c435ee34SDavid Howells 1609c435ee34SDavid Howells /* 1610c435ee34SDavid Howells * Flush all the callbacks we have on a server. 1611c435ee34SDavid Howells */ 1612d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net, 1613d2ddc776SDavid Howells struct afs_server *server, 16148b2a464cSDavid Howells struct afs_addr_cursor *ac, 1615d2ddc776SDavid Howells struct key *key) 1616c435ee34SDavid Howells { 1617c435ee34SDavid Howells struct afs_call *call; 1618c435ee34SDavid Howells __be32 *bp; 1619c435ee34SDavid Howells 1620c435ee34SDavid Howells _enter(""); 1621c435ee34SDavid Howells 1622d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0); 1623c435ee34SDavid Howells if (!call) 1624c435ee34SDavid Howells return -ENOMEM; 1625c435ee34SDavid Howells 1626c435ee34SDavid Howells call->key = key; 1627c435ee34SDavid Howells 1628c435ee34SDavid Howells /* marshall the parameters */ 1629c435ee34SDavid Howells bp = call->request; 1630c435ee34SDavid Howells *bp++ = htonl(FSGIVEUPALLCALLBACKS); 1631c435ee34SDavid Howells 1632977e5f8eSDavid Howells call->server = afs_use_server(server, afs_server_trace_give_up_cb); 16330b9bf381SDavid Howells afs_make_call(ac, call, GFP_NOFS); 16340b9bf381SDavid Howells return afs_wait_for_call_to_complete(call, ac); 1635d2ddc776SDavid Howells } 1636d2ddc776SDavid Howells 1637d2ddc776SDavid Howells /* 1638d2ddc776SDavid Howells * Deliver reply data to an FS.GetCapabilities operation. 1639d2ddc776SDavid Howells */ 1640d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call) 1641d2ddc776SDavid Howells { 1642d2ddc776SDavid Howells u32 count; 1643d2ddc776SDavid Howells int ret; 1644d2ddc776SDavid Howells 1645fc276122SDavid Howells _enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter)); 1646d2ddc776SDavid Howells 1647d2ddc776SDavid Howells switch (call->unmarshall) { 1648d2ddc776SDavid Howells case 0: 164912bdcf33SDavid Howells afs_extract_to_tmp(call); 1650d2ddc776SDavid Howells call->unmarshall++; 1651df561f66SGustavo A. R. Silva fallthrough; 1652d2ddc776SDavid Howells 165329881608SGustavo A. R. Silva /* Extract the capabilities word count */ 1654d2ddc776SDavid Howells case 1: 165512bdcf33SDavid Howells ret = afs_extract_data(call, true); 1656d2ddc776SDavid Howells if (ret < 0) 1657d2ddc776SDavid Howells return ret; 1658d2ddc776SDavid Howells 1659d2ddc776SDavid Howells count = ntohl(call->tmp); 1660d2ddc776SDavid Howells 1661d2ddc776SDavid Howells call->count = count; 1662d2ddc776SDavid Howells call->count2 = count; 166323a28913SDavid Howells afs_extract_discard(call, count * sizeof(__be32)); 1664d2ddc776SDavid Howells call->unmarshall++; 1665df561f66SGustavo A. R. Silva fallthrough; 1666d2ddc776SDavid Howells 166729881608SGustavo A. R. Silva /* Extract capabilities words */ 1668d2ddc776SDavid Howells case 2: 166912bdcf33SDavid Howells ret = afs_extract_data(call, false); 1670d2ddc776SDavid Howells if (ret < 0) 1671d2ddc776SDavid Howells return ret; 1672d2ddc776SDavid Howells 1673d2ddc776SDavid Howells /* TODO: Examine capabilities */ 1674d2ddc776SDavid Howells 1675d2ddc776SDavid Howells call->unmarshall++; 1676d2ddc776SDavid Howells break; 1677d2ddc776SDavid Howells } 1678d2ddc776SDavid Howells 1679d2ddc776SDavid Howells _leave(" = 0 [done]"); 1680d2ddc776SDavid Howells return 0; 1681d2ddc776SDavid Howells } 1682d2ddc776SDavid Howells 1683d2ddc776SDavid Howells /* 1684d2ddc776SDavid Howells * FS.GetCapabilities operation type 1685d2ddc776SDavid Howells */ 1686d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = { 1687d2ddc776SDavid Howells .name = "FS.GetCapabilities", 1688025db80cSDavid Howells .op = afs_FS_GetCapabilities, 1689d2ddc776SDavid Howells .deliver = afs_deliver_fs_get_capabilities, 16903bf0fb6fSDavid Howells .done = afs_fileserver_probe_result, 1691ffba718eSDavid Howells .destructor = afs_flat_call_destructor, 1692d2ddc776SDavid Howells }; 1693d2ddc776SDavid Howells 1694d2ddc776SDavid Howells /* 1695f6cbb368SDavid Howells * Probe a fileserver for the capabilities that it supports. This RPC can 1696f6cbb368SDavid Howells * reply with up to 196 words. The operation is asynchronous and if we managed 1697f6cbb368SDavid Howells * to allocate a call, true is returned the result is delivered through the 1698f6cbb368SDavid Howells * ->done() - otherwise we return false to indicate we didn't even try. 1699d2ddc776SDavid Howells */ 1700f6cbb368SDavid Howells bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server, 1701f6cbb368SDavid Howells struct afs_addr_cursor *ac, struct key *key) 1702d2ddc776SDavid Howells { 1703d2ddc776SDavid Howells struct afs_call *call; 1704d2ddc776SDavid Howells __be32 *bp; 1705d2ddc776SDavid Howells 1706d2ddc776SDavid Howells _enter(""); 1707d2ddc776SDavid Howells 1708d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4); 1709d2ddc776SDavid Howells if (!call) 1710f6cbb368SDavid Howells return false; 1711d2ddc776SDavid Howells 1712d2ddc776SDavid Howells call->key = key; 1713977e5f8eSDavid Howells call->server = afs_use_server(server, afs_server_trace_get_caps); 171430062bd1SDavid Howells call->upgrade = true; 17150b9bf381SDavid Howells call->async = true; 171694f699c9SDavid Howells call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; 1717d2ddc776SDavid Howells 1718d2ddc776SDavid Howells /* marshall the parameters */ 1719d2ddc776SDavid Howells bp = call->request; 1720d2ddc776SDavid Howells *bp++ = htonl(FSGETCAPABILITIES); 1721d2ddc776SDavid Howells 1722025db80cSDavid Howells trace_afs_make_fs_call(call, NULL); 17230b9bf381SDavid Howells afs_make_call(ac, call, GFP_NOFS); 1724f6cbb368SDavid Howells afs_put_call(call); 1725f6cbb368SDavid Howells return true; 1726e8d6c554SDavid Howells } 17275cf9dd55SDavid Howells 17285cf9dd55SDavid Howells /* 17295cf9dd55SDavid Howells * Deliver reply data to an FS.InlineBulkStatus call 17305cf9dd55SDavid Howells */ 17315cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) 17325cf9dd55SDavid Howells { 1733e49c7b2fSDavid Howells struct afs_operation *op = call->op; 173487182759SDavid Howells struct afs_status_cb *scb; 17355cf9dd55SDavid Howells const __be32 *bp; 17365cf9dd55SDavid Howells u32 tmp; 17375cf9dd55SDavid Howells int ret; 17385cf9dd55SDavid Howells 17395cf9dd55SDavid Howells _enter("{%u}", call->unmarshall); 17405cf9dd55SDavid Howells 17415cf9dd55SDavid Howells switch (call->unmarshall) { 17425cf9dd55SDavid Howells case 0: 174312bdcf33SDavid Howells afs_extract_to_tmp(call); 17445cf9dd55SDavid Howells call->unmarshall++; 1745df561f66SGustavo A. R. Silva fallthrough; 17465cf9dd55SDavid Howells 17475cf9dd55SDavid Howells /* Extract the file status count and array in two steps */ 17485cf9dd55SDavid Howells case 1: 17495cf9dd55SDavid Howells _debug("extract status count"); 175012bdcf33SDavid Howells ret = afs_extract_data(call, true); 17515cf9dd55SDavid Howells if (ret < 0) 17525cf9dd55SDavid Howells return ret; 17535cf9dd55SDavid Howells 17545cf9dd55SDavid Howells tmp = ntohl(call->tmp); 1755e49c7b2fSDavid Howells _debug("status count: %u/%u", tmp, op->nr_files); 1756e49c7b2fSDavid Howells if (tmp != op->nr_files) 17577126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_ibulkst_count); 17585cf9dd55SDavid Howells 17595cf9dd55SDavid Howells call->count = 0; 17605cf9dd55SDavid Howells call->unmarshall++; 17615cf9dd55SDavid Howells more_counts: 176212bdcf33SDavid Howells afs_extract_to_buf(call, 21 * sizeof(__be32)); 1763df561f66SGustavo A. R. Silva fallthrough; 176429881608SGustavo A. R. Silva 17655cf9dd55SDavid Howells case 2: 17665cf9dd55SDavid Howells _debug("extract status array %u", call->count); 176712bdcf33SDavid Howells ret = afs_extract_data(call, true); 17685cf9dd55SDavid Howells if (ret < 0) 17695cf9dd55SDavid Howells return ret; 17705cf9dd55SDavid Howells 1771e49c7b2fSDavid Howells switch (call->count) { 1772e49c7b2fSDavid Howells case 0: 1773e49c7b2fSDavid Howells scb = &op->file[0].scb; 1774e49c7b2fSDavid Howells break; 1775e49c7b2fSDavid Howells case 1: 1776e49c7b2fSDavid Howells scb = &op->file[1].scb; 1777e49c7b2fSDavid Howells break; 1778e49c7b2fSDavid Howells default: 1779e49c7b2fSDavid Howells scb = &op->more_files[call->count - 2].scb; 1780e49c7b2fSDavid Howells break; 1781e49c7b2fSDavid Howells } 1782e49c7b2fSDavid Howells 17835cf9dd55SDavid Howells bp = call->buffer; 178438355eecSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, scb); 1785e49c7b2fSDavid Howells 17865cf9dd55SDavid Howells call->count++; 1787e49c7b2fSDavid Howells if (call->count < op->nr_files) 17885cf9dd55SDavid Howells goto more_counts; 17895cf9dd55SDavid Howells 17905cf9dd55SDavid Howells call->count = 0; 17915cf9dd55SDavid Howells call->unmarshall++; 179212bdcf33SDavid Howells afs_extract_to_tmp(call); 1793df561f66SGustavo A. R. Silva fallthrough; 17945cf9dd55SDavid Howells 17955cf9dd55SDavid Howells /* Extract the callback count and array in two steps */ 17965cf9dd55SDavid Howells case 3: 17975cf9dd55SDavid Howells _debug("extract CB count"); 179812bdcf33SDavid Howells ret = afs_extract_data(call, true); 17995cf9dd55SDavid Howells if (ret < 0) 18005cf9dd55SDavid Howells return ret; 18015cf9dd55SDavid Howells 18025cf9dd55SDavid Howells tmp = ntohl(call->tmp); 18035cf9dd55SDavid Howells _debug("CB count: %u", tmp); 1804e49c7b2fSDavid Howells if (tmp != op->nr_files) 18057126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_ibulkst_cb_count); 18065cf9dd55SDavid Howells call->count = 0; 18075cf9dd55SDavid Howells call->unmarshall++; 18085cf9dd55SDavid Howells more_cbs: 180912bdcf33SDavid Howells afs_extract_to_buf(call, 3 * sizeof(__be32)); 1810df561f66SGustavo A. R. Silva fallthrough; 181129881608SGustavo A. R. Silva 18125cf9dd55SDavid Howells case 4: 18135cf9dd55SDavid Howells _debug("extract CB array"); 181412bdcf33SDavid Howells ret = afs_extract_data(call, true); 18155cf9dd55SDavid Howells if (ret < 0) 18165cf9dd55SDavid Howells return ret; 18175cf9dd55SDavid Howells 18185cf9dd55SDavid Howells _debug("unmarshall CB array"); 1819e49c7b2fSDavid Howells switch (call->count) { 1820e49c7b2fSDavid Howells case 0: 1821e49c7b2fSDavid Howells scb = &op->file[0].scb; 1822e49c7b2fSDavid Howells break; 1823e49c7b2fSDavid Howells case 1: 1824e49c7b2fSDavid Howells scb = &op->file[1].scb; 1825e49c7b2fSDavid Howells break; 1826e49c7b2fSDavid Howells default: 1827e49c7b2fSDavid Howells scb = &op->more_files[call->count - 2].scb; 1828e49c7b2fSDavid Howells break; 1829e49c7b2fSDavid Howells } 1830e49c7b2fSDavid Howells 18315cf9dd55SDavid Howells bp = call->buffer; 1832a58823acSDavid Howells xdr_decode_AFSCallBack(&bp, call, scb); 18335cf9dd55SDavid Howells call->count++; 1834e49c7b2fSDavid Howells if (call->count < op->nr_files) 18355cf9dd55SDavid Howells goto more_cbs; 18365cf9dd55SDavid Howells 183712bdcf33SDavid Howells afs_extract_to_buf(call, 6 * sizeof(__be32)); 18385cf9dd55SDavid Howells call->unmarshall++; 1839df561f66SGustavo A. R. Silva fallthrough; 184029881608SGustavo A. R. Silva 18415cf9dd55SDavid Howells case 5: 184212bdcf33SDavid Howells ret = afs_extract_data(call, false); 18435cf9dd55SDavid Howells if (ret < 0) 18445cf9dd55SDavid Howells return ret; 18455cf9dd55SDavid Howells 18465cf9dd55SDavid Howells bp = call->buffer; 1847e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 18485cf9dd55SDavid Howells 18495cf9dd55SDavid Howells call->unmarshall++; 1850*b2db6c35SGustavo A. R. Silva fallthrough; 18515cf9dd55SDavid Howells 18525cf9dd55SDavid Howells case 6: 18535cf9dd55SDavid Howells break; 18545cf9dd55SDavid Howells } 18555cf9dd55SDavid Howells 18565cf9dd55SDavid Howells _leave(" = 0 [done]"); 18575cf9dd55SDavid Howells return 0; 18585cf9dd55SDavid Howells } 18595cf9dd55SDavid Howells 1860e49c7b2fSDavid Howells static void afs_done_fs_inline_bulk_status(struct afs_call *call) 1861e49c7b2fSDavid Howells { 1862e49c7b2fSDavid Howells if (call->error == -ECONNABORTED && 186320325960SDavid Howells call->abort_code == RX_INVALID_OPERATION) { 1864e49c7b2fSDavid Howells set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags); 186520325960SDavid Howells if (call->op) 186620325960SDavid Howells set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags); 186720325960SDavid Howells } 1868e49c7b2fSDavid Howells } 1869e49c7b2fSDavid Howells 18705cf9dd55SDavid Howells /* 18715cf9dd55SDavid Howells * FS.InlineBulkStatus operation type 18725cf9dd55SDavid Howells */ 18735cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = { 18745cf9dd55SDavid Howells .name = "FS.InlineBulkStatus", 18755cf9dd55SDavid Howells .op = afs_FS_InlineBulkStatus, 18765cf9dd55SDavid Howells .deliver = afs_deliver_fs_inline_bulk_status, 1877e49c7b2fSDavid Howells .done = afs_done_fs_inline_bulk_status, 18785cf9dd55SDavid Howells .destructor = afs_flat_call_destructor, 18795cf9dd55SDavid Howells }; 18805cf9dd55SDavid Howells 18815cf9dd55SDavid Howells /* 18825cf9dd55SDavid Howells * Fetch the status information for up to 50 files 18835cf9dd55SDavid Howells */ 1884e49c7b2fSDavid Howells void afs_fs_inline_bulk_status(struct afs_operation *op) 18855cf9dd55SDavid Howells { 1886e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1887e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 18885cf9dd55SDavid Howells struct afs_call *call; 18895cf9dd55SDavid Howells __be32 *bp; 18905cf9dd55SDavid Howells int i; 18915cf9dd55SDavid Howells 189220325960SDavid Howells if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) { 1893e49c7b2fSDavid Howells op->error = -ENOTSUPP; 1894e49c7b2fSDavid Howells return; 18955cf9dd55SDavid Howells } 18965cf9dd55SDavid Howells 1897e49c7b2fSDavid Howells _enter(",%x,{%llx:%llu},%u", 1898e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files); 1899e49c7b2fSDavid Howells 1900e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus, 1901e49c7b2fSDavid Howells (2 + op->nr_files * 3) * 4, 1902e49c7b2fSDavid Howells 21 * 4); 1903e49c7b2fSDavid Howells if (!call) 1904e49c7b2fSDavid Howells return afs_op_nomem(op); 19055cf9dd55SDavid Howells 19065cf9dd55SDavid Howells /* marshall the parameters */ 19075cf9dd55SDavid Howells bp = call->request; 19085cf9dd55SDavid Howells *bp++ = htonl(FSINLINEBULKSTATUS); 1909e49c7b2fSDavid Howells *bp++ = htonl(op->nr_files); 1910e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 1911e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 1912e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 1913e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1914e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1915e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1916e49c7b2fSDavid Howells for (i = 0; i < op->nr_files - 2; i++) { 1917e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.vid); 1918e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.vnode); 1919e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.unique); 19205cf9dd55SDavid Howells } 19215cf9dd55SDavid Howells 1922e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1923e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 19245cf9dd55SDavid Howells } 1925260f082bSDavid Howells 1926260f082bSDavid Howells /* 1927260f082bSDavid Howells * deliver reply data to an FS.FetchACL 1928260f082bSDavid Howells */ 1929260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call) 1930260f082bSDavid Howells { 1931e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1932e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1933260f082bSDavid Howells struct afs_acl *acl; 1934260f082bSDavid Howells const __be32 *bp; 1935260f082bSDavid Howells unsigned int size; 1936260f082bSDavid Howells int ret; 1937260f082bSDavid Howells 1938260f082bSDavid Howells _enter("{%u}", call->unmarshall); 1939260f082bSDavid Howells 1940260f082bSDavid Howells switch (call->unmarshall) { 1941260f082bSDavid Howells case 0: 1942260f082bSDavid Howells afs_extract_to_tmp(call); 1943260f082bSDavid Howells call->unmarshall++; 1944df561f66SGustavo A. R. Silva fallthrough; 1945260f082bSDavid Howells 1946260f082bSDavid Howells /* extract the returned data length */ 1947260f082bSDavid Howells case 1: 1948260f082bSDavid Howells ret = afs_extract_data(call, true); 1949260f082bSDavid Howells if (ret < 0) 1950260f082bSDavid Howells return ret; 1951260f082bSDavid Howells 1952260f082bSDavid Howells size = call->count2 = ntohl(call->tmp); 1953260f082bSDavid Howells size = round_up(size, 4); 1954260f082bSDavid Howells 1955260f082bSDavid Howells acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); 1956260f082bSDavid Howells if (!acl) 1957260f082bSDavid Howells return -ENOMEM; 1958e49c7b2fSDavid Howells op->acl = acl; 1959260f082bSDavid Howells acl->size = call->count2; 1960260f082bSDavid Howells afs_extract_begin(call, acl->data, size); 1961260f082bSDavid Howells call->unmarshall++; 1962df561f66SGustavo A. R. Silva fallthrough; 1963260f082bSDavid Howells 1964260f082bSDavid Howells /* extract the returned data */ 1965260f082bSDavid Howells case 2: 1966260f082bSDavid Howells ret = afs_extract_data(call, true); 1967260f082bSDavid Howells if (ret < 0) 1968260f082bSDavid Howells return ret; 1969260f082bSDavid Howells 1970260f082bSDavid Howells afs_extract_to_buf(call, (21 + 6) * 4); 1971260f082bSDavid Howells call->unmarshall++; 1972df561f66SGustavo A. R. Silva fallthrough; 1973260f082bSDavid Howells 1974260f082bSDavid Howells /* extract the metadata */ 1975260f082bSDavid Howells case 3: 1976260f082bSDavid Howells ret = afs_extract_data(call, false); 1977260f082bSDavid Howells if (ret < 0) 1978260f082bSDavid Howells return ret; 1979260f082bSDavid Howells 1980260f082bSDavid Howells bp = call->buffer; 1981e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 1982e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 1983260f082bSDavid Howells 1984260f082bSDavid Howells call->unmarshall++; 1985*b2db6c35SGustavo A. R. Silva fallthrough; 1986260f082bSDavid Howells 1987260f082bSDavid Howells case 4: 1988260f082bSDavid Howells break; 1989260f082bSDavid Howells } 1990260f082bSDavid Howells 1991260f082bSDavid Howells _leave(" = 0 [done]"); 1992260f082bSDavid Howells return 0; 1993260f082bSDavid Howells } 1994260f082bSDavid Howells 1995260f082bSDavid Howells /* 1996260f082bSDavid Howells * FS.FetchACL operation type 1997260f082bSDavid Howells */ 1998260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = { 1999260f082bSDavid Howells .name = "FS.FetchACL", 2000260f082bSDavid Howells .op = afs_FS_FetchACL, 2001260f082bSDavid Howells .deliver = afs_deliver_fs_fetch_acl, 2002260f082bSDavid Howells }; 2003260f082bSDavid Howells 2004260f082bSDavid Howells /* 2005260f082bSDavid Howells * Fetch the ACL for a file. 2006260f082bSDavid Howells */ 2007e49c7b2fSDavid Howells void afs_fs_fetch_acl(struct afs_operation *op) 2008260f082bSDavid Howells { 2009e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 2010260f082bSDavid Howells struct afs_call *call; 2011260f082bSDavid Howells __be32 *bp; 2012260f082bSDavid Howells 2013260f082bSDavid Howells _enter(",%x,{%llx:%llu},,", 2014e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2015260f082bSDavid Howells 2016e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4); 2017e49c7b2fSDavid Howells if (!call) 2018e49c7b2fSDavid Howells return afs_op_nomem(op); 2019260f082bSDavid Howells 2020260f082bSDavid Howells /* marshall the parameters */ 2021260f082bSDavid Howells bp = call->request; 2022260f082bSDavid Howells bp[0] = htonl(FSFETCHACL); 2023e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 2024e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 2025e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2026260f082bSDavid Howells 2027e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 2028e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_KERNEL); 2029ffba718eSDavid Howells } 2030ffba718eSDavid Howells 2031ffba718eSDavid Howells /* 2032b10494afSJoe Gorse * FS.StoreACL operation type 2033b10494afSJoe Gorse */ 2034b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = { 2035b10494afSJoe Gorse .name = "FS.StoreACL", 2036b10494afSJoe Gorse .op = afs_FS_StoreACL, 2037ffba718eSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 2038b10494afSJoe Gorse .destructor = afs_flat_call_destructor, 2039b10494afSJoe Gorse }; 2040b10494afSJoe Gorse 2041b10494afSJoe Gorse /* 2042b10494afSJoe Gorse * Fetch the ACL for a file. 2043b10494afSJoe Gorse */ 2044e49c7b2fSDavid Howells void afs_fs_store_acl(struct afs_operation *op) 2045b10494afSJoe Gorse { 2046e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 2047b10494afSJoe Gorse struct afs_call *call; 2048e49c7b2fSDavid Howells const struct afs_acl *acl = op->acl; 2049b10494afSJoe Gorse size_t size; 2050b10494afSJoe Gorse __be32 *bp; 2051b10494afSJoe Gorse 2052b10494afSJoe Gorse _enter(",%x,{%llx:%llu},,", 2053e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2054b10494afSJoe Gorse 2055b10494afSJoe Gorse size = round_up(acl->size, 4); 2056e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL, 2057b10494afSJoe Gorse 5 * 4 + size, (21 + 6) * 4); 2058e49c7b2fSDavid Howells if (!call) 2059e49c7b2fSDavid Howells return afs_op_nomem(op); 2060b10494afSJoe Gorse 2061b10494afSJoe Gorse /* marshall the parameters */ 2062b10494afSJoe Gorse bp = call->request; 2063b10494afSJoe Gorse bp[0] = htonl(FSSTOREACL); 2064e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 2065e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 2066e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2067b10494afSJoe Gorse bp[4] = htonl(acl->size); 2068b10494afSJoe Gorse memcpy(&bp[5], acl->data, acl->size); 2069b10494afSJoe Gorse if (acl->size != size) 2070b10494afSJoe Gorse memset((void *)&bp[5] + acl->size, 0, size - acl->size); 2071b10494afSJoe Gorse 2072e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 2073e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_KERNEL); 20741da177e4SLinus Torvalds } 2075