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> 131da177e4SLinus Torvalds #include "internal.h" 1408e0e7c8SDavid Howells #include "afs_fs.h" 15dd9fbcb8SDavid Howells #include "xdr_fs.h" 16c435ee34SDavid Howells 176db3ac3cSDavid Howells /* 18260a9803SDavid Howells * decode an AFSFid block 19260a9803SDavid Howells */ 20260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 21260a9803SDavid Howells { 22260a9803SDavid Howells const __be32 *bp = *_bp; 23260a9803SDavid Howells 24260a9803SDavid Howells fid->vid = ntohl(*bp++); 25260a9803SDavid Howells fid->vnode = ntohl(*bp++); 26260a9803SDavid Howells fid->unique = ntohl(*bp++); 27260a9803SDavid Howells *_bp = bp; 28260a9803SDavid Howells } 29260a9803SDavid Howells 30260a9803SDavid Howells /* 31888b3384SDavid Howells * Dump a bad file status record. 32888b3384SDavid Howells */ 33888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp) 34888b3384SDavid Howells { 35888b3384SDavid Howells __be32 x[4]; 36888b3384SDavid Howells int i; 37888b3384SDavid Howells 38888b3384SDavid Howells pr_notice("AFS XDR: Bad status record\n"); 39888b3384SDavid Howells for (i = 0; i < 5 * 4 * 4; i += 16) { 40888b3384SDavid Howells memcpy(x, bp, 16); 41888b3384SDavid Howells bp += 4; 42888b3384SDavid Howells pr_notice("%03x: %08x %08x %08x %08x\n", 43888b3384SDavid Howells i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); 44888b3384SDavid Howells } 45888b3384SDavid Howells 46888b3384SDavid Howells memcpy(x, bp, 4); 47888b3384SDavid Howells pr_notice("0x50: %08x\n", ntohl(x[0])); 48888b3384SDavid Howells } 49888b3384SDavid Howells 50888b3384SDavid Howells /* 51dd9fbcb8SDavid Howells * decode an AFSFetchStatus block 52dd9fbcb8SDavid Howells */ 5338355eecSDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 54a58823acSDavid Howells struct afs_call *call, 55a58823acSDavid Howells struct afs_status_cb *scb) 56dd9fbcb8SDavid Howells { 57dd9fbcb8SDavid Howells const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; 58a58823acSDavid Howells struct afs_file_status *status = &scb->status; 59684b0f68SDavid Howells bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); 60dd9fbcb8SDavid Howells u64 data_version, size; 61dd9fbcb8SDavid Howells u32 type, abort_code; 62dd9fbcb8SDavid Howells 63684b0f68SDavid Howells abort_code = ntohl(xdr->abort_code); 64684b0f68SDavid Howells 65dd9fbcb8SDavid Howells if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { 66684b0f68SDavid Howells if (xdr->if_version == htonl(0) && 67684b0f68SDavid Howells abort_code != 0 && 68684b0f68SDavid Howells inline_error) { 69684b0f68SDavid Howells /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus 70684b0f68SDavid Howells * whereby it doesn't set the interface version in the error 71684b0f68SDavid Howells * case. 72684b0f68SDavid Howells */ 73684b0f68SDavid Howells status->abort_code = abort_code; 74a38a7558SDavid Howells scb->have_error = true; 7538355eecSDavid Howells goto advance; 76684b0f68SDavid Howells } 77684b0f68SDavid Howells 78dd9fbcb8SDavid Howells pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); 79dd9fbcb8SDavid Howells goto bad; 80dd9fbcb8SDavid Howells } 81dd9fbcb8SDavid Howells 82684b0f68SDavid Howells if (abort_code != 0 && inline_error) { 83684b0f68SDavid Howells status->abort_code = abort_code; 843e0d9892SDavid Howells scb->have_error = true; 8538355eecSDavid Howells goto advance; 86684b0f68SDavid Howells } 87684b0f68SDavid Howells 88dd9fbcb8SDavid Howells type = ntohl(xdr->type); 89dd9fbcb8SDavid Howells switch (type) { 90dd9fbcb8SDavid Howells case AFS_FTYPE_FILE: 91dd9fbcb8SDavid Howells case AFS_FTYPE_DIR: 92dd9fbcb8SDavid Howells case AFS_FTYPE_SYMLINK: 93dd9fbcb8SDavid Howells status->type = type; 94dd9fbcb8SDavid Howells break; 95dd9fbcb8SDavid Howells default: 96dd9fbcb8SDavid Howells goto bad; 97dd9fbcb8SDavid Howells } 98dd9fbcb8SDavid Howells 99a58823acSDavid Howells status->nlink = ntohl(xdr->nlink); 100a58823acSDavid Howells status->author = ntohl(xdr->author); 101a58823acSDavid Howells status->owner = ntohl(xdr->owner); 102a58823acSDavid Howells status->caller_access = ntohl(xdr->caller_access); /* Ticket dependent */ 103a58823acSDavid Howells status->anon_access = ntohl(xdr->anon_access); 104a58823acSDavid Howells status->mode = ntohl(xdr->mode) & S_IALLUGO; 105a58823acSDavid Howells status->group = ntohl(xdr->group); 106a58823acSDavid Howells status->lock_count = ntohl(xdr->lock_count); 107dd9fbcb8SDavid Howells 108d4936803SDavid Howells status->mtime_client.tv_sec = ntohl(xdr->mtime_client); 109d4936803SDavid Howells status->mtime_client.tv_nsec = 0; 110d4936803SDavid Howells status->mtime_server.tv_sec = ntohl(xdr->mtime_server); 111d4936803SDavid Howells status->mtime_server.tv_nsec = 0; 112dd9fbcb8SDavid Howells 113dd9fbcb8SDavid Howells size = (u64)ntohl(xdr->size_lo); 114dd9fbcb8SDavid Howells size |= (u64)ntohl(xdr->size_hi) << 32; 115dd9fbcb8SDavid Howells status->size = size; 116dd9fbcb8SDavid Howells 117dd9fbcb8SDavid Howells data_version = (u64)ntohl(xdr->data_version_lo); 118dd9fbcb8SDavid Howells data_version |= (u64)ntohl(xdr->data_version_hi) << 32; 119dd9fbcb8SDavid Howells status->data_version = data_version; 120a38a7558SDavid Howells scb->have_status = true; 121c72057b5SDavid Howells advance: 122dd9fbcb8SDavid Howells *_bp = (const void *)*_bp + sizeof(*xdr); 12338355eecSDavid Howells return; 124dd9fbcb8SDavid Howells 125dd9fbcb8SDavid Howells bad: 126dd9fbcb8SDavid Howells xdr_dump_bad(*_bp); 1277126ead9SDavid Howells afs_protocol_error(call, afs_eproto_bad_status); 128c72057b5SDavid Howells goto advance; 129c875c76aSDavid Howells } 130c875c76aSDavid Howells 13178107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry) 13278107055SDavid Howells { 13378107055SDavid Howells return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry; 13478107055SDavid Howells } 13578107055SDavid Howells 136a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, 137a58823acSDavid Howells struct afs_call *call, 138a58823acSDavid Howells struct afs_status_cb *scb) 13978107055SDavid Howells { 140a58823acSDavid Howells struct afs_callback *cb = &scb->callback; 14178107055SDavid Howells const __be32 *bp = *_bp; 14278107055SDavid Howells 1437c712458SDavid Howells bp++; /* version */ 14478107055SDavid Howells cb->expires_at = xdr_decode_expiry(call, ntohl(*bp++)); 1457c712458SDavid Howells bp++; /* type */ 146a58823acSDavid Howells scb->have_cb = true; 14778107055SDavid Howells *_bp = bp; 14878107055SDavid Howells } 14978107055SDavid Howells 1501da177e4SLinus Torvalds /* 15108e0e7c8SDavid Howells * decode an AFSVolSync block 1521da177e4SLinus Torvalds */ 15308e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 15408e0e7c8SDavid Howells struct afs_volsync *volsync) 1551da177e4SLinus Torvalds { 15608e0e7c8SDavid Howells const __be32 *bp = *_bp; 15730062bd1SDavid Howells u32 creation; 1581da177e4SLinus Torvalds 15930062bd1SDavid Howells creation = ntohl(*bp++); 16008e0e7c8SDavid Howells bp++; /* spare2 */ 16108e0e7c8SDavid Howells bp++; /* spare3 */ 16208e0e7c8SDavid Howells bp++; /* spare4 */ 16308e0e7c8SDavid Howells bp++; /* spare5 */ 16408e0e7c8SDavid Howells bp++; /* spare6 */ 16508e0e7c8SDavid Howells *_bp = bp; 16630062bd1SDavid Howells 16730062bd1SDavid Howells if (volsync) 16830062bd1SDavid Howells volsync->creation = creation; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 17108e0e7c8SDavid Howells /* 17231143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 17331143d5dSDavid Howells */ 17431143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 17531143d5dSDavid Howells { 17631143d5dSDavid Howells __be32 *bp = *_bp; 17731143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 17831143d5dSDavid Howells 17931143d5dSDavid Howells mask = 0; 18031143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 18131143d5dSDavid Howells mask |= AFS_SET_MTIME; 18231143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 18331143d5dSDavid Howells } 18431143d5dSDavid Howells 18531143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 18631143d5dSDavid Howells mask |= AFS_SET_OWNER; 187a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 18831143d5dSDavid Howells } 18931143d5dSDavid Howells 19031143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 19131143d5dSDavid Howells mask |= AFS_SET_GROUP; 192a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 19331143d5dSDavid Howells } 19431143d5dSDavid Howells 19531143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 19631143d5dSDavid Howells mask |= AFS_SET_MODE; 19731143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 19831143d5dSDavid Howells } 19931143d5dSDavid Howells 20031143d5dSDavid Howells *bp++ = htonl(mask); 20131143d5dSDavid Howells *bp++ = htonl(mtime); 20231143d5dSDavid Howells *bp++ = htonl(owner); 20331143d5dSDavid Howells *bp++ = htonl(group); 20431143d5dSDavid Howells *bp++ = htonl(mode); 20531143d5dSDavid Howells *bp++ = 0; /* segment size */ 20631143d5dSDavid Howells *_bp = bp; 20731143d5dSDavid Howells } 20831143d5dSDavid Howells 20931143d5dSDavid Howells /* 21045222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 21145222b9eSDavid Howells */ 21245222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 21345222b9eSDavid Howells struct afs_volume_status *vs) 21445222b9eSDavid Howells { 21545222b9eSDavid Howells const __be32 *bp = *_bp; 21645222b9eSDavid Howells 21745222b9eSDavid Howells vs->vid = ntohl(*bp++); 21845222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 21945222b9eSDavid Howells vs->online = ntohl(*bp++); 22045222b9eSDavid Howells vs->in_service = ntohl(*bp++); 22145222b9eSDavid Howells vs->blessed = ntohl(*bp++); 22245222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 22345222b9eSDavid Howells vs->type = ntohl(*bp++); 22445222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 22545222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 22645222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 22745222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 22845222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 22930062bd1SDavid Howells vs->vol_copy_date = 0; 23030062bd1SDavid Howells vs->vol_backup_date = 0; 23145222b9eSDavid Howells *_bp = bp; 23245222b9eSDavid Howells } 23345222b9eSDavid Howells 23445222b9eSDavid Howells /* 23508e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 23608e0e7c8SDavid Howells */ 237e49c7b2fSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call) 23808e0e7c8SDavid Howells { 239e49c7b2fSDavid Howells struct afs_operation *op = call->op; 240e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; 24108e0e7c8SDavid Howells const __be32 *bp; 242372ee163SDavid Howells int ret; 2431da177e4SLinus Torvalds 244d001648eSDavid Howells ret = afs_transfer_reply(call); 245372ee163SDavid Howells if (ret < 0) 246372ee163SDavid Howells return ret; 2471da177e4SLinus Torvalds 24808e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 24908e0e7c8SDavid Howells bp = call->buffer; 250e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 251e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 252e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 2531da177e4SLinus Torvalds 25408e0e7c8SDavid Howells _leave(" = 0 [done]"); 25508e0e7c8SDavid Howells return 0; 256ec26815aSDavid Howells } 25708e0e7c8SDavid Howells 25808e0e7c8SDavid Howells /* 25908e0e7c8SDavid Howells * FS.FetchStatus operation type 26008e0e7c8SDavid Howells */ 261e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 262e49c7b2fSDavid Howells .name = "FS.FetchStatus", 263025db80cSDavid Howells .op = afs_FS_FetchStatus, 264e49c7b2fSDavid Howells .deliver = afs_deliver_fs_fetch_status, 26508e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 26608e0e7c8SDavid Howells }; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* 2691da177e4SLinus Torvalds * fetch the status information for a file 2701da177e4SLinus Torvalds */ 271e49c7b2fSDavid Howells void afs_fs_fetch_status(struct afs_operation *op) 2721da177e4SLinus Torvalds { 273e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[op->fetch_status.which]; 27408e0e7c8SDavid Howells struct afs_call *call; 2751da177e4SLinus Torvalds __be32 *bp; 2761da177e4SLinus Torvalds 2773b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 278e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2791da177e4SLinus Torvalds 280e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchStatus, 2815cf9dd55SDavid Howells 16, (21 + 3 + 6) * 4); 282e49c7b2fSDavid Howells if (!call) 283e49c7b2fSDavid Howells return afs_op_nomem(op); 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds /* marshall the parameters */ 28608e0e7c8SDavid Howells bp = call->request; 2871da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 288e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 289e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 290e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2911da177e4SLinus Torvalds 292e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 293e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 294ec26815aSDavid Howells } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds /* 29708e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 2981da177e4SLinus Torvalds */ 299d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call) 3001da177e4SLinus Torvalds { 301e49c7b2fSDavid Howells struct afs_operation *op = call->op; 302e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 303e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 30408e0e7c8SDavid Howells const __be32 *bp; 305196ee9cdSDavid Howells unsigned int size; 3061da177e4SLinus Torvalds int ret; 3071da177e4SLinus Torvalds 30812bdcf33SDavid Howells _enter("{%u,%zu/%llu}", 309fc276122SDavid Howells call->unmarshall, iov_iter_count(call->iter), req->actual_len); 3101da177e4SLinus Torvalds 31108e0e7c8SDavid Howells switch (call->unmarshall) { 31208e0e7c8SDavid Howells case 0: 313196ee9cdSDavid Howells req->actual_len = 0; 31412bdcf33SDavid Howells req->index = 0; 31512bdcf33SDavid Howells req->offset = req->pos & (PAGE_SIZE - 1); 31608e0e7c8SDavid Howells call->unmarshall++; 31712bdcf33SDavid Howells if (call->operation_ID == FSFETCHDATA64) { 31812bdcf33SDavid Howells afs_extract_to_tmp64(call); 31912bdcf33SDavid Howells } else { 32012bdcf33SDavid Howells call->tmp_u = htonl(0); 32112bdcf33SDavid Howells afs_extract_to_tmp(call); 322b9b1f8d5SDavid Howells } 323df561f66SGustavo A. R. Silva fallthrough; 3241da177e4SLinus Torvalds 32529881608SGustavo A. R. Silva /* extract the returned data length */ 32612bdcf33SDavid Howells case 1: 32708e0e7c8SDavid Howells _debug("extract data length"); 32812bdcf33SDavid Howells ret = afs_extract_data(call, true); 329372ee163SDavid Howells if (ret < 0) 330372ee163SDavid Howells return ret; 3311da177e4SLinus Torvalds 33212bdcf33SDavid Howells req->actual_len = be64_to_cpu(call->tmp64); 333196ee9cdSDavid Howells _debug("DATA length: %llu", req->actual_len); 33412bdcf33SDavid Howells req->remain = min(req->len, req->actual_len); 33512bdcf33SDavid Howells if (req->remain == 0) 336196ee9cdSDavid Howells goto no_more_data; 33712bdcf33SDavid Howells 33808e0e7c8SDavid Howells call->unmarshall++; 3391da177e4SLinus Torvalds 340196ee9cdSDavid Howells begin_page: 3416db3ac3cSDavid Howells ASSERTCMP(req->index, <, req->nr_pages); 34212bdcf33SDavid Howells if (req->remain > PAGE_SIZE - req->offset) 34312bdcf33SDavid Howells size = PAGE_SIZE - req->offset; 344196ee9cdSDavid Howells else 345196ee9cdSDavid Howells size = req->remain; 34612bdcf33SDavid Howells call->bvec[0].bv_len = size; 34712bdcf33SDavid Howells call->bvec[0].bv_offset = req->offset; 34812bdcf33SDavid Howells call->bvec[0].bv_page = req->pages[req->index]; 349fc276122SDavid Howells iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size); 35012bdcf33SDavid Howells ASSERTCMP(size, <=, PAGE_SIZE); 351df561f66SGustavo A. R. Silva fallthrough; 352196ee9cdSDavid Howells 35329881608SGustavo A. R. Silva /* extract the returned data */ 35412bdcf33SDavid Howells case 2: 35512bdcf33SDavid Howells _debug("extract data %zu/%llu", 356fc276122SDavid Howells iov_iter_count(call->iter), req->remain); 357196ee9cdSDavid Howells 35812bdcf33SDavid Howells ret = afs_extract_data(call, true); 359372ee163SDavid Howells if (ret < 0) 360372ee163SDavid Howells return ret; 36112bdcf33SDavid Howells req->remain -= call->bvec[0].bv_len; 36212bdcf33SDavid Howells req->offset += call->bvec[0].bv_len; 36312bdcf33SDavid Howells ASSERTCMP(req->offset, <=, PAGE_SIZE); 36412bdcf33SDavid Howells if (req->offset == PAGE_SIZE) { 36512bdcf33SDavid Howells req->offset = 0; 36629f06985SDavid Howells req->index++; 36712bdcf33SDavid Howells if (req->remain > 0) 368196ee9cdSDavid Howells goto begin_page; 369196ee9cdSDavid Howells } 37012bdcf33SDavid Howells 37112bdcf33SDavid Howells ASSERTCMP(req->remain, ==, 0); 37212bdcf33SDavid Howells if (req->actual_len <= req->len) 3736db3ac3cSDavid Howells goto no_more_data; 3746db3ac3cSDavid Howells 3756db3ac3cSDavid Howells /* Discard any excess data the server gave us */ 37623a28913SDavid Howells afs_extract_discard(call, req->actual_len - req->len); 37712bdcf33SDavid Howells call->unmarshall = 3; 378df561f66SGustavo A. R. Silva fallthrough; 37929881608SGustavo A. R. Silva 38012bdcf33SDavid Howells case 3: 38112bdcf33SDavid Howells _debug("extract discard %zu/%llu", 382fc276122SDavid Howells iov_iter_count(call->iter), req->actual_len - req->len); 3836db3ac3cSDavid Howells 38412bdcf33SDavid Howells ret = afs_extract_data(call, true); 3856db3ac3cSDavid Howells if (ret < 0) 3866db3ac3cSDavid Howells return ret; 3871da177e4SLinus Torvalds 388196ee9cdSDavid Howells no_more_data: 38912bdcf33SDavid Howells call->unmarshall = 4; 39012bdcf33SDavid Howells afs_extract_to_buf(call, (21 + 3 + 6) * 4); 391df561f66SGustavo A. R. Silva fallthrough; 39208e0e7c8SDavid Howells 39329881608SGustavo A. R. Silva /* extract the metadata */ 39412bdcf33SDavid Howells case 4: 39512bdcf33SDavid Howells ret = afs_extract_data(call, false); 396372ee163SDavid Howells if (ret < 0) 397372ee163SDavid Howells return ret; 3981da177e4SLinus Torvalds 39908e0e7c8SDavid Howells bp = call->buffer; 400e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 401e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 402e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 4031da177e4SLinus Torvalds 404e49c7b2fSDavid Howells req->data_version = vp->scb.status.data_version; 405e49c7b2fSDavid Howells req->file_size = vp->scb.status.size; 406a58823acSDavid Howells 40708e0e7c8SDavid Howells call->unmarshall++; 4081da177e4SLinus Torvalds 40912bdcf33SDavid Howells case 5: 4101da177e4SLinus Torvalds break; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4136db3ac3cSDavid Howells for (; req->index < req->nr_pages; req->index++) { 41412bdcf33SDavid Howells if (req->offset < PAGE_SIZE) 4156db3ac3cSDavid Howells zero_user_segment(req->pages[req->index], 41612bdcf33SDavid Howells req->offset, PAGE_SIZE); 41712bdcf33SDavid Howells req->offset = 0; 418416351f2SDavid Howells } 419416351f2SDavid Howells 4209d1be4f4SDavid Howells if (req->page_done) 4219d1be4f4SDavid Howells for (req->index = 0; req->index < req->nr_pages; req->index++) 4229d1be4f4SDavid Howells req->page_done(req); 4239d1be4f4SDavid Howells 42408e0e7c8SDavid Howells _leave(" = 0 [done]"); 42508e0e7c8SDavid Howells return 0; 426ec26815aSDavid Howells } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* 42908e0e7c8SDavid Howells * FS.FetchData operation type 4301da177e4SLinus Torvalds */ 43108e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 43200d3b7a4SDavid Howells .name = "FS.FetchData", 433025db80cSDavid Howells .op = afs_FS_FetchData, 43408e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 435e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 43608e0e7c8SDavid Howells }; 43708e0e7c8SDavid Howells 438b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 439b9b1f8d5SDavid Howells .name = "FS.FetchData64", 440025db80cSDavid Howells .op = afs_FS_FetchData64, 441b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 442e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 443b9b1f8d5SDavid Howells }; 444b9b1f8d5SDavid Howells 445b9b1f8d5SDavid Howells /* 446b9b1f8d5SDavid Howells * fetch data from a very large file 447b9b1f8d5SDavid Howells */ 448e49c7b2fSDavid Howells static void afs_fs_fetch_data64(struct afs_operation *op) 449b9b1f8d5SDavid Howells { 450e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 451e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 452b9b1f8d5SDavid Howells struct afs_call *call; 453b9b1f8d5SDavid Howells __be32 *bp; 454b9b1f8d5SDavid Howells 455b9b1f8d5SDavid Howells _enter(""); 456b9b1f8d5SDavid Howells 457e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 458b9b1f8d5SDavid Howells if (!call) 459e49c7b2fSDavid Howells return afs_op_nomem(op); 460b9b1f8d5SDavid Howells 461b9b1f8d5SDavid Howells /* marshall the parameters */ 462b9b1f8d5SDavid Howells bp = call->request; 463b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 464e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 465e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 466e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 467196ee9cdSDavid Howells bp[4] = htonl(upper_32_bits(req->pos)); 468196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->pos)); 469b9b1f8d5SDavid Howells bp[6] = 0; 470196ee9cdSDavid Howells bp[7] = htonl(lower_32_bits(req->len)); 471b9b1f8d5SDavid Howells 472e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 473e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 474b9b1f8d5SDavid Howells } 475b9b1f8d5SDavid Howells 47608e0e7c8SDavid Howells /* 47708e0e7c8SDavid Howells * fetch data from a file 47808e0e7c8SDavid Howells */ 479e49c7b2fSDavid Howells void afs_fs_fetch_data(struct afs_operation *op) 4801da177e4SLinus Torvalds { 481e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 48208e0e7c8SDavid Howells struct afs_call *call; 483e49c7b2fSDavid Howells struct afs_read *req = op->fetch.req; 48408e0e7c8SDavid Howells __be32 *bp; 4851da177e4SLinus Torvalds 486196ee9cdSDavid Howells if (upper_32_bits(req->pos) || 487196ee9cdSDavid Howells upper_32_bits(req->len) || 488196ee9cdSDavid Howells upper_32_bits(req->pos + req->len)) 489e49c7b2fSDavid Howells return afs_fs_fetch_data64(op); 490b9b1f8d5SDavid Howells 49108e0e7c8SDavid Howells _enter(""); 4921da177e4SLinus Torvalds 493e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 49408e0e7c8SDavid Howells if (!call) 495e49c7b2fSDavid Howells return afs_op_nomem(op); 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* marshall the parameters */ 49808e0e7c8SDavid Howells bp = call->request; 49908e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 500e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 501e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 502e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 503196ee9cdSDavid Howells bp[4] = htonl(lower_32_bits(req->pos)); 504196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->len)); 5051da177e4SLinus Torvalds 506e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 507e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 50808e0e7c8SDavid Howells } 509260a9803SDavid Howells 510260a9803SDavid Howells /* 511260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 512260a9803SDavid Howells */ 513d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call) 514260a9803SDavid Howells { 515e49c7b2fSDavid Howells struct afs_operation *op = call->op; 516e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 517e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 518260a9803SDavid Howells const __be32 *bp; 519372ee163SDavid Howells int ret; 520260a9803SDavid Howells 521d001648eSDavid Howells ret = afs_transfer_reply(call); 522372ee163SDavid Howells if (ret < 0) 523372ee163SDavid Howells return ret; 524260a9803SDavid Howells 525260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 526260a9803SDavid Howells bp = call->buffer; 527e49c7b2fSDavid Howells xdr_decode_AFSFid(&bp, &op->file[1].fid); 528e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 529e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 530e49c7b2fSDavid Howells xdr_decode_AFSCallBack(&bp, call, &vp->scb); 531e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 532260a9803SDavid Howells 533260a9803SDavid Howells _leave(" = 0 [done]"); 534260a9803SDavid Howells return 0; 535260a9803SDavid Howells } 536260a9803SDavid Howells 537260a9803SDavid Howells /* 538260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 539260a9803SDavid Howells */ 540025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = { 541025db80cSDavid Howells .name = "FS.CreateFile", 542025db80cSDavid Howells .op = afs_FS_CreateFile, 543025db80cSDavid Howells .deliver = afs_deliver_fs_create_vnode, 544025db80cSDavid Howells .destructor = afs_flat_call_destructor, 545025db80cSDavid Howells }; 546025db80cSDavid Howells 547e49c7b2fSDavid Howells /* 548e49c7b2fSDavid Howells * Create a file. 549e49c7b2fSDavid Howells */ 550e49c7b2fSDavid Howells void afs_fs_create_file(struct afs_operation *op) 551e49c7b2fSDavid Howells { 552e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 553e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 554e49c7b2fSDavid Howells struct afs_call *call; 555e49c7b2fSDavid Howells size_t namesz, reqsz, padsz; 556e49c7b2fSDavid Howells __be32 *bp; 557e49c7b2fSDavid Howells 558e49c7b2fSDavid Howells _enter(""); 559e49c7b2fSDavid Howells 560e49c7b2fSDavid Howells namesz = name->len; 561e49c7b2fSDavid Howells padsz = (4 - (namesz & 3)) & 3; 562e49c7b2fSDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 563e49c7b2fSDavid Howells 564e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, 565e49c7b2fSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 566e49c7b2fSDavid Howells if (!call) 567e49c7b2fSDavid Howells return afs_op_nomem(op); 568e49c7b2fSDavid Howells 569e49c7b2fSDavid Howells /* marshall the parameters */ 570e49c7b2fSDavid Howells bp = call->request; 571e49c7b2fSDavid Howells *bp++ = htonl(FSCREATEFILE); 572e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 573e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 574e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 575e49c7b2fSDavid Howells *bp++ = htonl(namesz); 576e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 577e49c7b2fSDavid Howells bp = (void *) bp + namesz; 578e49c7b2fSDavid Howells if (padsz > 0) { 579e49c7b2fSDavid Howells memset(bp, 0, padsz); 580e49c7b2fSDavid Howells bp = (void *) bp + padsz; 581e49c7b2fSDavid Howells } 582e49c7b2fSDavid Howells *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 583e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 584e49c7b2fSDavid Howells *bp++ = 0; /* owner */ 585e49c7b2fSDavid Howells *bp++ = 0; /* group */ 586e49c7b2fSDavid Howells *bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */ 587e49c7b2fSDavid Howells *bp++ = 0; /* segment size */ 588e49c7b2fSDavid Howells 589e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 590e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 591e49c7b2fSDavid Howells } 592e49c7b2fSDavid Howells 593025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = { 594025db80cSDavid Howells .name = "FS.MakeDir", 595025db80cSDavid Howells .op = afs_FS_MakeDir, 596260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 597260a9803SDavid Howells .destructor = afs_flat_call_destructor, 598260a9803SDavid Howells }; 599260a9803SDavid Howells 600260a9803SDavid Howells /* 601e49c7b2fSDavid Howells * Create a new directory 602260a9803SDavid Howells */ 603e49c7b2fSDavid Howells void afs_fs_make_dir(struct afs_operation *op) 604260a9803SDavid Howells { 605e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 606e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 607260a9803SDavid Howells struct afs_call *call; 608260a9803SDavid Howells size_t namesz, reqsz, padsz; 609260a9803SDavid Howells __be32 *bp; 610260a9803SDavid Howells 611260a9803SDavid Howells _enter(""); 612260a9803SDavid Howells 613e49c7b2fSDavid Howells namesz = name->len; 614260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 615260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 616260a9803SDavid Howells 617e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir, 618025db80cSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 619260a9803SDavid Howells if (!call) 620e49c7b2fSDavid Howells return afs_op_nomem(op); 621260a9803SDavid Howells 622260a9803SDavid Howells /* marshall the parameters */ 623260a9803SDavid Howells bp = call->request; 624e49c7b2fSDavid Howells *bp++ = htonl(FSMAKEDIR); 625e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 626e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 627e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 628260a9803SDavid Howells *bp++ = htonl(namesz); 629e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 630260a9803SDavid Howells bp = (void *) bp + namesz; 631260a9803SDavid Howells if (padsz > 0) { 632260a9803SDavid Howells memset(bp, 0, padsz); 633260a9803SDavid Howells bp = (void *) bp + padsz; 634260a9803SDavid Howells } 635ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 636e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 637260a9803SDavid Howells *bp++ = 0; /* owner */ 638260a9803SDavid Howells *bp++ = 0; /* group */ 639e49c7b2fSDavid Howells *bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */ 640260a9803SDavid Howells *bp++ = 0; /* segment size */ 641260a9803SDavid Howells 642e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 643e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 644260a9803SDavid Howells } 645260a9803SDavid Howells 646260a9803SDavid Howells /* 647e49c7b2fSDavid Howells * Deliver reply data to any operation that returns status and volume sync. 648260a9803SDavid Howells */ 649e49c7b2fSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call) 650260a9803SDavid Howells { 651e49c7b2fSDavid Howells struct afs_operation *op = call->op; 652e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 653260a9803SDavid Howells const __be32 *bp; 654372ee163SDavid Howells int ret; 655260a9803SDavid Howells 656d001648eSDavid Howells ret = afs_transfer_reply(call); 657372ee163SDavid Howells if (ret < 0) 658372ee163SDavid Howells return ret; 659260a9803SDavid Howells 660260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 661260a9803SDavid Howells bp = call->buffer; 662e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 663e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 664260a9803SDavid Howells 665260a9803SDavid Howells _leave(" = 0 [done]"); 666260a9803SDavid Howells return 0; 667260a9803SDavid Howells } 668260a9803SDavid Howells 669260a9803SDavid Howells /* 670e49c7b2fSDavid Howells * FS.RemoveFile operation type 671260a9803SDavid Howells */ 672025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = { 673025db80cSDavid Howells .name = "FS.RemoveFile", 674025db80cSDavid Howells .op = afs_FS_RemoveFile, 675e49c7b2fSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 676260a9803SDavid Howells .destructor = afs_flat_call_destructor, 677260a9803SDavid Howells }; 678260a9803SDavid Howells 679260a9803SDavid Howells /* 680e49c7b2fSDavid Howells * Remove a file. 681260a9803SDavid Howells */ 682e49c7b2fSDavid Howells void afs_fs_remove_file(struct afs_operation *op) 683260a9803SDavid Howells { 684e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 685e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 686260a9803SDavid Howells struct afs_call *call; 687260a9803SDavid Howells size_t namesz, reqsz, padsz; 688260a9803SDavid Howells __be32 *bp; 689260a9803SDavid Howells 690260a9803SDavid Howells _enter(""); 691260a9803SDavid Howells 692e49c7b2fSDavid Howells namesz = name->len; 693260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 694260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 695260a9803SDavid Howells 696e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile, 697025db80cSDavid Howells reqsz, (21 + 6) * 4); 698260a9803SDavid Howells if (!call) 699e49c7b2fSDavid Howells return afs_op_nomem(op); 700260a9803SDavid Howells 701260a9803SDavid Howells /* marshall the parameters */ 702260a9803SDavid Howells bp = call->request; 703e49c7b2fSDavid Howells *bp++ = htonl(FSREMOVEFILE); 704e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 705e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 706e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 707260a9803SDavid Howells *bp++ = htonl(namesz); 708e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 709260a9803SDavid Howells bp = (void *) bp + namesz; 710260a9803SDavid Howells if (padsz > 0) { 711260a9803SDavid Howells memset(bp, 0, padsz); 712260a9803SDavid Howells bp = (void *) bp + padsz; 713260a9803SDavid Howells } 714260a9803SDavid Howells 715e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 716e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 717e49c7b2fSDavid Howells } 718e49c7b2fSDavid Howells 719e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = { 720e49c7b2fSDavid Howells .name = "FS.RemoveDir", 721e49c7b2fSDavid Howells .op = afs_FS_RemoveDir, 722e49c7b2fSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 723e49c7b2fSDavid Howells .destructor = afs_flat_call_destructor, 724e49c7b2fSDavid Howells }; 725e49c7b2fSDavid Howells 726e49c7b2fSDavid Howells /* 727e49c7b2fSDavid Howells * Remove a directory. 728e49c7b2fSDavid Howells */ 729e49c7b2fSDavid Howells void afs_fs_remove_dir(struct afs_operation *op) 730e49c7b2fSDavid Howells { 731e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 732e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 733e49c7b2fSDavid Howells struct afs_call *call; 734e49c7b2fSDavid Howells size_t namesz, reqsz, padsz; 735e49c7b2fSDavid Howells __be32 *bp; 736e49c7b2fSDavid Howells 737e49c7b2fSDavid Howells _enter(""); 738e49c7b2fSDavid Howells 739e49c7b2fSDavid Howells namesz = name->len; 740e49c7b2fSDavid Howells padsz = (4 - (namesz & 3)) & 3; 741e49c7b2fSDavid Howells reqsz = (5 * 4) + namesz + padsz; 742e49c7b2fSDavid Howells 743e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir, 744e49c7b2fSDavid Howells reqsz, (21 + 6) * 4); 745e49c7b2fSDavid Howells if (!call) 746e49c7b2fSDavid Howells return afs_op_nomem(op); 747e49c7b2fSDavid Howells 748e49c7b2fSDavid Howells /* marshall the parameters */ 749e49c7b2fSDavid Howells bp = call->request; 750e49c7b2fSDavid Howells *bp++ = htonl(FSREMOVEDIR); 751e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 752e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 753e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 754e49c7b2fSDavid Howells *bp++ = htonl(namesz); 755e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 756e49c7b2fSDavid Howells bp = (void *) bp + namesz; 757e49c7b2fSDavid Howells if (padsz > 0) { 758e49c7b2fSDavid Howells memset(bp, 0, padsz); 759e49c7b2fSDavid Howells bp = (void *) bp + padsz; 760e49c7b2fSDavid Howells } 761e49c7b2fSDavid Howells 762e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 763e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 764260a9803SDavid Howells } 765260a9803SDavid Howells 766260a9803SDavid Howells /* 767260a9803SDavid Howells * deliver reply data to an FS.Link 768260a9803SDavid Howells */ 769d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call) 770260a9803SDavid Howells { 771e49c7b2fSDavid Howells struct afs_operation *op = call->op; 772e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 773e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 774260a9803SDavid Howells const __be32 *bp; 775372ee163SDavid Howells int ret; 776260a9803SDavid Howells 777d001648eSDavid Howells _enter("{%u}", call->unmarshall); 778260a9803SDavid Howells 779d001648eSDavid Howells ret = afs_transfer_reply(call); 780372ee163SDavid Howells if (ret < 0) 781372ee163SDavid Howells return ret; 782260a9803SDavid Howells 783260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 784260a9803SDavid Howells bp = call->buffer; 785e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 786e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 787e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 788260a9803SDavid Howells 789260a9803SDavid Howells _leave(" = 0 [done]"); 790260a9803SDavid Howells return 0; 791260a9803SDavid Howells } 792260a9803SDavid Howells 793260a9803SDavid Howells /* 794260a9803SDavid Howells * FS.Link operation type 795260a9803SDavid Howells */ 796260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 797260a9803SDavid Howells .name = "FS.Link", 798025db80cSDavid Howells .op = afs_FS_Link, 799260a9803SDavid Howells .deliver = afs_deliver_fs_link, 800260a9803SDavid Howells .destructor = afs_flat_call_destructor, 801260a9803SDavid Howells }; 802260a9803SDavid Howells 803260a9803SDavid Howells /* 804260a9803SDavid Howells * make a hard link 805260a9803SDavid Howells */ 806e49c7b2fSDavid Howells void afs_fs_link(struct afs_operation *op) 807260a9803SDavid Howells { 808e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 809e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 810e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 811260a9803SDavid Howells struct afs_call *call; 812260a9803SDavid Howells size_t namesz, reqsz, padsz; 813260a9803SDavid Howells __be32 *bp; 814260a9803SDavid Howells 815260a9803SDavid Howells _enter(""); 816260a9803SDavid Howells 817e49c7b2fSDavid Howells namesz = name->len; 818260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 819260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 820260a9803SDavid Howells 821e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 822260a9803SDavid Howells if (!call) 823e49c7b2fSDavid Howells return afs_op_nomem(op); 824260a9803SDavid Howells 825260a9803SDavid Howells /* marshall the parameters */ 826260a9803SDavid Howells bp = call->request; 827260a9803SDavid Howells *bp++ = htonl(FSLINK); 828e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 829e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 830e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 831260a9803SDavid Howells *bp++ = htonl(namesz); 832e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 833260a9803SDavid Howells bp = (void *) bp + namesz; 834260a9803SDavid Howells if (padsz > 0) { 835260a9803SDavid Howells memset(bp, 0, padsz); 836260a9803SDavid Howells bp = (void *) bp + padsz; 837260a9803SDavid Howells } 838e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 839e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 840e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 841260a9803SDavid Howells 842e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &vp->fid, name); 843e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 844260a9803SDavid Howells } 845260a9803SDavid Howells 846260a9803SDavid Howells /* 847260a9803SDavid Howells * deliver reply data to an FS.Symlink 848260a9803SDavid Howells */ 849d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call) 850260a9803SDavid Howells { 851e49c7b2fSDavid Howells struct afs_operation *op = call->op; 852e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 853e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 854260a9803SDavid Howells const __be32 *bp; 855372ee163SDavid Howells int ret; 856260a9803SDavid Howells 857d001648eSDavid Howells _enter("{%u}", call->unmarshall); 858260a9803SDavid Howells 859d001648eSDavid Howells ret = afs_transfer_reply(call); 860372ee163SDavid Howells if (ret < 0) 861372ee163SDavid Howells return ret; 862260a9803SDavid Howells 863260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 864260a9803SDavid Howells bp = call->buffer; 865e49c7b2fSDavid Howells xdr_decode_AFSFid(&bp, &vp->fid); 866e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 867e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb); 868e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 869260a9803SDavid Howells 870260a9803SDavid Howells _leave(" = 0 [done]"); 871260a9803SDavid Howells return 0; 872260a9803SDavid Howells } 873260a9803SDavid Howells 874260a9803SDavid Howells /* 875260a9803SDavid Howells * FS.Symlink operation type 876260a9803SDavid Howells */ 877260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 878260a9803SDavid Howells .name = "FS.Symlink", 879025db80cSDavid Howells .op = afs_FS_Symlink, 880260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 881260a9803SDavid Howells .destructor = afs_flat_call_destructor, 882260a9803SDavid Howells }; 883260a9803SDavid Howells 884260a9803SDavid Howells /* 885260a9803SDavid Howells * create a symbolic link 886260a9803SDavid Howells */ 887e49c7b2fSDavid Howells void afs_fs_symlink(struct afs_operation *op) 888260a9803SDavid Howells { 889e49c7b2fSDavid Howells const struct qstr *name = &op->dentry->d_name; 890e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 891260a9803SDavid Howells struct afs_call *call; 892260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 893260a9803SDavid Howells __be32 *bp; 894260a9803SDavid Howells 895260a9803SDavid Howells _enter(""); 896260a9803SDavid Howells 897e49c7b2fSDavid Howells namesz = name->len; 898260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 899260a9803SDavid Howells 900e49c7b2fSDavid Howells c_namesz = strlen(op->create.symlink); 901260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 902260a9803SDavid Howells 903260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 904260a9803SDavid Howells 905e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz, 906260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 907260a9803SDavid Howells if (!call) 908e49c7b2fSDavid Howells return afs_op_nomem(op); 909260a9803SDavid Howells 910260a9803SDavid Howells /* marshall the parameters */ 911260a9803SDavid Howells bp = call->request; 912260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 913e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 914e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 915e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 916260a9803SDavid Howells *bp++ = htonl(namesz); 917e49c7b2fSDavid Howells memcpy(bp, name->name, namesz); 918260a9803SDavid Howells bp = (void *) bp + namesz; 919260a9803SDavid Howells if (padsz > 0) { 920260a9803SDavid Howells memset(bp, 0, padsz); 921260a9803SDavid Howells bp = (void *) bp + padsz; 922260a9803SDavid Howells } 923260a9803SDavid Howells *bp++ = htonl(c_namesz); 924e49c7b2fSDavid Howells memcpy(bp, op->create.symlink, c_namesz); 925260a9803SDavid Howells bp = (void *) bp + c_namesz; 926260a9803SDavid Howells if (c_padsz > 0) { 927260a9803SDavid Howells memset(bp, 0, c_padsz); 928260a9803SDavid Howells bp = (void *) bp + c_padsz; 929260a9803SDavid Howells } 930ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 931e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 932260a9803SDavid Howells *bp++ = 0; /* owner */ 933260a9803SDavid Howells *bp++ = 0; /* group */ 934260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 935260a9803SDavid Howells *bp++ = 0; /* segment size */ 936260a9803SDavid Howells 937e49c7b2fSDavid Howells trace_afs_make_fs_call1(call, &dvp->fid, name); 938e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 939260a9803SDavid Howells } 940260a9803SDavid Howells 941260a9803SDavid Howells /* 942260a9803SDavid Howells * deliver reply data to an FS.Rename 943260a9803SDavid Howells */ 944d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call) 945260a9803SDavid Howells { 946e49c7b2fSDavid Howells struct afs_operation *op = call->op; 947e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 948e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 949260a9803SDavid Howells const __be32 *bp; 950372ee163SDavid Howells int ret; 951260a9803SDavid Howells 952d001648eSDavid Howells ret = afs_transfer_reply(call); 953372ee163SDavid Howells if (ret < 0) 954372ee163SDavid Howells return ret; 955260a9803SDavid Howells 95638355eecSDavid Howells bp = call->buffer; 957b98f0ec9SDavid Howells /* If the two dirs are the same, we have two copies of the same status 958b98f0ec9SDavid Howells * report, so we just decode it twice. 959b98f0ec9SDavid Howells */ 960e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb); 961e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb); 962e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 963260a9803SDavid Howells 964260a9803SDavid Howells _leave(" = 0 [done]"); 965260a9803SDavid Howells return 0; 966260a9803SDavid Howells } 967260a9803SDavid Howells 968260a9803SDavid Howells /* 969260a9803SDavid Howells * FS.Rename operation type 970260a9803SDavid Howells */ 971260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 972260a9803SDavid Howells .name = "FS.Rename", 973025db80cSDavid Howells .op = afs_FS_Rename, 974260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 975260a9803SDavid Howells .destructor = afs_flat_call_destructor, 976260a9803SDavid Howells }; 977260a9803SDavid Howells 978260a9803SDavid Howells /* 979a58823acSDavid Howells * Rename/move a file or directory. 980260a9803SDavid Howells */ 981e49c7b2fSDavid Howells void afs_fs_rename(struct afs_operation *op) 982260a9803SDavid Howells { 983e49c7b2fSDavid Howells struct afs_vnode_param *orig_dvp = &op->file[0]; 984e49c7b2fSDavid Howells struct afs_vnode_param *new_dvp = &op->file[1]; 985e49c7b2fSDavid Howells const struct qstr *orig_name = &op->dentry->d_name; 986e49c7b2fSDavid Howells const struct qstr *new_name = &op->dentry_2->d_name; 987260a9803SDavid Howells struct afs_call *call; 988260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 989260a9803SDavid Howells __be32 *bp; 990260a9803SDavid Howells 991260a9803SDavid Howells _enter(""); 992260a9803SDavid Howells 993e49c7b2fSDavid Howells o_namesz = orig_name->len; 994260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 995260a9803SDavid Howells 996e49c7b2fSDavid Howells n_namesz = new_name->len; 997260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 998260a9803SDavid Howells 999260a9803SDavid Howells reqsz = (4 * 4) + 1000260a9803SDavid Howells 4 + o_namesz + o_padsz + 1001260a9803SDavid Howells (3 * 4) + 1002260a9803SDavid Howells 4 + n_namesz + n_padsz; 1003260a9803SDavid Howells 1004e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1005260a9803SDavid Howells if (!call) 1006e49c7b2fSDavid Howells return afs_op_nomem(op); 1007260a9803SDavid Howells 1008260a9803SDavid Howells /* marshall the parameters */ 1009260a9803SDavid Howells bp = call->request; 1010260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1011e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.vid); 1012e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.vnode); 1013e49c7b2fSDavid Howells *bp++ = htonl(orig_dvp->fid.unique); 1014260a9803SDavid Howells *bp++ = htonl(o_namesz); 1015e49c7b2fSDavid Howells memcpy(bp, orig_name->name, o_namesz); 1016260a9803SDavid Howells bp = (void *) bp + o_namesz; 1017260a9803SDavid Howells if (o_padsz > 0) { 1018260a9803SDavid Howells memset(bp, 0, o_padsz); 1019260a9803SDavid Howells bp = (void *) bp + o_padsz; 1020260a9803SDavid Howells } 1021260a9803SDavid Howells 1022e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.vid); 1023e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.vnode); 1024e49c7b2fSDavid Howells *bp++ = htonl(new_dvp->fid.unique); 1025260a9803SDavid Howells *bp++ = htonl(n_namesz); 1026e49c7b2fSDavid Howells memcpy(bp, new_name->name, n_namesz); 1027260a9803SDavid Howells bp = (void *) bp + n_namesz; 1028260a9803SDavid Howells if (n_padsz > 0) { 1029260a9803SDavid Howells memset(bp, 0, n_padsz); 1030260a9803SDavid Howells bp = (void *) bp + n_padsz; 1031260a9803SDavid Howells } 1032260a9803SDavid Howells 1033e49c7b2fSDavid Howells trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name); 1034e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1035260a9803SDavid Howells } 103631143d5dSDavid Howells 103731143d5dSDavid Howells /* 1038e49c7b2fSDavid Howells * Deliver reply data to FS.StoreData or FS.StoreStatus 103931143d5dSDavid Howells */ 1040d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call) 104131143d5dSDavid Howells { 1042e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1043e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 104431143d5dSDavid Howells const __be32 *bp; 1045372ee163SDavid Howells int ret; 104631143d5dSDavid Howells 1047d001648eSDavid Howells _enter(""); 104831143d5dSDavid Howells 1049d001648eSDavid Howells ret = afs_transfer_reply(call); 1050372ee163SDavid Howells if (ret < 0) 1051372ee163SDavid Howells return ret; 105231143d5dSDavid Howells 105331143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 105431143d5dSDavid Howells bp = call->buffer; 1055e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 1056e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 105731143d5dSDavid Howells 105831143d5dSDavid Howells _leave(" = 0 [done]"); 105931143d5dSDavid Howells return 0; 106031143d5dSDavid Howells } 106131143d5dSDavid Howells 106231143d5dSDavid Howells /* 106331143d5dSDavid Howells * FS.StoreData operation type 106431143d5dSDavid Howells */ 106531143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 106631143d5dSDavid Howells .name = "FS.StoreData", 1067025db80cSDavid Howells .op = afs_FS_StoreData, 106831143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 106931143d5dSDavid Howells .destructor = afs_flat_call_destructor, 107031143d5dSDavid Howells }; 107131143d5dSDavid Howells 1072b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1073b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1074025db80cSDavid Howells .op = afs_FS_StoreData64, 1075b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1076b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1077b9b1f8d5SDavid Howells }; 1078b9b1f8d5SDavid Howells 1079b9b1f8d5SDavid Howells /* 1080b9b1f8d5SDavid Howells * store a set of pages to a very large file 1081b9b1f8d5SDavid Howells */ 1082e49c7b2fSDavid Howells static void afs_fs_store_data64(struct afs_operation *op, 1083e49c7b2fSDavid Howells loff_t pos, loff_t size, loff_t i_size) 1084b9b1f8d5SDavid Howells { 1085e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1086b9b1f8d5SDavid Howells struct afs_call *call; 1087b9b1f8d5SDavid Howells __be32 *bp; 1088b9b1f8d5SDavid Howells 10893b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1090e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 1091b9b1f8d5SDavid Howells 1092e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64, 1093b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1094b9b1f8d5SDavid Howells (21 + 6) * 4); 1095b9b1f8d5SDavid Howells if (!call) 1096e49c7b2fSDavid Howells return afs_op_nomem(op); 1097b9b1f8d5SDavid Howells 1098b9b1f8d5SDavid Howells call->send_pages = true; 1099b9b1f8d5SDavid Howells 1100b9b1f8d5SDavid Howells /* marshall the parameters */ 1101b9b1f8d5SDavid Howells bp = call->request; 1102b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1103e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1104e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1105e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1106b9b1f8d5SDavid Howells 1107ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1108e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 1109b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1110b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1111b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1112b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1113b9b1f8d5SDavid Howells 1114e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(pos)); 1115e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(pos)); 1116e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(size)); 1117e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(size)); 1118e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(i_size)); 1119e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(i_size)); 1120b9b1f8d5SDavid Howells 1121e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1122e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1123b9b1f8d5SDavid Howells } 1124b9b1f8d5SDavid Howells 112531143d5dSDavid Howells /* 112631143d5dSDavid Howells * store a set of pages 112731143d5dSDavid Howells */ 1128e49c7b2fSDavid Howells void afs_fs_store_data(struct afs_operation *op) 112931143d5dSDavid Howells { 1130e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 113131143d5dSDavid Howells struct afs_call *call; 113231143d5dSDavid Howells loff_t size, pos, i_size; 113331143d5dSDavid Howells __be32 *bp; 113431143d5dSDavid Howells 11353b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1136e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 113731143d5dSDavid Howells 1138e49c7b2fSDavid Howells size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset; 1139e49c7b2fSDavid Howells if (op->store.first != op->store.last) 1140e49c7b2fSDavid Howells size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT; 1141e49c7b2fSDavid Howells pos = (loff_t)op->store.first << PAGE_SHIFT; 1142e49c7b2fSDavid Howells pos += op->store.first_offset; 114331143d5dSDavid Howells 1144e49c7b2fSDavid Howells i_size = i_size_read(&vp->vnode->vfs_inode); 114531143d5dSDavid Howells if (pos + size > i_size) 114631143d5dSDavid Howells i_size = size + pos; 114731143d5dSDavid Howells 114831143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 114931143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 115031143d5dSDavid Howells (unsigned long long) i_size); 115131143d5dSDavid Howells 1152e49c7b2fSDavid Howells if (upper_32_bits(pos) || upper_32_bits(i_size) || upper_32_bits(size) || 1153e49c7b2fSDavid Howells upper_32_bits(pos + size)) 1154e49c7b2fSDavid Howells return afs_fs_store_data64(op, pos, size, i_size); 115531143d5dSDavid Howells 1156e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData, 115731143d5dSDavid Howells (4 + 6 + 3) * 4, 115831143d5dSDavid Howells (21 + 6) * 4); 115931143d5dSDavid Howells if (!call) 1160e49c7b2fSDavid Howells return afs_op_nomem(op); 116131143d5dSDavid Howells 116231143d5dSDavid Howells call->send_pages = true; 116331143d5dSDavid Howells 116431143d5dSDavid Howells /* marshall the parameters */ 116531143d5dSDavid Howells bp = call->request; 116631143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 1167e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1168e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1169e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 117031143d5dSDavid Howells 1171ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1172e49c7b2fSDavid Howells *bp++ = htonl(op->mtime.tv_sec); /* mtime */ 117331143d5dSDavid Howells *bp++ = 0; /* owner */ 117431143d5dSDavid Howells *bp++ = 0; /* group */ 117531143d5dSDavid Howells *bp++ = 0; /* unix mode */ 117631143d5dSDavid Howells *bp++ = 0; /* segment size */ 117731143d5dSDavid Howells 1178e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(pos)); 1179e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(size)); 1180e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(i_size)); 118131143d5dSDavid Howells 1182e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1183e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 118431143d5dSDavid Howells } 118531143d5dSDavid Howells 118631143d5dSDavid Howells /* 118731143d5dSDavid Howells * FS.StoreStatus operation type 118831143d5dSDavid Howells */ 118931143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 119031143d5dSDavid Howells .name = "FS.StoreStatus", 1191025db80cSDavid Howells .op = afs_FS_StoreStatus, 1192e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 119331143d5dSDavid Howells .destructor = afs_flat_call_destructor, 119431143d5dSDavid Howells }; 119531143d5dSDavid Howells 119631143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 119731143d5dSDavid Howells .name = "FS.StoreData", 1198025db80cSDavid Howells .op = afs_FS_StoreData, 1199e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 120031143d5dSDavid Howells .destructor = afs_flat_call_destructor, 120131143d5dSDavid Howells }; 120231143d5dSDavid Howells 1203b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1204b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1205025db80cSDavid Howells .op = afs_FS_StoreData64, 1206e49c7b2fSDavid Howells .deliver = afs_deliver_fs_store_data, 1207b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1208b9b1f8d5SDavid Howells }; 1209b9b1f8d5SDavid Howells 1210b9b1f8d5SDavid Howells /* 1211b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1212b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1213b9b1f8d5SDavid Howells */ 1214e49c7b2fSDavid Howells static void afs_fs_setattr_size64(struct afs_operation *op) 1215b9b1f8d5SDavid Howells { 1216e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1217b9b1f8d5SDavid Howells struct afs_call *call; 1218e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 1219b9b1f8d5SDavid Howells __be32 *bp; 1220b9b1f8d5SDavid Howells 12213b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1222e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 1223b9b1f8d5SDavid Howells 1224b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1225b9b1f8d5SDavid Howells 1226e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status, 1227b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1228b9b1f8d5SDavid Howells (21 + 6) * 4); 1229b9b1f8d5SDavid Howells if (!call) 1230e49c7b2fSDavid Howells return afs_op_nomem(op); 1231b9b1f8d5SDavid Howells 1232b9b1f8d5SDavid Howells /* marshall the parameters */ 1233b9b1f8d5SDavid Howells bp = call->request; 1234b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1235e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1236e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1237e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1238b9b1f8d5SDavid Howells 1239b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1240b9b1f8d5SDavid Howells 1241e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(attr->ia_size)); /* position of start of write */ 1242e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(attr->ia_size)); 1243b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1244b9b1f8d5SDavid Howells *bp++ = 0; 1245e49c7b2fSDavid Howells *bp++ = htonl(upper_32_bits(attr->ia_size)); /* new file length */ 1246e49c7b2fSDavid Howells *bp++ = htonl(lower_32_bits(attr->ia_size)); 1247b9b1f8d5SDavid Howells 1248e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1249e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1250b9b1f8d5SDavid Howells } 1251b9b1f8d5SDavid Howells 125231143d5dSDavid Howells /* 125331143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 125431143d5dSDavid Howells * so as to alter the file size also 125531143d5dSDavid Howells */ 1256e49c7b2fSDavid Howells static void afs_fs_setattr_size(struct afs_operation *op) 125731143d5dSDavid Howells { 1258e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 125931143d5dSDavid Howells struct afs_call *call; 1260e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 126131143d5dSDavid Howells __be32 *bp; 126231143d5dSDavid Howells 12633b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1264e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 126531143d5dSDavid Howells 126631143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1267e49c7b2fSDavid Howells if (upper_32_bits(attr->ia_size)) 1268e49c7b2fSDavid Howells return afs_fs_setattr_size64(op); 126931143d5dSDavid Howells 1270e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status, 127131143d5dSDavid Howells (4 + 6 + 3) * 4, 127231143d5dSDavid Howells (21 + 6) * 4); 127331143d5dSDavid Howells if (!call) 1274e49c7b2fSDavid Howells return afs_op_nomem(op); 127531143d5dSDavid Howells 127631143d5dSDavid Howells /* marshall the parameters */ 127731143d5dSDavid Howells bp = call->request; 127831143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 1279e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1280e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1281e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 128231143d5dSDavid Howells 128331143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 128431143d5dSDavid Howells 12858c7ae38dSDavid Howells *bp++ = htonl(attr->ia_size); /* position of start of write */ 128631143d5dSDavid Howells *bp++ = 0; /* size of write */ 128731143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 128831143d5dSDavid Howells 1289e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1290e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 129131143d5dSDavid Howells } 129231143d5dSDavid Howells 129331143d5dSDavid Howells /* 129431143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 129531143d5dSDavid Howells * size, and FS.StoreStatus otherwise 129631143d5dSDavid Howells */ 1297e49c7b2fSDavid Howells void afs_fs_setattr(struct afs_operation *op) 129831143d5dSDavid Howells { 1299e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 130031143d5dSDavid Howells struct afs_call *call; 1301e49c7b2fSDavid Howells struct iattr *attr = op->setattr.attr; 130231143d5dSDavid Howells __be32 *bp; 130331143d5dSDavid Howells 130431143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 1305e49c7b2fSDavid Howells return afs_fs_setattr_size(op); 130631143d5dSDavid Howells 13073b6492dfSDavid Howells _enter(",%x,{%llx:%llu},,", 1308e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 130931143d5dSDavid Howells 1310e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus, 131131143d5dSDavid Howells (4 + 6) * 4, 131231143d5dSDavid Howells (21 + 6) * 4); 131331143d5dSDavid Howells if (!call) 1314e49c7b2fSDavid Howells return afs_op_nomem(op); 131531143d5dSDavid Howells 131631143d5dSDavid Howells /* marshall the parameters */ 131731143d5dSDavid Howells bp = call->request; 131831143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 1319e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1320e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1321e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 132231143d5dSDavid Howells 1323e49c7b2fSDavid Howells xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr); 132431143d5dSDavid Howells 1325e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1326e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 132731143d5dSDavid Howells } 132845222b9eSDavid Howells 132945222b9eSDavid Howells /* 133045222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 133145222b9eSDavid Howells */ 1332d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call) 133345222b9eSDavid Howells { 1334e49c7b2fSDavid Howells struct afs_operation *op = call->op; 133545222b9eSDavid Howells const __be32 *bp; 133645222b9eSDavid Howells char *p; 133712bdcf33SDavid Howells u32 size; 133845222b9eSDavid Howells int ret; 133945222b9eSDavid Howells 1340d001648eSDavid Howells _enter("{%u}", call->unmarshall); 134145222b9eSDavid Howells 134245222b9eSDavid Howells switch (call->unmarshall) { 134345222b9eSDavid Howells case 0: 134445222b9eSDavid Howells call->unmarshall++; 134512bdcf33SDavid Howells afs_extract_to_buf(call, 12 * 4); 1346df561f66SGustavo A. R. Silva fallthrough; 134745222b9eSDavid Howells 134829881608SGustavo A. R. Silva /* extract the returned status record */ 134945222b9eSDavid Howells case 1: 135045222b9eSDavid Howells _debug("extract status"); 135112bdcf33SDavid Howells ret = afs_extract_data(call, true); 1352372ee163SDavid Howells if (ret < 0) 1353372ee163SDavid Howells return ret; 135445222b9eSDavid Howells 135545222b9eSDavid Howells bp = call->buffer; 1356e49c7b2fSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs); 135745222b9eSDavid Howells call->unmarshall++; 135812bdcf33SDavid Howells afs_extract_to_tmp(call); 1359df561f66SGustavo A. R. Silva fallthrough; 136045222b9eSDavid Howells 136129881608SGustavo A. R. Silva /* extract the volume name length */ 136245222b9eSDavid Howells case 2: 136312bdcf33SDavid Howells ret = afs_extract_data(call, true); 1364372ee163SDavid Howells if (ret < 0) 1365372ee163SDavid Howells return ret; 136645222b9eSDavid Howells 136745222b9eSDavid Howells call->count = ntohl(call->tmp); 136845222b9eSDavid Howells _debug("volname length: %u", call->count); 136945222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 13707126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_volname_len); 137112bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1372ffba718eSDavid Howells afs_extract_to_buf(call, size); 137345222b9eSDavid Howells call->unmarshall++; 1374df561f66SGustavo A. R. Silva fallthrough; 137545222b9eSDavid Howells 137629881608SGustavo A. R. Silva /* extract the volume name */ 137745222b9eSDavid Howells case 3: 137845222b9eSDavid Howells _debug("extract volname"); 137912bdcf33SDavid Howells ret = afs_extract_data(call, true); 1380372ee163SDavid Howells if (ret < 0) 1381372ee163SDavid Howells return ret; 138245222b9eSDavid Howells 1383ffba718eSDavid Howells p = call->buffer; 138445222b9eSDavid Howells p[call->count] = 0; 138545222b9eSDavid Howells _debug("volname '%s'", p); 138612bdcf33SDavid Howells afs_extract_to_tmp(call); 138745222b9eSDavid Howells call->unmarshall++; 1388df561f66SGustavo A. R. Silva fallthrough; 138945222b9eSDavid Howells 139029881608SGustavo A. R. Silva /* extract the offline message length */ 139112bdcf33SDavid Howells case 4: 139212bdcf33SDavid Howells ret = afs_extract_data(call, true); 1393372ee163SDavid Howells if (ret < 0) 1394372ee163SDavid Howells return ret; 139545222b9eSDavid Howells 139645222b9eSDavid Howells call->count = ntohl(call->tmp); 139745222b9eSDavid Howells _debug("offline msg length: %u", call->count); 139845222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 13997126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_offline_msg_len); 140012bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1401ffba718eSDavid Howells afs_extract_to_buf(call, size); 140245222b9eSDavid Howells call->unmarshall++; 1403df561f66SGustavo A. R. Silva fallthrough; 140445222b9eSDavid Howells 140529881608SGustavo A. R. Silva /* extract the offline message */ 140612bdcf33SDavid Howells case 5: 140745222b9eSDavid Howells _debug("extract offline"); 140812bdcf33SDavid Howells ret = afs_extract_data(call, true); 1409372ee163SDavid Howells if (ret < 0) 1410372ee163SDavid Howells return ret; 141145222b9eSDavid Howells 1412ffba718eSDavid Howells p = call->buffer; 141345222b9eSDavid Howells p[call->count] = 0; 141445222b9eSDavid Howells _debug("offline '%s'", p); 141545222b9eSDavid Howells 141612bdcf33SDavid Howells afs_extract_to_tmp(call); 141745222b9eSDavid Howells call->unmarshall++; 1418df561f66SGustavo A. R. Silva fallthrough; 141945222b9eSDavid Howells 142029881608SGustavo A. R. Silva /* extract the message of the day length */ 142112bdcf33SDavid Howells case 6: 142212bdcf33SDavid Howells ret = afs_extract_data(call, true); 1423372ee163SDavid Howells if (ret < 0) 1424372ee163SDavid Howells return ret; 142545222b9eSDavid Howells 142645222b9eSDavid Howells call->count = ntohl(call->tmp); 142745222b9eSDavid Howells _debug("motd length: %u", call->count); 142845222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 14297126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_motd_len); 143012bdcf33SDavid Howells size = (call->count + 3) & ~3; /* It's padded */ 1431ffba718eSDavid Howells afs_extract_to_buf(call, size); 143245222b9eSDavid Howells call->unmarshall++; 1433df561f66SGustavo A. R. Silva fallthrough; 143445222b9eSDavid Howells 143529881608SGustavo A. R. Silva /* extract the message of the day */ 143612bdcf33SDavid Howells case 7: 143745222b9eSDavid Howells _debug("extract motd"); 143812bdcf33SDavid Howells ret = afs_extract_data(call, false); 1439372ee163SDavid Howells if (ret < 0) 1440372ee163SDavid Howells return ret; 144145222b9eSDavid Howells 1442ffba718eSDavid Howells p = call->buffer; 144345222b9eSDavid Howells p[call->count] = 0; 144445222b9eSDavid Howells _debug("motd '%s'", p); 144545222b9eSDavid Howells 144645222b9eSDavid Howells call->unmarshall++; 144745222b9eSDavid Howells 144812bdcf33SDavid Howells case 8: 144945222b9eSDavid Howells break; 145045222b9eSDavid Howells } 145145222b9eSDavid Howells 145245222b9eSDavid Howells _leave(" = 0 [done]"); 145345222b9eSDavid Howells return 0; 145445222b9eSDavid Howells } 145545222b9eSDavid Howells 145645222b9eSDavid Howells /* 145745222b9eSDavid Howells * FS.GetVolumeStatus operation type 145845222b9eSDavid Howells */ 145945222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 146045222b9eSDavid Howells .name = "FS.GetVolumeStatus", 1461025db80cSDavid Howells .op = afs_FS_GetVolumeStatus, 146245222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 1463ffba718eSDavid Howells .destructor = afs_flat_call_destructor, 146445222b9eSDavid Howells }; 146545222b9eSDavid Howells 146645222b9eSDavid Howells /* 146745222b9eSDavid Howells * fetch the status of a volume 146845222b9eSDavid Howells */ 1469e49c7b2fSDavid Howells void afs_fs_get_volume_status(struct afs_operation *op) 147045222b9eSDavid Howells { 1471e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 147245222b9eSDavid Howells struct afs_call *call; 147345222b9eSDavid Howells __be32 *bp; 147445222b9eSDavid Howells 147545222b9eSDavid Howells _enter(""); 147645222b9eSDavid Howells 1477e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4, 1478ffba718eSDavid Howells max(12 * 4, AFSOPAQUEMAX + 1)); 1479ffba718eSDavid Howells if (!call) 1480e49c7b2fSDavid Howells return afs_op_nomem(op); 148145222b9eSDavid Howells 148245222b9eSDavid Howells /* marshall the parameters */ 148345222b9eSDavid Howells bp = call->request; 148445222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 1485e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 148645222b9eSDavid Howells 1487e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1488e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 148945222b9eSDavid Howells } 1490e8d6c554SDavid Howells 1491e8d6c554SDavid Howells /* 1492e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1493e8d6c554SDavid Howells */ 1494d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call) 1495e8d6c554SDavid Howells { 1496e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1497e8d6c554SDavid Howells const __be32 *bp; 1498372ee163SDavid Howells int ret; 1499e8d6c554SDavid Howells 1500d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1501e8d6c554SDavid Howells 1502d001648eSDavid Howells ret = afs_transfer_reply(call); 1503372ee163SDavid Howells if (ret < 0) 1504372ee163SDavid Howells return ret; 1505e8d6c554SDavid Howells 1506e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1507e8d6c554SDavid Howells bp = call->buffer; 1508e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 1509e8d6c554SDavid Howells 1510e8d6c554SDavid Howells _leave(" = 0 [done]"); 1511e8d6c554SDavid Howells return 0; 1512e8d6c554SDavid Howells } 1513e8d6c554SDavid Howells 1514e8d6c554SDavid Howells /* 1515e8d6c554SDavid Howells * FS.SetLock operation type 1516e8d6c554SDavid Howells */ 1517e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1518e8d6c554SDavid Howells .name = "FS.SetLock", 1519025db80cSDavid Howells .op = afs_FS_SetLock, 1520e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1521a690f60aSDavid Howells .done = afs_lock_op_done, 1522e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1523e8d6c554SDavid Howells }; 1524e8d6c554SDavid Howells 1525e8d6c554SDavid Howells /* 1526e8d6c554SDavid Howells * FS.ExtendLock operation type 1527e8d6c554SDavid Howells */ 1528e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1529e8d6c554SDavid Howells .name = "FS.ExtendLock", 1530025db80cSDavid Howells .op = afs_FS_ExtendLock, 1531e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1532a690f60aSDavid Howells .done = afs_lock_op_done, 1533e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1534e8d6c554SDavid Howells }; 1535e8d6c554SDavid Howells 1536e8d6c554SDavid Howells /* 1537e8d6c554SDavid Howells * FS.ReleaseLock operation type 1538e8d6c554SDavid Howells */ 1539e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1540e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1541025db80cSDavid Howells .op = afs_FS_ReleaseLock, 1542e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1543e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1544e8d6c554SDavid Howells }; 1545e8d6c554SDavid Howells 1546e8d6c554SDavid Howells /* 1547d2ddc776SDavid Howells * Set a lock on a file 1548e8d6c554SDavid Howells */ 1549e49c7b2fSDavid Howells void afs_fs_set_lock(struct afs_operation *op) 1550e8d6c554SDavid Howells { 1551e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1552e8d6c554SDavid Howells struct afs_call *call; 1553e8d6c554SDavid Howells __be32 *bp; 1554e8d6c554SDavid Howells 1555e8d6c554SDavid Howells _enter(""); 1556e8d6c554SDavid Howells 1557e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4); 1558e8d6c554SDavid Howells if (!call) 1559e49c7b2fSDavid Howells return afs_op_nomem(op); 1560e8d6c554SDavid Howells 1561e8d6c554SDavid Howells /* marshall the parameters */ 1562e8d6c554SDavid Howells bp = call->request; 1563e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1564e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1565e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1566e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1567e49c7b2fSDavid Howells *bp++ = htonl(op->lock.type); 1568e8d6c554SDavid Howells 1569e49c7b2fSDavid Howells trace_afs_make_fs_calli(call, &vp->fid, op->lock.type); 1570e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1571e8d6c554SDavid Howells } 1572e8d6c554SDavid Howells 1573e8d6c554SDavid Howells /* 1574e8d6c554SDavid Howells * extend a lock on a file 1575e8d6c554SDavid Howells */ 1576e49c7b2fSDavid Howells void afs_fs_extend_lock(struct afs_operation *op) 1577e8d6c554SDavid Howells { 1578e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1579e8d6c554SDavid Howells struct afs_call *call; 1580e8d6c554SDavid Howells __be32 *bp; 1581e8d6c554SDavid Howells 1582e8d6c554SDavid Howells _enter(""); 1583e8d6c554SDavid Howells 1584e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); 1585e8d6c554SDavid Howells if (!call) 1586e49c7b2fSDavid Howells return afs_op_nomem(op); 1587e8d6c554SDavid Howells 1588e8d6c554SDavid Howells /* marshall the parameters */ 1589e8d6c554SDavid Howells bp = call->request; 1590e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1591e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1592e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1593e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1594e8d6c554SDavid Howells 1595e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1596e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1597e8d6c554SDavid Howells } 1598e8d6c554SDavid Howells 1599e8d6c554SDavid Howells /* 1600e8d6c554SDavid Howells * release a lock on a file 1601e8d6c554SDavid Howells */ 1602e49c7b2fSDavid Howells void afs_fs_release_lock(struct afs_operation *op) 1603e8d6c554SDavid Howells { 1604e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1605e8d6c554SDavid Howells struct afs_call *call; 1606e8d6c554SDavid Howells __be32 *bp; 1607e8d6c554SDavid Howells 1608e8d6c554SDavid Howells _enter(""); 1609e8d6c554SDavid Howells 1610e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1611e8d6c554SDavid Howells if (!call) 1612e49c7b2fSDavid Howells return afs_op_nomem(op); 1613e8d6c554SDavid Howells 1614e8d6c554SDavid Howells /* marshall the parameters */ 1615e8d6c554SDavid Howells bp = call->request; 1616e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1617e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1618e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1619e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1620e8d6c554SDavid Howells 1621e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1622e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 1623c435ee34SDavid Howells } 1624c435ee34SDavid Howells 1625c435ee34SDavid Howells /* 1626c435ee34SDavid Howells * Deliver reply data to an FS.GiveUpAllCallBacks operation. 1627c435ee34SDavid Howells */ 1628c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call) 1629c435ee34SDavid Howells { 1630c435ee34SDavid Howells return afs_transfer_reply(call); 1631c435ee34SDavid Howells } 1632c435ee34SDavid Howells 1633c435ee34SDavid Howells /* 1634c435ee34SDavid Howells * FS.GiveUpAllCallBacks operation type 1635c435ee34SDavid Howells */ 1636c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = { 1637c435ee34SDavid Howells .name = "FS.GiveUpAllCallBacks", 1638025db80cSDavid Howells .op = afs_FS_GiveUpAllCallBacks, 1639c435ee34SDavid Howells .deliver = afs_deliver_fs_give_up_all_callbacks, 1640c435ee34SDavid Howells .destructor = afs_flat_call_destructor, 1641c435ee34SDavid Howells }; 1642c435ee34SDavid Howells 1643c435ee34SDavid Howells /* 1644c435ee34SDavid Howells * Flush all the callbacks we have on a server. 1645c435ee34SDavid Howells */ 1646d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net, 1647d2ddc776SDavid Howells struct afs_server *server, 16488b2a464cSDavid Howells struct afs_addr_cursor *ac, 1649d2ddc776SDavid Howells struct key *key) 1650c435ee34SDavid Howells { 1651c435ee34SDavid Howells struct afs_call *call; 1652c435ee34SDavid Howells __be32 *bp; 1653c435ee34SDavid Howells 1654c435ee34SDavid Howells _enter(""); 1655c435ee34SDavid Howells 1656d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0); 1657c435ee34SDavid Howells if (!call) 1658c435ee34SDavid Howells return -ENOMEM; 1659c435ee34SDavid Howells 1660c435ee34SDavid Howells call->key = key; 1661c435ee34SDavid Howells 1662c435ee34SDavid Howells /* marshall the parameters */ 1663c435ee34SDavid Howells bp = call->request; 1664c435ee34SDavid Howells *bp++ = htonl(FSGIVEUPALLCALLBACKS); 1665c435ee34SDavid Howells 1666977e5f8eSDavid Howells call->server = afs_use_server(server, afs_server_trace_give_up_cb); 16670b9bf381SDavid Howells afs_make_call(ac, call, GFP_NOFS); 16680b9bf381SDavid Howells return afs_wait_for_call_to_complete(call, ac); 1669d2ddc776SDavid Howells } 1670d2ddc776SDavid Howells 1671d2ddc776SDavid Howells /* 1672d2ddc776SDavid Howells * Deliver reply data to an FS.GetCapabilities operation. 1673d2ddc776SDavid Howells */ 1674d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call) 1675d2ddc776SDavid Howells { 1676d2ddc776SDavid Howells u32 count; 1677d2ddc776SDavid Howells int ret; 1678d2ddc776SDavid Howells 1679fc276122SDavid Howells _enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter)); 1680d2ddc776SDavid Howells 1681d2ddc776SDavid Howells switch (call->unmarshall) { 1682d2ddc776SDavid Howells case 0: 168312bdcf33SDavid Howells afs_extract_to_tmp(call); 1684d2ddc776SDavid Howells call->unmarshall++; 1685df561f66SGustavo A. R. Silva fallthrough; 1686d2ddc776SDavid Howells 168729881608SGustavo A. R. Silva /* Extract the capabilities word count */ 1688d2ddc776SDavid Howells case 1: 168912bdcf33SDavid Howells ret = afs_extract_data(call, true); 1690d2ddc776SDavid Howells if (ret < 0) 1691d2ddc776SDavid Howells return ret; 1692d2ddc776SDavid Howells 1693d2ddc776SDavid Howells count = ntohl(call->tmp); 1694d2ddc776SDavid Howells 1695d2ddc776SDavid Howells call->count = count; 1696d2ddc776SDavid Howells call->count2 = count; 169723a28913SDavid Howells afs_extract_discard(call, count * sizeof(__be32)); 1698d2ddc776SDavid Howells call->unmarshall++; 1699df561f66SGustavo A. R. Silva fallthrough; 1700d2ddc776SDavid Howells 170129881608SGustavo A. R. Silva /* Extract capabilities words */ 1702d2ddc776SDavid Howells case 2: 170312bdcf33SDavid Howells ret = afs_extract_data(call, false); 1704d2ddc776SDavid Howells if (ret < 0) 1705d2ddc776SDavid Howells return ret; 1706d2ddc776SDavid Howells 1707d2ddc776SDavid Howells /* TODO: Examine capabilities */ 1708d2ddc776SDavid Howells 1709d2ddc776SDavid Howells call->unmarshall++; 1710d2ddc776SDavid Howells break; 1711d2ddc776SDavid Howells } 1712d2ddc776SDavid Howells 1713d2ddc776SDavid Howells _leave(" = 0 [done]"); 1714d2ddc776SDavid Howells return 0; 1715d2ddc776SDavid Howells } 1716d2ddc776SDavid Howells 1717d2ddc776SDavid Howells /* 1718d2ddc776SDavid Howells * FS.GetCapabilities operation type 1719d2ddc776SDavid Howells */ 1720d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = { 1721d2ddc776SDavid Howells .name = "FS.GetCapabilities", 1722025db80cSDavid Howells .op = afs_FS_GetCapabilities, 1723d2ddc776SDavid Howells .deliver = afs_deliver_fs_get_capabilities, 17243bf0fb6fSDavid Howells .done = afs_fileserver_probe_result, 1725ffba718eSDavid Howells .destructor = afs_flat_call_destructor, 1726d2ddc776SDavid Howells }; 1727d2ddc776SDavid Howells 1728d2ddc776SDavid Howells /* 1729f6cbb368SDavid Howells * Probe a fileserver for the capabilities that it supports. This RPC can 1730f6cbb368SDavid Howells * reply with up to 196 words. The operation is asynchronous and if we managed 1731f6cbb368SDavid Howells * to allocate a call, true is returned the result is delivered through the 1732f6cbb368SDavid Howells * ->done() - otherwise we return false to indicate we didn't even try. 1733d2ddc776SDavid Howells */ 1734f6cbb368SDavid Howells bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server, 1735f6cbb368SDavid Howells struct afs_addr_cursor *ac, struct key *key) 1736d2ddc776SDavid Howells { 1737d2ddc776SDavid Howells struct afs_call *call; 1738d2ddc776SDavid Howells __be32 *bp; 1739d2ddc776SDavid Howells 1740d2ddc776SDavid Howells _enter(""); 1741d2ddc776SDavid Howells 1742d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4); 1743d2ddc776SDavid Howells if (!call) 1744f6cbb368SDavid Howells return false; 1745d2ddc776SDavid Howells 1746d2ddc776SDavid Howells call->key = key; 1747977e5f8eSDavid Howells call->server = afs_use_server(server, afs_server_trace_get_caps); 174830062bd1SDavid Howells call->upgrade = true; 17490b9bf381SDavid Howells call->async = true; 175094f699c9SDavid Howells call->max_lifespan = AFS_PROBE_MAX_LIFESPAN; 1751d2ddc776SDavid Howells 1752d2ddc776SDavid Howells /* marshall the parameters */ 1753d2ddc776SDavid Howells bp = call->request; 1754d2ddc776SDavid Howells *bp++ = htonl(FSGETCAPABILITIES); 1755d2ddc776SDavid Howells 1756025db80cSDavid Howells trace_afs_make_fs_call(call, NULL); 17570b9bf381SDavid Howells afs_make_call(ac, call, GFP_NOFS); 1758f6cbb368SDavid Howells afs_put_call(call); 1759f6cbb368SDavid Howells return true; 1760e8d6c554SDavid Howells } 17615cf9dd55SDavid Howells 17625cf9dd55SDavid Howells /* 17635cf9dd55SDavid Howells * Deliver reply data to an FS.InlineBulkStatus call 17645cf9dd55SDavid Howells */ 17655cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) 17665cf9dd55SDavid Howells { 1767e49c7b2fSDavid Howells struct afs_operation *op = call->op; 176887182759SDavid Howells struct afs_status_cb *scb; 17695cf9dd55SDavid Howells const __be32 *bp; 17705cf9dd55SDavid Howells u32 tmp; 17715cf9dd55SDavid Howells int ret; 17725cf9dd55SDavid Howells 17735cf9dd55SDavid Howells _enter("{%u}", call->unmarshall); 17745cf9dd55SDavid Howells 17755cf9dd55SDavid Howells switch (call->unmarshall) { 17765cf9dd55SDavid Howells case 0: 177712bdcf33SDavid Howells afs_extract_to_tmp(call); 17785cf9dd55SDavid Howells call->unmarshall++; 1779df561f66SGustavo A. R. Silva fallthrough; 17805cf9dd55SDavid Howells 17815cf9dd55SDavid Howells /* Extract the file status count and array in two steps */ 17825cf9dd55SDavid Howells case 1: 17835cf9dd55SDavid Howells _debug("extract status count"); 178412bdcf33SDavid Howells ret = afs_extract_data(call, true); 17855cf9dd55SDavid Howells if (ret < 0) 17865cf9dd55SDavid Howells return ret; 17875cf9dd55SDavid Howells 17885cf9dd55SDavid Howells tmp = ntohl(call->tmp); 1789e49c7b2fSDavid Howells _debug("status count: %u/%u", tmp, op->nr_files); 1790e49c7b2fSDavid Howells if (tmp != op->nr_files) 17917126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_ibulkst_count); 17925cf9dd55SDavid Howells 17935cf9dd55SDavid Howells call->count = 0; 17945cf9dd55SDavid Howells call->unmarshall++; 17955cf9dd55SDavid Howells more_counts: 179612bdcf33SDavid Howells afs_extract_to_buf(call, 21 * sizeof(__be32)); 1797df561f66SGustavo A. R. Silva fallthrough; 179829881608SGustavo A. R. Silva 17995cf9dd55SDavid Howells case 2: 18005cf9dd55SDavid Howells _debug("extract status array %u", call->count); 180112bdcf33SDavid Howells ret = afs_extract_data(call, true); 18025cf9dd55SDavid Howells if (ret < 0) 18035cf9dd55SDavid Howells return ret; 18045cf9dd55SDavid Howells 1805e49c7b2fSDavid Howells switch (call->count) { 1806e49c7b2fSDavid Howells case 0: 1807e49c7b2fSDavid Howells scb = &op->file[0].scb; 1808e49c7b2fSDavid Howells break; 1809e49c7b2fSDavid Howells case 1: 1810e49c7b2fSDavid Howells scb = &op->file[1].scb; 1811e49c7b2fSDavid Howells break; 1812e49c7b2fSDavid Howells default: 1813e49c7b2fSDavid Howells scb = &op->more_files[call->count - 2].scb; 1814e49c7b2fSDavid Howells break; 1815e49c7b2fSDavid Howells } 1816e49c7b2fSDavid Howells 18175cf9dd55SDavid Howells bp = call->buffer; 181838355eecSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, scb); 1819e49c7b2fSDavid Howells 18205cf9dd55SDavid Howells call->count++; 1821e49c7b2fSDavid Howells if (call->count < op->nr_files) 18225cf9dd55SDavid Howells goto more_counts; 18235cf9dd55SDavid Howells 18245cf9dd55SDavid Howells call->count = 0; 18255cf9dd55SDavid Howells call->unmarshall++; 182612bdcf33SDavid Howells afs_extract_to_tmp(call); 1827df561f66SGustavo A. R. Silva fallthrough; 18285cf9dd55SDavid Howells 18295cf9dd55SDavid Howells /* Extract the callback count and array in two steps */ 18305cf9dd55SDavid Howells case 3: 18315cf9dd55SDavid Howells _debug("extract CB count"); 183212bdcf33SDavid Howells ret = afs_extract_data(call, true); 18335cf9dd55SDavid Howells if (ret < 0) 18345cf9dd55SDavid Howells return ret; 18355cf9dd55SDavid Howells 18365cf9dd55SDavid Howells tmp = ntohl(call->tmp); 18375cf9dd55SDavid Howells _debug("CB count: %u", tmp); 1838e49c7b2fSDavid Howells if (tmp != op->nr_files) 18397126ead9SDavid Howells return afs_protocol_error(call, afs_eproto_ibulkst_cb_count); 18405cf9dd55SDavid Howells call->count = 0; 18415cf9dd55SDavid Howells call->unmarshall++; 18425cf9dd55SDavid Howells more_cbs: 184312bdcf33SDavid Howells afs_extract_to_buf(call, 3 * sizeof(__be32)); 1844df561f66SGustavo A. R. Silva fallthrough; 184529881608SGustavo A. R. Silva 18465cf9dd55SDavid Howells case 4: 18475cf9dd55SDavid Howells _debug("extract CB array"); 184812bdcf33SDavid Howells ret = afs_extract_data(call, true); 18495cf9dd55SDavid Howells if (ret < 0) 18505cf9dd55SDavid Howells return ret; 18515cf9dd55SDavid Howells 18525cf9dd55SDavid Howells _debug("unmarshall CB array"); 1853e49c7b2fSDavid Howells switch (call->count) { 1854e49c7b2fSDavid Howells case 0: 1855e49c7b2fSDavid Howells scb = &op->file[0].scb; 1856e49c7b2fSDavid Howells break; 1857e49c7b2fSDavid Howells case 1: 1858e49c7b2fSDavid Howells scb = &op->file[1].scb; 1859e49c7b2fSDavid Howells break; 1860e49c7b2fSDavid Howells default: 1861e49c7b2fSDavid Howells scb = &op->more_files[call->count - 2].scb; 1862e49c7b2fSDavid Howells break; 1863e49c7b2fSDavid Howells } 1864e49c7b2fSDavid Howells 18655cf9dd55SDavid Howells bp = call->buffer; 1866a58823acSDavid Howells xdr_decode_AFSCallBack(&bp, call, scb); 18675cf9dd55SDavid Howells call->count++; 1868e49c7b2fSDavid Howells if (call->count < op->nr_files) 18695cf9dd55SDavid Howells goto more_cbs; 18705cf9dd55SDavid Howells 187112bdcf33SDavid Howells afs_extract_to_buf(call, 6 * sizeof(__be32)); 18725cf9dd55SDavid Howells call->unmarshall++; 1873df561f66SGustavo A. R. Silva fallthrough; 187429881608SGustavo A. R. Silva 18755cf9dd55SDavid Howells case 5: 187612bdcf33SDavid Howells ret = afs_extract_data(call, false); 18775cf9dd55SDavid Howells if (ret < 0) 18785cf9dd55SDavid Howells return ret; 18795cf9dd55SDavid Howells 18805cf9dd55SDavid Howells bp = call->buffer; 1881e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 18825cf9dd55SDavid Howells 18835cf9dd55SDavid Howells call->unmarshall++; 18845cf9dd55SDavid Howells 18855cf9dd55SDavid Howells case 6: 18865cf9dd55SDavid Howells break; 18875cf9dd55SDavid Howells } 18885cf9dd55SDavid Howells 18895cf9dd55SDavid Howells _leave(" = 0 [done]"); 18905cf9dd55SDavid Howells return 0; 18915cf9dd55SDavid Howells } 18925cf9dd55SDavid Howells 1893e49c7b2fSDavid Howells static void afs_done_fs_inline_bulk_status(struct afs_call *call) 1894e49c7b2fSDavid Howells { 1895e49c7b2fSDavid Howells if (call->error == -ECONNABORTED && 189620325960SDavid Howells call->abort_code == RX_INVALID_OPERATION) { 1897e49c7b2fSDavid Howells set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags); 189820325960SDavid Howells if (call->op) 189920325960SDavid Howells set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags); 190020325960SDavid Howells } 1901e49c7b2fSDavid Howells } 1902e49c7b2fSDavid Howells 19035cf9dd55SDavid Howells /* 19045cf9dd55SDavid Howells * FS.InlineBulkStatus operation type 19055cf9dd55SDavid Howells */ 19065cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = { 19075cf9dd55SDavid Howells .name = "FS.InlineBulkStatus", 19085cf9dd55SDavid Howells .op = afs_FS_InlineBulkStatus, 19095cf9dd55SDavid Howells .deliver = afs_deliver_fs_inline_bulk_status, 1910e49c7b2fSDavid Howells .done = afs_done_fs_inline_bulk_status, 19115cf9dd55SDavid Howells .destructor = afs_flat_call_destructor, 19125cf9dd55SDavid Howells }; 19135cf9dd55SDavid Howells 19145cf9dd55SDavid Howells /* 19155cf9dd55SDavid Howells * Fetch the status information for up to 50 files 19165cf9dd55SDavid Howells */ 1917e49c7b2fSDavid Howells void afs_fs_inline_bulk_status(struct afs_operation *op) 19185cf9dd55SDavid Howells { 1919e49c7b2fSDavid Howells struct afs_vnode_param *dvp = &op->file[0]; 1920e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[1]; 19215cf9dd55SDavid Howells struct afs_call *call; 19225cf9dd55SDavid Howells __be32 *bp; 19235cf9dd55SDavid Howells int i; 19245cf9dd55SDavid Howells 192520325960SDavid Howells if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) { 1926e49c7b2fSDavid Howells op->error = -ENOTSUPP; 1927e49c7b2fSDavid Howells return; 19285cf9dd55SDavid Howells } 19295cf9dd55SDavid Howells 1930e49c7b2fSDavid Howells _enter(",%x,{%llx:%llu},%u", 1931e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files); 1932e49c7b2fSDavid Howells 1933e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus, 1934e49c7b2fSDavid Howells (2 + op->nr_files * 3) * 4, 1935e49c7b2fSDavid Howells 21 * 4); 1936e49c7b2fSDavid Howells if (!call) 1937e49c7b2fSDavid Howells return afs_op_nomem(op); 19385cf9dd55SDavid Howells 19395cf9dd55SDavid Howells /* marshall the parameters */ 19405cf9dd55SDavid Howells bp = call->request; 19415cf9dd55SDavid Howells *bp++ = htonl(FSINLINEBULKSTATUS); 1942e49c7b2fSDavid Howells *bp++ = htonl(op->nr_files); 1943e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vid); 1944e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.vnode); 1945e49c7b2fSDavid Howells *bp++ = htonl(dvp->fid.unique); 1946e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vid); 1947e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.vnode); 1948e49c7b2fSDavid Howells *bp++ = htonl(vp->fid.unique); 1949e49c7b2fSDavid Howells for (i = 0; i < op->nr_files - 2; i++) { 1950e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.vid); 1951e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.vnode); 1952e49c7b2fSDavid Howells *bp++ = htonl(op->more_files[i].fid.unique); 19535cf9dd55SDavid Howells } 19545cf9dd55SDavid Howells 1955e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 1956e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_NOFS); 19575cf9dd55SDavid Howells } 1958260f082bSDavid Howells 1959260f082bSDavid Howells /* 1960260f082bSDavid Howells * deliver reply data to an FS.FetchACL 1961260f082bSDavid Howells */ 1962260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call) 1963260f082bSDavid Howells { 1964e49c7b2fSDavid Howells struct afs_operation *op = call->op; 1965e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 1966260f082bSDavid Howells struct afs_acl *acl; 1967260f082bSDavid Howells const __be32 *bp; 1968260f082bSDavid Howells unsigned int size; 1969260f082bSDavid Howells int ret; 1970260f082bSDavid Howells 1971260f082bSDavid Howells _enter("{%u}", call->unmarshall); 1972260f082bSDavid Howells 1973260f082bSDavid Howells switch (call->unmarshall) { 1974260f082bSDavid Howells case 0: 1975260f082bSDavid Howells afs_extract_to_tmp(call); 1976260f082bSDavid Howells call->unmarshall++; 1977df561f66SGustavo A. R. Silva fallthrough; 1978260f082bSDavid Howells 1979260f082bSDavid Howells /* extract the returned data length */ 1980260f082bSDavid Howells case 1: 1981260f082bSDavid Howells ret = afs_extract_data(call, true); 1982260f082bSDavid Howells if (ret < 0) 1983260f082bSDavid Howells return ret; 1984260f082bSDavid Howells 1985260f082bSDavid Howells size = call->count2 = ntohl(call->tmp); 1986260f082bSDavid Howells size = round_up(size, 4); 1987260f082bSDavid Howells 1988260f082bSDavid Howells acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); 1989260f082bSDavid Howells if (!acl) 1990260f082bSDavid Howells return -ENOMEM; 1991e49c7b2fSDavid Howells op->acl = acl; 1992260f082bSDavid Howells acl->size = call->count2; 1993260f082bSDavid Howells afs_extract_begin(call, acl->data, size); 1994260f082bSDavid Howells call->unmarshall++; 1995df561f66SGustavo A. R. Silva fallthrough; 1996260f082bSDavid Howells 1997260f082bSDavid Howells /* extract the returned data */ 1998260f082bSDavid Howells case 2: 1999260f082bSDavid Howells ret = afs_extract_data(call, true); 2000260f082bSDavid Howells if (ret < 0) 2001260f082bSDavid Howells return ret; 2002260f082bSDavid Howells 2003260f082bSDavid Howells afs_extract_to_buf(call, (21 + 6) * 4); 2004260f082bSDavid Howells call->unmarshall++; 2005df561f66SGustavo A. R. Silva fallthrough; 2006260f082bSDavid Howells 2007260f082bSDavid Howells /* extract the metadata */ 2008260f082bSDavid Howells case 3: 2009260f082bSDavid Howells ret = afs_extract_data(call, false); 2010260f082bSDavid Howells if (ret < 0) 2011260f082bSDavid Howells return ret; 2012260f082bSDavid Howells 2013260f082bSDavid Howells bp = call->buffer; 2014e49c7b2fSDavid Howells xdr_decode_AFSFetchStatus(&bp, call, &vp->scb); 2015e49c7b2fSDavid Howells xdr_decode_AFSVolSync(&bp, &op->volsync); 2016260f082bSDavid Howells 2017260f082bSDavid Howells call->unmarshall++; 2018260f082bSDavid Howells 2019260f082bSDavid Howells case 4: 2020260f082bSDavid Howells break; 2021260f082bSDavid Howells } 2022260f082bSDavid Howells 2023260f082bSDavid Howells _leave(" = 0 [done]"); 2024260f082bSDavid Howells return 0; 2025260f082bSDavid Howells } 2026260f082bSDavid Howells 2027260f082bSDavid Howells /* 2028260f082bSDavid Howells * FS.FetchACL operation type 2029260f082bSDavid Howells */ 2030260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = { 2031260f082bSDavid Howells .name = "FS.FetchACL", 2032260f082bSDavid Howells .op = afs_FS_FetchACL, 2033260f082bSDavid Howells .deliver = afs_deliver_fs_fetch_acl, 2034260f082bSDavid Howells }; 2035260f082bSDavid Howells 2036260f082bSDavid Howells /* 2037260f082bSDavid Howells * Fetch the ACL for a file. 2038260f082bSDavid Howells */ 2039e49c7b2fSDavid Howells void afs_fs_fetch_acl(struct afs_operation *op) 2040260f082bSDavid Howells { 2041e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 2042260f082bSDavid Howells struct afs_call *call; 2043260f082bSDavid Howells __be32 *bp; 2044260f082bSDavid Howells 2045260f082bSDavid Howells _enter(",%x,{%llx:%llu},,", 2046e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2047260f082bSDavid Howells 2048e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4); 2049e49c7b2fSDavid Howells if (!call) 2050e49c7b2fSDavid Howells return afs_op_nomem(op); 2051260f082bSDavid Howells 2052260f082bSDavid Howells /* marshall the parameters */ 2053260f082bSDavid Howells bp = call->request; 2054260f082bSDavid Howells bp[0] = htonl(FSFETCHACL); 2055e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 2056e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 2057e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2058260f082bSDavid Howells 2059e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 2060e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_KERNEL); 2061ffba718eSDavid Howells } 2062ffba718eSDavid Howells 2063ffba718eSDavid Howells /* 2064b10494afSJoe Gorse * FS.StoreACL operation type 2065b10494afSJoe Gorse */ 2066b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = { 2067b10494afSJoe Gorse .name = "FS.StoreACL", 2068b10494afSJoe Gorse .op = afs_FS_StoreACL, 2069ffba718eSDavid Howells .deliver = afs_deliver_fs_file_status_and_vol, 2070b10494afSJoe Gorse .destructor = afs_flat_call_destructor, 2071b10494afSJoe Gorse }; 2072b10494afSJoe Gorse 2073b10494afSJoe Gorse /* 2074b10494afSJoe Gorse * Fetch the ACL for a file. 2075b10494afSJoe Gorse */ 2076e49c7b2fSDavid Howells void afs_fs_store_acl(struct afs_operation *op) 2077b10494afSJoe Gorse { 2078e49c7b2fSDavid Howells struct afs_vnode_param *vp = &op->file[0]; 2079b10494afSJoe Gorse struct afs_call *call; 2080e49c7b2fSDavid Howells const struct afs_acl *acl = op->acl; 2081b10494afSJoe Gorse size_t size; 2082b10494afSJoe Gorse __be32 *bp; 2083b10494afSJoe Gorse 2084b10494afSJoe Gorse _enter(",%x,{%llx:%llu},,", 2085e49c7b2fSDavid Howells key_serial(op->key), vp->fid.vid, vp->fid.vnode); 2086b10494afSJoe Gorse 2087b10494afSJoe Gorse size = round_up(acl->size, 4); 2088e49c7b2fSDavid Howells call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL, 2089b10494afSJoe Gorse 5 * 4 + size, (21 + 6) * 4); 2090e49c7b2fSDavid Howells if (!call) 2091e49c7b2fSDavid Howells return afs_op_nomem(op); 2092b10494afSJoe Gorse 2093b10494afSJoe Gorse /* marshall the parameters */ 2094b10494afSJoe Gorse bp = call->request; 2095b10494afSJoe Gorse bp[0] = htonl(FSSTOREACL); 2096e49c7b2fSDavid Howells bp[1] = htonl(vp->fid.vid); 2097e49c7b2fSDavid Howells bp[2] = htonl(vp->fid.vnode); 2098e49c7b2fSDavid Howells bp[3] = htonl(vp->fid.unique); 2099b10494afSJoe Gorse bp[4] = htonl(acl->size); 2100b10494afSJoe Gorse memcpy(&bp[5], acl->data, acl->size); 2101b10494afSJoe Gorse if (acl->size != size) 2102b10494afSJoe Gorse memset((void *)&bp[5] + acl->size, 0, size - acl->size); 2103b10494afSJoe Gorse 2104e49c7b2fSDavid Howells trace_afs_make_fs_call(call, &vp->fid); 2105e49c7b2fSDavid Howells afs_make_op_call(op, call, GFP_KERNEL); 21061da177e4SLinus Torvalds } 2107