108e0e7c8SDavid Howells /* AFS File Server client stubs 21da177e4SLinus Torvalds * 308e0e7c8SDavid Howells * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/init.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 1508e0e7c8SDavid Howells #include <linux/circ_buf.h> 16a01179e6SJeff Layton #include <linux/iversion.h> 171da177e4SLinus Torvalds #include "internal.h" 1808e0e7c8SDavid Howells #include "afs_fs.h" 19dd9fbcb8SDavid Howells #include "xdr_fs.h" 201da177e4SLinus Torvalds 21025db80cSDavid Howells static const struct afs_fid afs_zero_fid; 22025db80cSDavid Howells 231da177e4SLinus Torvalds /* 246db3ac3cSDavid Howells * We need somewhere to discard into in case the server helpfully returns more 256db3ac3cSDavid Howells * than we asked for in FS.FetchData{,64}. 266db3ac3cSDavid Howells */ 276db3ac3cSDavid Howells static u8 afs_discard_buffer[64]; 286db3ac3cSDavid Howells 29d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi) 30c435ee34SDavid Howells { 31d2ddc776SDavid Howells call->cbi = afs_get_cb_interest(cbi); 32c435ee34SDavid Howells } 33c435ee34SDavid Howells 346db3ac3cSDavid Howells /* 35260a9803SDavid Howells * decode an AFSFid block 36260a9803SDavid Howells */ 37260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 38260a9803SDavid Howells { 39260a9803SDavid Howells const __be32 *bp = *_bp; 40260a9803SDavid Howells 41260a9803SDavid Howells fid->vid = ntohl(*bp++); 42260a9803SDavid Howells fid->vnode = ntohl(*bp++); 43260a9803SDavid Howells fid->unique = ntohl(*bp++); 44260a9803SDavid Howells *_bp = bp; 45260a9803SDavid Howells } 46260a9803SDavid Howells 47260a9803SDavid Howells /* 48888b3384SDavid Howells * Dump a bad file status record. 49888b3384SDavid Howells */ 50888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp) 51888b3384SDavid Howells { 52888b3384SDavid Howells __be32 x[4]; 53888b3384SDavid Howells int i; 54888b3384SDavid Howells 55888b3384SDavid Howells pr_notice("AFS XDR: Bad status record\n"); 56888b3384SDavid Howells for (i = 0; i < 5 * 4 * 4; i += 16) { 57888b3384SDavid Howells memcpy(x, bp, 16); 58888b3384SDavid Howells bp += 4; 59888b3384SDavid Howells pr_notice("%03x: %08x %08x %08x %08x\n", 60888b3384SDavid Howells i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3])); 61888b3384SDavid Howells } 62888b3384SDavid Howells 63888b3384SDavid Howells memcpy(x, bp, 4); 64888b3384SDavid Howells pr_notice("0x50: %08x\n", ntohl(x[0])); 65888b3384SDavid Howells } 66888b3384SDavid Howells 67888b3384SDavid Howells /* 68dd9fbcb8SDavid Howells * Update the core inode struct from a returned status record. 691da177e4SLinus Torvalds */ 70dd9fbcb8SDavid Howells void afs_update_inode_from_status(struct afs_vnode *vnode, 71260a9803SDavid Howells struct afs_file_status *status, 720c3a5ac2SDavid Howells const afs_dataversion_t *expected_version, 73dd9fbcb8SDavid Howells u8 flags) 741da177e4SLinus Torvalds { 75dd9fbcb8SDavid Howells struct timespec t; 7608e0e7c8SDavid Howells umode_t mode; 7708e0e7c8SDavid Howells 78dd9fbcb8SDavid Howells t.tv_sec = status->mtime_client; 79dd9fbcb8SDavid Howells t.tv_nsec = 0; 80dd9fbcb8SDavid Howells vnode->vfs_inode.i_ctime = t; 81dd9fbcb8SDavid Howells vnode->vfs_inode.i_mtime = t; 82dd9fbcb8SDavid Howells vnode->vfs_inode.i_atime = t; 83c435ee34SDavid Howells 84dd9fbcb8SDavid Howells if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) { 85dd9fbcb8SDavid Howells vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner); 86dd9fbcb8SDavid Howells vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group); 87bfe86848SMiklos Szeredi set_nlink(&vnode->vfs_inode, status->nlink); 88260a9803SDavid Howells 8908e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 9008e0e7c8SDavid Howells mode &= ~S_IALLUGO; 91260a9803SDavid Howells mode |= status->mode; 92260a9803SDavid Howells barrier(); 9308e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 9408e0e7c8SDavid Howells } 9508e0e7c8SDavid Howells 96dd9fbcb8SDavid Howells if (!(flags & AFS_VNODE_NOT_YET_SET)) { 97dd9fbcb8SDavid Howells if (expected_version && 98dd9fbcb8SDavid Howells *expected_version != status->data_version) { 99dd9fbcb8SDavid Howells _debug("vnode modified %llx on {%x:%u} [exp %llx]", 100dd9fbcb8SDavid Howells (unsigned long long) status->data_version, 101dd9fbcb8SDavid Howells vnode->fid.vid, vnode->fid.vnode, 102dd9fbcb8SDavid Howells (unsigned long long) *expected_version); 103a4ff7401SDavid Howells vnode->invalid_before = status->data_version; 104f3ddee8dSDavid Howells if (vnode->status.type == AFS_FTYPE_DIR) { 105f3ddee8dSDavid Howells if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) 106f3ddee8dSDavid Howells afs_stat_v(vnode, n_inval); 107f3ddee8dSDavid Howells } else { 10808e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1091da177e4SLinus Torvalds } 11063a4681fSDavid Howells } else if (vnode->status.type == AFS_FTYPE_DIR) { 11163a4681fSDavid Howells /* Expected directory change is handled elsewhere so 11263a4681fSDavid Howells * that we can locally edit the directory and save on a 11363a4681fSDavid Howells * download. 11463a4681fSDavid Howells */ 11563a4681fSDavid Howells if (test_bit(AFS_VNODE_DIR_VALID, &vnode->flags)) 11663a4681fSDavid Howells flags &= ~AFS_VNODE_DATA_CHANGED; 117ec26815aSDavid Howells } 118f3ddee8dSDavid Howells } 119c435ee34SDavid Howells 120dd9fbcb8SDavid Howells if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) { 121dd9fbcb8SDavid Howells inode_set_iversion_raw(&vnode->vfs_inode, status->data_version); 122dd9fbcb8SDavid Howells i_size_write(&vnode->vfs_inode, status->size); 123dd9fbcb8SDavid Howells } 124dd9fbcb8SDavid Howells } 125dd9fbcb8SDavid Howells 126dd9fbcb8SDavid Howells /* 127dd9fbcb8SDavid Howells * decode an AFSFetchStatus block 128dd9fbcb8SDavid Howells */ 1295f702c8eSDavid Howells static int xdr_decode_AFSFetchStatus(struct afs_call *call, 1305f702c8eSDavid Howells const __be32 **_bp, 131dd9fbcb8SDavid Howells struct afs_file_status *status, 132dd9fbcb8SDavid Howells struct afs_vnode *vnode, 133dd9fbcb8SDavid Howells const afs_dataversion_t *expected_version, 134f3ddee8dSDavid Howells struct afs_read *read_req) 135dd9fbcb8SDavid Howells { 136dd9fbcb8SDavid Howells const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp; 137684b0f68SDavid Howells bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus); 138dd9fbcb8SDavid Howells u64 data_version, size; 139dd9fbcb8SDavid Howells u32 type, abort_code; 140dd9fbcb8SDavid Howells u8 flags = 0; 141dd9fbcb8SDavid Howells 142684b0f68SDavid Howells abort_code = ntohl(xdr->abort_code); 143684b0f68SDavid Howells 144dd9fbcb8SDavid Howells if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) { 145684b0f68SDavid Howells if (xdr->if_version == htonl(0) && 146684b0f68SDavid Howells abort_code != 0 && 147684b0f68SDavid Howells inline_error) { 148684b0f68SDavid Howells /* The OpenAFS fileserver has a bug in FS.InlineBulkStatus 149684b0f68SDavid Howells * whereby it doesn't set the interface version in the error 150684b0f68SDavid Howells * case. 151684b0f68SDavid Howells */ 152684b0f68SDavid Howells status->abort_code = abort_code; 153de52cf92SAl Viro return 0; 154684b0f68SDavid Howells } 155684b0f68SDavid Howells 156dd9fbcb8SDavid Howells pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version)); 157dd9fbcb8SDavid Howells goto bad; 158dd9fbcb8SDavid Howells } 159dd9fbcb8SDavid Howells 160684b0f68SDavid Howells if (abort_code != 0 && inline_error) { 161684b0f68SDavid Howells status->abort_code = abort_code; 162de52cf92SAl Viro return 0; 163684b0f68SDavid Howells } 164684b0f68SDavid Howells 165dd9fbcb8SDavid Howells type = ntohl(xdr->type); 166dd9fbcb8SDavid Howells switch (type) { 167dd9fbcb8SDavid Howells case AFS_FTYPE_FILE: 168dd9fbcb8SDavid Howells case AFS_FTYPE_DIR: 169dd9fbcb8SDavid Howells case AFS_FTYPE_SYMLINK: 170dd9fbcb8SDavid Howells if (type != status->type && 171dd9fbcb8SDavid Howells vnode && 172dd9fbcb8SDavid Howells !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 173dd9fbcb8SDavid Howells pr_warning("Vnode %x:%x:%x changed type %u to %u\n", 174dd9fbcb8SDavid Howells vnode->fid.vid, 175dd9fbcb8SDavid Howells vnode->fid.vnode, 176dd9fbcb8SDavid Howells vnode->fid.unique, 177dd9fbcb8SDavid Howells status->type, type); 178dd9fbcb8SDavid Howells goto bad; 179dd9fbcb8SDavid Howells } 180dd9fbcb8SDavid Howells status->type = type; 181dd9fbcb8SDavid Howells break; 182dd9fbcb8SDavid Howells default: 183dd9fbcb8SDavid Howells goto bad; 184dd9fbcb8SDavid Howells } 185dd9fbcb8SDavid Howells 186dd9fbcb8SDavid Howells #define EXTRACT_M(FIELD) \ 187dd9fbcb8SDavid Howells do { \ 188dd9fbcb8SDavid Howells u32 x = ntohl(xdr->FIELD); \ 189dd9fbcb8SDavid Howells if (status->FIELD != x) { \ 190dd9fbcb8SDavid Howells flags |= AFS_VNODE_META_CHANGED; \ 191dd9fbcb8SDavid Howells status->FIELD = x; \ 192dd9fbcb8SDavid Howells } \ 193dd9fbcb8SDavid Howells } while (0) 194dd9fbcb8SDavid Howells 195dd9fbcb8SDavid Howells EXTRACT_M(nlink); 196dd9fbcb8SDavid Howells EXTRACT_M(author); 197dd9fbcb8SDavid Howells EXTRACT_M(owner); 198dd9fbcb8SDavid Howells EXTRACT_M(caller_access); /* call ticket dependent */ 199dd9fbcb8SDavid Howells EXTRACT_M(anon_access); 200dd9fbcb8SDavid Howells EXTRACT_M(mode); 201dd9fbcb8SDavid Howells EXTRACT_M(group); 202dd9fbcb8SDavid Howells 203dd9fbcb8SDavid Howells status->mtime_client = ntohl(xdr->mtime_client); 204dd9fbcb8SDavid Howells status->mtime_server = ntohl(xdr->mtime_server); 205dd9fbcb8SDavid Howells status->lock_count = ntohl(xdr->lock_count); 206dd9fbcb8SDavid Howells 207dd9fbcb8SDavid Howells size = (u64)ntohl(xdr->size_lo); 208dd9fbcb8SDavid Howells size |= (u64)ntohl(xdr->size_hi) << 32; 209dd9fbcb8SDavid Howells status->size = size; 210dd9fbcb8SDavid Howells 211dd9fbcb8SDavid Howells data_version = (u64)ntohl(xdr->data_version_lo); 212dd9fbcb8SDavid Howells data_version |= (u64)ntohl(xdr->data_version_hi) << 32; 213dd9fbcb8SDavid Howells if (data_version != status->data_version) { 214dd9fbcb8SDavid Howells status->data_version = data_version; 215dd9fbcb8SDavid Howells flags |= AFS_VNODE_DATA_CHANGED; 216dd9fbcb8SDavid Howells } 217f3ddee8dSDavid Howells 218f3ddee8dSDavid Howells if (read_req) { 219f3ddee8dSDavid Howells read_req->data_version = data_version; 220f3ddee8dSDavid Howells read_req->file_size = size; 221f3ddee8dSDavid Howells } 222dd9fbcb8SDavid Howells 223dd9fbcb8SDavid Howells *_bp = (const void *)*_bp + sizeof(*xdr); 224dd9fbcb8SDavid Howells 225dd9fbcb8SDavid Howells if (vnode) { 226dd9fbcb8SDavid Howells if (test_bit(AFS_VNODE_UNSET, &vnode->flags)) 227dd9fbcb8SDavid Howells flags |= AFS_VNODE_NOT_YET_SET; 228dd9fbcb8SDavid Howells afs_update_inode_from_status(vnode, status, expected_version, 229dd9fbcb8SDavid Howells flags); 230dd9fbcb8SDavid Howells } 231dd9fbcb8SDavid Howells 232c875c76aSDavid Howells return 0; 233dd9fbcb8SDavid Howells 234dd9fbcb8SDavid Howells bad: 235dd9fbcb8SDavid Howells xdr_dump_bad(*_bp); 236c875c76aSDavid Howells return afs_protocol_error(call, -EBADMSG); 237c875c76aSDavid Howells } 238c875c76aSDavid Howells 239c875c76aSDavid Howells /* 240c875c76aSDavid Howells * Decode the file status. We need to lock the target vnode if we're going to 241c875c76aSDavid Howells * update its status so that stat() sees the attributes update atomically. 242c875c76aSDavid Howells */ 243c875c76aSDavid Howells static int afs_decode_status(struct afs_call *call, 244c875c76aSDavid Howells const __be32 **_bp, 245c875c76aSDavid Howells struct afs_file_status *status, 246c875c76aSDavid Howells struct afs_vnode *vnode, 247c875c76aSDavid Howells const afs_dataversion_t *expected_version, 248c875c76aSDavid Howells struct afs_read *read_req) 249c875c76aSDavid Howells { 250c875c76aSDavid Howells int ret; 251c875c76aSDavid Howells 252c875c76aSDavid Howells if (!vnode) 253c875c76aSDavid Howells return xdr_decode_AFSFetchStatus(call, _bp, status, vnode, 254c875c76aSDavid Howells expected_version, read_req); 255c875c76aSDavid Howells 256c875c76aSDavid Howells write_seqlock(&vnode->cb_lock); 257c875c76aSDavid Howells ret = xdr_decode_AFSFetchStatus(call, _bp, status, vnode, 258c875c76aSDavid Howells expected_version, read_req); 259c875c76aSDavid Howells write_sequnlock(&vnode->cb_lock); 260c875c76aSDavid Howells return ret; 261260a9803SDavid Howells } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds /* 26408e0e7c8SDavid Howells * decode an AFSCallBack block 2651da177e4SLinus Torvalds */ 266c435ee34SDavid Howells static void xdr_decode_AFSCallBack(struct afs_call *call, 267c435ee34SDavid Howells struct afs_vnode *vnode, 268c435ee34SDavid Howells const __be32 **_bp) 2691da177e4SLinus Torvalds { 270d2ddc776SDavid Howells struct afs_cb_interest *old, *cbi = call->cbi; 27108e0e7c8SDavid Howells const __be32 *bp = *_bp; 272c435ee34SDavid Howells u32 cb_expiry; 2731da177e4SLinus Torvalds 274c435ee34SDavid Howells write_seqlock(&vnode->cb_lock); 275c435ee34SDavid Howells 27668251f0aSDavid Howells if (call->cb_break == afs_cb_break_sum(vnode, cbi)) { 27708e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 278c435ee34SDavid Howells cb_expiry = ntohl(*bp++); 27908e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 280c435ee34SDavid Howells vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds(); 281d2ddc776SDavid Howells old = vnode->cb_interest; 282d2ddc776SDavid Howells if (old != call->cbi) { 283d2ddc776SDavid Howells vnode->cb_interest = cbi; 284d2ddc776SDavid Howells cbi = old; 285d2ddc776SDavid Howells } 286c435ee34SDavid Howells set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 287c435ee34SDavid Howells } else { 288c435ee34SDavid Howells bp += 3; 289c435ee34SDavid Howells } 290c435ee34SDavid Howells 291c435ee34SDavid Howells write_sequnlock(&vnode->cb_lock); 292d2ddc776SDavid Howells call->cbi = cbi; 29308e0e7c8SDavid Howells *_bp = bp; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 296260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 297260a9803SDavid Howells struct afs_callback *cb) 298260a9803SDavid Howells { 299260a9803SDavid Howells const __be32 *bp = *_bp; 300260a9803SDavid Howells 301260a9803SDavid Howells cb->version = ntohl(*bp++); 302260a9803SDavid Howells cb->expiry = ntohl(*bp++); 303260a9803SDavid Howells cb->type = ntohl(*bp++); 304260a9803SDavid Howells *_bp = bp; 305260a9803SDavid Howells } 306260a9803SDavid Howells 3071da177e4SLinus Torvalds /* 30808e0e7c8SDavid Howells * decode an AFSVolSync block 3091da177e4SLinus Torvalds */ 31008e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 31108e0e7c8SDavid Howells struct afs_volsync *volsync) 3121da177e4SLinus Torvalds { 31308e0e7c8SDavid Howells const __be32 *bp = *_bp; 3141da177e4SLinus Torvalds 31508e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 31608e0e7c8SDavid Howells bp++; /* spare2 */ 31708e0e7c8SDavid Howells bp++; /* spare3 */ 31808e0e7c8SDavid Howells bp++; /* spare4 */ 31908e0e7c8SDavid Howells bp++; /* spare5 */ 32008e0e7c8SDavid Howells bp++; /* spare6 */ 32108e0e7c8SDavid Howells *_bp = bp; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds 32408e0e7c8SDavid Howells /* 32531143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 32631143d5dSDavid Howells */ 32731143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 32831143d5dSDavid Howells { 32931143d5dSDavid Howells __be32 *bp = *_bp; 33031143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 33131143d5dSDavid Howells 33231143d5dSDavid Howells mask = 0; 33331143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 33431143d5dSDavid Howells mask |= AFS_SET_MTIME; 33531143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 33631143d5dSDavid Howells } 33731143d5dSDavid Howells 33831143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 33931143d5dSDavid Howells mask |= AFS_SET_OWNER; 340a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 34131143d5dSDavid Howells } 34231143d5dSDavid Howells 34331143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 34431143d5dSDavid Howells mask |= AFS_SET_GROUP; 345a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 34631143d5dSDavid Howells } 34731143d5dSDavid Howells 34831143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 34931143d5dSDavid Howells mask |= AFS_SET_MODE; 35031143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 35131143d5dSDavid Howells } 35231143d5dSDavid Howells 35331143d5dSDavid Howells *bp++ = htonl(mask); 35431143d5dSDavid Howells *bp++ = htonl(mtime); 35531143d5dSDavid Howells *bp++ = htonl(owner); 35631143d5dSDavid Howells *bp++ = htonl(group); 35731143d5dSDavid Howells *bp++ = htonl(mode); 35831143d5dSDavid Howells *bp++ = 0; /* segment size */ 35931143d5dSDavid Howells *_bp = bp; 36031143d5dSDavid Howells } 36131143d5dSDavid Howells 36231143d5dSDavid Howells /* 36345222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 36445222b9eSDavid Howells */ 36545222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 36645222b9eSDavid Howells struct afs_volume_status *vs) 36745222b9eSDavid Howells { 36845222b9eSDavid Howells const __be32 *bp = *_bp; 36945222b9eSDavid Howells 37045222b9eSDavid Howells vs->vid = ntohl(*bp++); 37145222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 37245222b9eSDavid Howells vs->online = ntohl(*bp++); 37345222b9eSDavid Howells vs->in_service = ntohl(*bp++); 37445222b9eSDavid Howells vs->blessed = ntohl(*bp++); 37545222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 37645222b9eSDavid Howells vs->type = ntohl(*bp++); 37745222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 37845222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 37945222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 38045222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 38145222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 38245222b9eSDavid Howells *_bp = bp; 38345222b9eSDavid Howells } 38445222b9eSDavid Howells 38545222b9eSDavid Howells /* 38608e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 38708e0e7c8SDavid Howells */ 3885cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call) 38908e0e7c8SDavid Howells { 39097e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 39108e0e7c8SDavid Howells const __be32 *bp; 392372ee163SDavid Howells int ret; 3931da177e4SLinus Torvalds 394d001648eSDavid Howells ret = afs_transfer_reply(call); 395372ee163SDavid Howells if (ret < 0) 396372ee163SDavid Howells return ret; 3971da177e4SLinus Torvalds 398c435ee34SDavid Howells _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); 399c435ee34SDavid Howells 40008e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 40108e0e7c8SDavid Howells bp = call->buffer; 402c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, 403dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 4045f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 405c435ee34SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 40697e3043aSDavid Howells if (call->reply[1]) 40797e3043aSDavid Howells xdr_decode_AFSVolSync(&bp, call->reply[1]); 4081da177e4SLinus Torvalds 40908e0e7c8SDavid Howells _leave(" = 0 [done]"); 41008e0e7c8SDavid Howells return 0; 411ec26815aSDavid Howells } 41208e0e7c8SDavid Howells 41308e0e7c8SDavid Howells /* 41408e0e7c8SDavid Howells * FS.FetchStatus operation type 41508e0e7c8SDavid Howells */ 4165cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus_vnode = { 4175cf9dd55SDavid Howells .name = "FS.FetchStatus(vnode)", 418025db80cSDavid Howells .op = afs_FS_FetchStatus, 4195cf9dd55SDavid Howells .deliver = afs_deliver_fs_fetch_status_vnode, 42008e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 42108e0e7c8SDavid Howells }; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /* 4241da177e4SLinus Torvalds * fetch the status information for a file 4251da177e4SLinus Torvalds */ 4260c3a5ac2SDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync, 4270c3a5ac2SDavid Howells bool new_inode) 4281da177e4SLinus Torvalds { 429d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 43008e0e7c8SDavid Howells struct afs_call *call; 431f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 4321da177e4SLinus Torvalds __be32 *bp; 4331da177e4SLinus Torvalds 434416351f2SDavid Howells _enter(",%x,{%x:%u},,", 435d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 4361da177e4SLinus Torvalds 4375cf9dd55SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode, 4385cf9dd55SDavid Howells 16, (21 + 3 + 6) * 4); 439d2ddc776SDavid Howells if (!call) { 440d2ddc776SDavid Howells fc->ac.error = -ENOMEM; 44108e0e7c8SDavid Howells return -ENOMEM; 442d2ddc776SDavid Howells } 4431da177e4SLinus Torvalds 444d2ddc776SDavid Howells call->key = fc->key; 44597e3043aSDavid Howells call->reply[0] = vnode; 44697e3043aSDavid Howells call->reply[1] = volsync; 4470c3a5ac2SDavid Howells call->expected_version = new_inode ? 1 : vnode->status.data_version; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* marshall the parameters */ 45008e0e7c8SDavid Howells bp = call->request; 4511da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 4521da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 4531da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 4541da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 4551da177e4SLinus Torvalds 456d2ddc776SDavid Howells call->cb_break = fc->cb_break; 457d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 458025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 459d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 460ec26815aSDavid Howells } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds /* 46308e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 4641da177e4SLinus Torvalds */ 465d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call) 4661da177e4SLinus Torvalds { 46797e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 46897e3043aSDavid Howells struct afs_read *req = call->reply[2]; 46908e0e7c8SDavid Howells const __be32 *bp; 470196ee9cdSDavid Howells unsigned int size; 47108e0e7c8SDavid Howells void *buffer; 4721da177e4SLinus Torvalds int ret; 4731da177e4SLinus Torvalds 4746a0e3999SDavid Howells _enter("{%u,%zu/%u;%llu/%llu}", 475196ee9cdSDavid Howells call->unmarshall, call->offset, call->count, 476196ee9cdSDavid Howells req->remain, req->actual_len); 4771da177e4SLinus Torvalds 47808e0e7c8SDavid Howells switch (call->unmarshall) { 47908e0e7c8SDavid Howells case 0: 480196ee9cdSDavid Howells req->actual_len = 0; 48108e0e7c8SDavid Howells call->offset = 0; 48208e0e7c8SDavid Howells call->unmarshall++; 483b9b1f8d5SDavid Howells if (call->operation_ID != FSFETCHDATA64) { 484b9b1f8d5SDavid Howells call->unmarshall++; 485b9b1f8d5SDavid Howells goto no_msw; 486b9b1f8d5SDavid Howells } 4871da177e4SLinus Torvalds 488b9b1f8d5SDavid Howells /* extract the upper part of the returned data length of an 489b9b1f8d5SDavid Howells * FSFETCHDATA64 op (which should always be 0 using this 490b9b1f8d5SDavid Howells * client) */ 49108e0e7c8SDavid Howells case 1: 492b9b1f8d5SDavid Howells _debug("extract data length (MSW)"); 493d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 494372ee163SDavid Howells if (ret < 0) 495372ee163SDavid Howells return ret; 496b9b1f8d5SDavid Howells 497196ee9cdSDavid Howells req->actual_len = ntohl(call->tmp); 498196ee9cdSDavid Howells req->actual_len <<= 32; 499b9b1f8d5SDavid Howells call->offset = 0; 500b9b1f8d5SDavid Howells call->unmarshall++; 501b9b1f8d5SDavid Howells 502b9b1f8d5SDavid Howells no_msw: 503b9b1f8d5SDavid Howells /* extract the returned data length */ 504b9b1f8d5SDavid Howells case 2: 50508e0e7c8SDavid Howells _debug("extract data length"); 506d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 507372ee163SDavid Howells if (ret < 0) 508372ee163SDavid Howells return ret; 5091da177e4SLinus Torvalds 510196ee9cdSDavid Howells req->actual_len |= ntohl(call->tmp); 511196ee9cdSDavid Howells _debug("DATA length: %llu", req->actual_len); 512196ee9cdSDavid Howells 513196ee9cdSDavid Howells req->remain = req->actual_len; 514196ee9cdSDavid Howells call->offset = req->pos & (PAGE_SIZE - 1); 515196ee9cdSDavid Howells req->index = 0; 516196ee9cdSDavid Howells if (req->actual_len == 0) 517196ee9cdSDavid Howells goto no_more_data; 51808e0e7c8SDavid Howells call->unmarshall++; 5191da177e4SLinus Torvalds 520196ee9cdSDavid Howells begin_page: 5216db3ac3cSDavid Howells ASSERTCMP(req->index, <, req->nr_pages); 522196ee9cdSDavid Howells if (req->remain > PAGE_SIZE - call->offset) 523196ee9cdSDavid Howells size = PAGE_SIZE - call->offset; 524196ee9cdSDavid Howells else 525196ee9cdSDavid Howells size = req->remain; 526196ee9cdSDavid Howells call->count = call->offset + size; 527196ee9cdSDavid Howells ASSERTCMP(call->count, <=, PAGE_SIZE); 528196ee9cdSDavid Howells req->remain -= size; 529196ee9cdSDavid Howells 53008e0e7c8SDavid Howells /* extract the returned data */ 531b9b1f8d5SDavid Howells case 3: 5326a0e3999SDavid Howells _debug("extract data %llu/%llu %zu/%u", 533196ee9cdSDavid Howells req->remain, req->actual_len, call->offset, call->count); 534196ee9cdSDavid Howells 535196ee9cdSDavid Howells buffer = kmap(req->pages[req->index]); 536196ee9cdSDavid Howells ret = afs_extract_data(call, buffer, call->count, true); 537196ee9cdSDavid Howells kunmap(req->pages[req->index]); 538372ee163SDavid Howells if (ret < 0) 539372ee163SDavid Howells return ret; 540196ee9cdSDavid Howells if (call->offset == PAGE_SIZE) { 541196ee9cdSDavid Howells if (req->page_done) 542196ee9cdSDavid Howells req->page_done(call, req); 54329f06985SDavid Howells req->index++; 544196ee9cdSDavid Howells if (req->remain > 0) { 545196ee9cdSDavid Howells call->offset = 0; 546e8e581a8SDavid Howells if (req->index >= req->nr_pages) { 547e8e581a8SDavid Howells call->unmarshall = 4; 5486db3ac3cSDavid Howells goto begin_discard; 549e8e581a8SDavid Howells } 550196ee9cdSDavid Howells goto begin_page; 551196ee9cdSDavid Howells } 552416351f2SDavid Howells } 5536db3ac3cSDavid Howells goto no_more_data; 5546db3ac3cSDavid Howells 5556db3ac3cSDavid Howells /* Discard any excess data the server gave us */ 5566db3ac3cSDavid Howells begin_discard: 5576db3ac3cSDavid Howells case 4: 5586a0e3999SDavid Howells size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain); 5596db3ac3cSDavid Howells call->count = size; 5606a0e3999SDavid Howells _debug("extract discard %llu/%llu %zu/%u", 5616db3ac3cSDavid Howells req->remain, req->actual_len, call->offset, call->count); 5626db3ac3cSDavid Howells 5636db3ac3cSDavid Howells call->offset = 0; 5646db3ac3cSDavid Howells ret = afs_extract_data(call, afs_discard_buffer, call->count, true); 5656db3ac3cSDavid Howells req->remain -= call->offset; 5666db3ac3cSDavid Howells if (ret < 0) 5676db3ac3cSDavid Howells return ret; 5686db3ac3cSDavid Howells if (req->remain > 0) 5696db3ac3cSDavid Howells goto begin_discard; 5701da177e4SLinus Torvalds 571196ee9cdSDavid Howells no_more_data: 57208e0e7c8SDavid Howells call->offset = 0; 5736db3ac3cSDavid Howells call->unmarshall = 5; 57408e0e7c8SDavid Howells 57508e0e7c8SDavid Howells /* extract the metadata */ 5766db3ac3cSDavid Howells case 5: 577d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 578d001648eSDavid Howells (21 + 3 + 6) * 4, false); 579372ee163SDavid Howells if (ret < 0) 580372ee163SDavid Howells return ret; 5811da177e4SLinus Torvalds 58208e0e7c8SDavid Howells bp = call->buffer; 583c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, 584f3ddee8dSDavid Howells &vnode->status.data_version, req) < 0) 5855f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 586c435ee34SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 58797e3043aSDavid Howells if (call->reply[1]) 58897e3043aSDavid Howells xdr_decode_AFSVolSync(&bp, call->reply[1]); 5891da177e4SLinus Torvalds 59008e0e7c8SDavid Howells call->offset = 0; 59108e0e7c8SDavid Howells call->unmarshall++; 5921da177e4SLinus Torvalds 5936db3ac3cSDavid Howells case 6: 5941da177e4SLinus Torvalds break; 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds 5976db3ac3cSDavid Howells for (; req->index < req->nr_pages; req->index++) { 5986db3ac3cSDavid Howells if (call->count < PAGE_SIZE) 5996db3ac3cSDavid Howells zero_user_segment(req->pages[req->index], 6006db3ac3cSDavid Howells call->count, PAGE_SIZE); 601196ee9cdSDavid Howells if (req->page_done) 602196ee9cdSDavid Howells req->page_done(call, req); 6036db3ac3cSDavid Howells call->count = 0; 604416351f2SDavid Howells } 605416351f2SDavid Howells 60608e0e7c8SDavid Howells _leave(" = 0 [done]"); 60708e0e7c8SDavid Howells return 0; 608ec26815aSDavid Howells } 6091da177e4SLinus Torvalds 610196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call) 611196ee9cdSDavid Howells { 61297e3043aSDavid Howells struct afs_read *req = call->reply[2]; 613196ee9cdSDavid Howells 614196ee9cdSDavid Howells afs_put_read(req); 615196ee9cdSDavid Howells afs_flat_call_destructor(call); 616196ee9cdSDavid Howells } 617196ee9cdSDavid Howells 6181da177e4SLinus Torvalds /* 61908e0e7c8SDavid Howells * FS.FetchData operation type 6201da177e4SLinus Torvalds */ 62108e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 62200d3b7a4SDavid Howells .name = "FS.FetchData", 623025db80cSDavid Howells .op = afs_FS_FetchData, 62408e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 625196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 62608e0e7c8SDavid Howells }; 62708e0e7c8SDavid Howells 628b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 629b9b1f8d5SDavid Howells .name = "FS.FetchData64", 630025db80cSDavid Howells .op = afs_FS_FetchData64, 631b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 632196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 633b9b1f8d5SDavid Howells }; 634b9b1f8d5SDavid Howells 635b9b1f8d5SDavid Howells /* 636b9b1f8d5SDavid Howells * fetch data from a very large file 637b9b1f8d5SDavid Howells */ 638d2ddc776SDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) 639b9b1f8d5SDavid Howells { 640d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 641b9b1f8d5SDavid Howells struct afs_call *call; 642f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 643b9b1f8d5SDavid Howells __be32 *bp; 644b9b1f8d5SDavid Howells 645b9b1f8d5SDavid Howells _enter(""); 646b9b1f8d5SDavid Howells 647f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 648b9b1f8d5SDavid Howells if (!call) 649b9b1f8d5SDavid Howells return -ENOMEM; 650b9b1f8d5SDavid Howells 651d2ddc776SDavid Howells call->key = fc->key; 65297e3043aSDavid Howells call->reply[0] = vnode; 65397e3043aSDavid Howells call->reply[1] = NULL; /* volsync */ 65497e3043aSDavid Howells call->reply[2] = req; 6550c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version; 656b9b1f8d5SDavid Howells 657b9b1f8d5SDavid Howells /* marshall the parameters */ 658b9b1f8d5SDavid Howells bp = call->request; 659b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 660b9b1f8d5SDavid Howells bp[1] = htonl(vnode->fid.vid); 661b9b1f8d5SDavid Howells bp[2] = htonl(vnode->fid.vnode); 662b9b1f8d5SDavid Howells bp[3] = htonl(vnode->fid.unique); 663196ee9cdSDavid Howells bp[4] = htonl(upper_32_bits(req->pos)); 664196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->pos)); 665b9b1f8d5SDavid Howells bp[6] = 0; 666196ee9cdSDavid Howells bp[7] = htonl(lower_32_bits(req->len)); 667b9b1f8d5SDavid Howells 668f3ddee8dSDavid Howells refcount_inc(&req->usage); 669d2ddc776SDavid Howells call->cb_break = fc->cb_break; 670d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 671025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 672d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 673b9b1f8d5SDavid Howells } 674b9b1f8d5SDavid Howells 67508e0e7c8SDavid Howells /* 67608e0e7c8SDavid Howells * fetch data from a file 67708e0e7c8SDavid Howells */ 678d2ddc776SDavid Howells int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) 6791da177e4SLinus Torvalds { 680d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 68108e0e7c8SDavid Howells struct afs_call *call; 682f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 68308e0e7c8SDavid Howells __be32 *bp; 6841da177e4SLinus Torvalds 685196ee9cdSDavid Howells if (upper_32_bits(req->pos) || 686196ee9cdSDavid Howells upper_32_bits(req->len) || 687196ee9cdSDavid Howells upper_32_bits(req->pos + req->len)) 688d2ddc776SDavid Howells return afs_fs_fetch_data64(fc, req); 689b9b1f8d5SDavid Howells 69008e0e7c8SDavid Howells _enter(""); 6911da177e4SLinus Torvalds 692f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 69308e0e7c8SDavid Howells if (!call) 69408e0e7c8SDavid Howells return -ENOMEM; 6951da177e4SLinus Torvalds 696d2ddc776SDavid Howells call->key = fc->key; 69797e3043aSDavid Howells call->reply[0] = vnode; 69897e3043aSDavid Howells call->reply[1] = NULL; /* volsync */ 69997e3043aSDavid Howells call->reply[2] = req; 7000c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* marshall the parameters */ 70308e0e7c8SDavid Howells bp = call->request; 70408e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 70508e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 70608e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 70708e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 708196ee9cdSDavid Howells bp[4] = htonl(lower_32_bits(req->pos)); 709196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->len)); 7101da177e4SLinus Torvalds 711f3ddee8dSDavid Howells refcount_inc(&req->usage); 712d2ddc776SDavid Howells call->cb_break = fc->cb_break; 713d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 714025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 715d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 71608e0e7c8SDavid Howells } 717260a9803SDavid Howells 718260a9803SDavid Howells /* 719260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 720260a9803SDavid Howells */ 721d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call) 722260a9803SDavid Howells { 72397e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 724260a9803SDavid Howells const __be32 *bp; 725372ee163SDavid Howells int ret; 726260a9803SDavid Howells 727d001648eSDavid Howells _enter("{%u}", call->unmarshall); 728260a9803SDavid Howells 729d001648eSDavid Howells ret = afs_transfer_reply(call); 730372ee163SDavid Howells if (ret < 0) 731372ee163SDavid Howells return ret; 732260a9803SDavid Howells 733260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 734260a9803SDavid Howells bp = call->buffer; 73597e3043aSDavid Howells xdr_decode_AFSFid(&bp, call->reply[1]); 736c875c76aSDavid Howells if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) < 0 || 737c875c76aSDavid Howells afs_decode_status(call, &bp, &vnode->status, vnode, 738dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 7395f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 74097e3043aSDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); 74197e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 742260a9803SDavid Howells 743260a9803SDavid Howells _leave(" = 0 [done]"); 744260a9803SDavid Howells return 0; 745260a9803SDavid Howells } 746260a9803SDavid Howells 747260a9803SDavid Howells /* 748260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 749260a9803SDavid Howells */ 750025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = { 751025db80cSDavid Howells .name = "FS.CreateFile", 752025db80cSDavid Howells .op = afs_FS_CreateFile, 753025db80cSDavid Howells .deliver = afs_deliver_fs_create_vnode, 754025db80cSDavid Howells .destructor = afs_flat_call_destructor, 755025db80cSDavid Howells }; 756025db80cSDavid Howells 757025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = { 758025db80cSDavid Howells .name = "FS.MakeDir", 759025db80cSDavid Howells .op = afs_FS_MakeDir, 760260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 761260a9803SDavid Howells .destructor = afs_flat_call_destructor, 762260a9803SDavid Howells }; 763260a9803SDavid Howells 764260a9803SDavid Howells /* 765260a9803SDavid Howells * create a file or make a directory 766260a9803SDavid Howells */ 7678b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc, 768260a9803SDavid Howells const char *name, 769260a9803SDavid Howells umode_t mode, 77063a4681fSDavid Howells u64 current_data_version, 771260a9803SDavid Howells struct afs_fid *newfid, 772260a9803SDavid Howells struct afs_file_status *newstatus, 773d2ddc776SDavid Howells struct afs_callback *newcb) 774260a9803SDavid Howells { 775d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 776260a9803SDavid Howells struct afs_call *call; 777f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 778260a9803SDavid Howells size_t namesz, reqsz, padsz; 779260a9803SDavid Howells __be32 *bp; 780260a9803SDavid Howells 781260a9803SDavid Howells _enter(""); 782260a9803SDavid Howells 783260a9803SDavid Howells namesz = strlen(name); 784260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 785260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 786260a9803SDavid Howells 787025db80cSDavid Howells call = afs_alloc_flat_call( 788025db80cSDavid Howells net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile, 789025db80cSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 790260a9803SDavid Howells if (!call) 791260a9803SDavid Howells return -ENOMEM; 792260a9803SDavid Howells 793d2ddc776SDavid Howells call->key = fc->key; 79497e3043aSDavid Howells call->reply[0] = vnode; 79597e3043aSDavid Howells call->reply[1] = newfid; 79697e3043aSDavid Howells call->reply[2] = newstatus; 79797e3043aSDavid Howells call->reply[3] = newcb; 79863a4681fSDavid Howells call->expected_version = current_data_version + 1; 799260a9803SDavid Howells 800260a9803SDavid Howells /* marshall the parameters */ 801260a9803SDavid Howells bp = call->request; 802260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 803260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 804260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 805260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 806260a9803SDavid Howells *bp++ = htonl(namesz); 807260a9803SDavid Howells memcpy(bp, name, namesz); 808260a9803SDavid Howells bp = (void *) bp + namesz; 809260a9803SDavid Howells if (padsz > 0) { 810260a9803SDavid Howells memset(bp, 0, padsz); 811260a9803SDavid Howells bp = (void *) bp + padsz; 812260a9803SDavid Howells } 813ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 814ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 815260a9803SDavid Howells *bp++ = 0; /* owner */ 816260a9803SDavid Howells *bp++ = 0; /* group */ 817260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 818260a9803SDavid Howells *bp++ = 0; /* segment size */ 819260a9803SDavid Howells 820d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 821025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 822d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 823260a9803SDavid Howells } 824260a9803SDavid Howells 825260a9803SDavid Howells /* 826260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 827260a9803SDavid Howells */ 828d001648eSDavid Howells static int afs_deliver_fs_remove(struct afs_call *call) 829260a9803SDavid Howells { 83097e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 831260a9803SDavid Howells const __be32 *bp; 832372ee163SDavid Howells int ret; 833260a9803SDavid Howells 834d001648eSDavid Howells _enter("{%u}", call->unmarshall); 835260a9803SDavid Howells 836d001648eSDavid Howells ret = afs_transfer_reply(call); 837372ee163SDavid Howells if (ret < 0) 838372ee163SDavid Howells return ret; 839260a9803SDavid Howells 840260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 841260a9803SDavid Howells bp = call->buffer; 842c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, 843dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 8445f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 84597e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 846260a9803SDavid Howells 847260a9803SDavid Howells _leave(" = 0 [done]"); 848260a9803SDavid Howells return 0; 849260a9803SDavid Howells } 850260a9803SDavid Howells 851260a9803SDavid Howells /* 852260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 853260a9803SDavid Howells */ 854025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = { 855025db80cSDavid Howells .name = "FS.RemoveFile", 856025db80cSDavid Howells .op = afs_FS_RemoveFile, 857025db80cSDavid Howells .deliver = afs_deliver_fs_remove, 858025db80cSDavid Howells .destructor = afs_flat_call_destructor, 859025db80cSDavid Howells }; 860025db80cSDavid Howells 861025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = { 862025db80cSDavid Howells .name = "FS.RemoveDir", 863025db80cSDavid Howells .op = afs_FS_RemoveDir, 864260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 865260a9803SDavid Howells .destructor = afs_flat_call_destructor, 866260a9803SDavid Howells }; 867260a9803SDavid Howells 868260a9803SDavid Howells /* 869260a9803SDavid Howells * remove a file or directory 870260a9803SDavid Howells */ 87163a4681fSDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir, 87263a4681fSDavid Howells u64 current_data_version) 873260a9803SDavid Howells { 874d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 875260a9803SDavid Howells struct afs_call *call; 876f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 877260a9803SDavid Howells size_t namesz, reqsz, padsz; 878260a9803SDavid Howells __be32 *bp; 879260a9803SDavid Howells 880260a9803SDavid Howells _enter(""); 881260a9803SDavid Howells 882260a9803SDavid Howells namesz = strlen(name); 883260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 884260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 885260a9803SDavid Howells 886025db80cSDavid Howells call = afs_alloc_flat_call( 887025db80cSDavid Howells net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile, 888025db80cSDavid Howells reqsz, (21 + 6) * 4); 889260a9803SDavid Howells if (!call) 890260a9803SDavid Howells return -ENOMEM; 891260a9803SDavid Howells 892d2ddc776SDavid Howells call->key = fc->key; 89397e3043aSDavid Howells call->reply[0] = vnode; 89463a4681fSDavid Howells call->expected_version = current_data_version + 1; 895260a9803SDavid Howells 896260a9803SDavid Howells /* marshall the parameters */ 897260a9803SDavid Howells bp = call->request; 898260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 899260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 900260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 901260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 902260a9803SDavid Howells *bp++ = htonl(namesz); 903260a9803SDavid Howells memcpy(bp, name, namesz); 904260a9803SDavid Howells bp = (void *) bp + namesz; 905260a9803SDavid Howells if (padsz > 0) { 906260a9803SDavid Howells memset(bp, 0, padsz); 907260a9803SDavid Howells bp = (void *) bp + padsz; 908260a9803SDavid Howells } 909260a9803SDavid Howells 910d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 911025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 912d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 913260a9803SDavid Howells } 914260a9803SDavid Howells 915260a9803SDavid Howells /* 916260a9803SDavid Howells * deliver reply data to an FS.Link 917260a9803SDavid Howells */ 918d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call) 919260a9803SDavid Howells { 92097e3043aSDavid Howells struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1]; 921260a9803SDavid Howells const __be32 *bp; 922372ee163SDavid Howells int ret; 923260a9803SDavid Howells 924d001648eSDavid Howells _enter("{%u}", call->unmarshall); 925260a9803SDavid Howells 926d001648eSDavid Howells ret = afs_transfer_reply(call); 927372ee163SDavid Howells if (ret < 0) 928372ee163SDavid Howells return ret; 929260a9803SDavid Howells 930260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 931260a9803SDavid Howells bp = call->buffer; 932c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, NULL, NULL) < 0 || 933c875c76aSDavid Howells afs_decode_status(call, &bp, &dvnode->status, dvnode, 934dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 9355f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 93697e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 937260a9803SDavid Howells 938260a9803SDavid Howells _leave(" = 0 [done]"); 939260a9803SDavid Howells return 0; 940260a9803SDavid Howells } 941260a9803SDavid Howells 942260a9803SDavid Howells /* 943260a9803SDavid Howells * FS.Link operation type 944260a9803SDavid Howells */ 945260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 946260a9803SDavid Howells .name = "FS.Link", 947025db80cSDavid Howells .op = afs_FS_Link, 948260a9803SDavid Howells .deliver = afs_deliver_fs_link, 949260a9803SDavid Howells .destructor = afs_flat_call_destructor, 950260a9803SDavid Howells }; 951260a9803SDavid Howells 952260a9803SDavid Howells /* 953260a9803SDavid Howells * make a hard link 954260a9803SDavid Howells */ 955d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, 95663a4681fSDavid Howells const char *name, u64 current_data_version) 957260a9803SDavid Howells { 958d2ddc776SDavid Howells struct afs_vnode *dvnode = fc->vnode; 959260a9803SDavid Howells struct afs_call *call; 960f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 961260a9803SDavid Howells size_t namesz, reqsz, padsz; 962260a9803SDavid Howells __be32 *bp; 963260a9803SDavid Howells 964260a9803SDavid Howells _enter(""); 965260a9803SDavid Howells 966260a9803SDavid Howells namesz = strlen(name); 967260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 968260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 969260a9803SDavid Howells 970f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 971260a9803SDavid Howells if (!call) 972260a9803SDavid Howells return -ENOMEM; 973260a9803SDavid Howells 974d2ddc776SDavid Howells call->key = fc->key; 97597e3043aSDavid Howells call->reply[0] = dvnode; 97697e3043aSDavid Howells call->reply[1] = vnode; 97763a4681fSDavid Howells call->expected_version = current_data_version + 1; 978260a9803SDavid Howells 979260a9803SDavid Howells /* marshall the parameters */ 980260a9803SDavid Howells bp = call->request; 981260a9803SDavid Howells *bp++ = htonl(FSLINK); 982260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 983260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 984260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 985260a9803SDavid Howells *bp++ = htonl(namesz); 986260a9803SDavid Howells memcpy(bp, name, namesz); 987260a9803SDavid Howells bp = (void *) bp + namesz; 988260a9803SDavid Howells if (padsz > 0) { 989260a9803SDavid Howells memset(bp, 0, padsz); 990260a9803SDavid Howells bp = (void *) bp + padsz; 991260a9803SDavid Howells } 992260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 993260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 994260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 995260a9803SDavid Howells 996d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 997025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 998d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 999260a9803SDavid Howells } 1000260a9803SDavid Howells 1001260a9803SDavid Howells /* 1002260a9803SDavid Howells * deliver reply data to an FS.Symlink 1003260a9803SDavid Howells */ 1004d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call) 1005260a9803SDavid Howells { 100697e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 1007260a9803SDavid Howells const __be32 *bp; 1008372ee163SDavid Howells int ret; 1009260a9803SDavid Howells 1010d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1011260a9803SDavid Howells 1012d001648eSDavid Howells ret = afs_transfer_reply(call); 1013372ee163SDavid Howells if (ret < 0) 1014372ee163SDavid Howells return ret; 1015260a9803SDavid Howells 1016260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 1017260a9803SDavid Howells bp = call->buffer; 101897e3043aSDavid Howells xdr_decode_AFSFid(&bp, call->reply[1]); 1019c875c76aSDavid Howells if (afs_decode_status(call, &bp, call->reply[2], NULL, NULL, NULL) || 1020c875c76aSDavid Howells afs_decode_status(call, &bp, &vnode->status, vnode, 1021dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 10225f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 102397e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 1024260a9803SDavid Howells 1025260a9803SDavid Howells _leave(" = 0 [done]"); 1026260a9803SDavid Howells return 0; 1027260a9803SDavid Howells } 1028260a9803SDavid Howells 1029260a9803SDavid Howells /* 1030260a9803SDavid Howells * FS.Symlink operation type 1031260a9803SDavid Howells */ 1032260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 1033260a9803SDavid Howells .name = "FS.Symlink", 1034025db80cSDavid Howells .op = afs_FS_Symlink, 1035260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 1036260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1037260a9803SDavid Howells }; 1038260a9803SDavid Howells 1039260a9803SDavid Howells /* 1040260a9803SDavid Howells * create a symbolic link 1041260a9803SDavid Howells */ 10428b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc, 1043260a9803SDavid Howells const char *name, 1044260a9803SDavid Howells const char *contents, 104563a4681fSDavid Howells u64 current_data_version, 1046260a9803SDavid Howells struct afs_fid *newfid, 1047d2ddc776SDavid Howells struct afs_file_status *newstatus) 1048260a9803SDavid Howells { 1049d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1050260a9803SDavid Howells struct afs_call *call; 1051f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1052260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 1053260a9803SDavid Howells __be32 *bp; 1054260a9803SDavid Howells 1055260a9803SDavid Howells _enter(""); 1056260a9803SDavid Howells 1057260a9803SDavid Howells namesz = strlen(name); 1058260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 1059260a9803SDavid Howells 1060260a9803SDavid Howells c_namesz = strlen(contents); 1061260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 1062260a9803SDavid Howells 1063260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 1064260a9803SDavid Howells 1065f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz, 1066260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 1067260a9803SDavid Howells if (!call) 1068260a9803SDavid Howells return -ENOMEM; 1069260a9803SDavid Howells 1070d2ddc776SDavid Howells call->key = fc->key; 107197e3043aSDavid Howells call->reply[0] = vnode; 107297e3043aSDavid Howells call->reply[1] = newfid; 107397e3043aSDavid Howells call->reply[2] = newstatus; 107463a4681fSDavid Howells call->expected_version = current_data_version + 1; 1075260a9803SDavid Howells 1076260a9803SDavid Howells /* marshall the parameters */ 1077260a9803SDavid Howells bp = call->request; 1078260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 1079260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 1080260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1081260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 1082260a9803SDavid Howells *bp++ = htonl(namesz); 1083260a9803SDavid Howells memcpy(bp, name, namesz); 1084260a9803SDavid Howells bp = (void *) bp + namesz; 1085260a9803SDavid Howells if (padsz > 0) { 1086260a9803SDavid Howells memset(bp, 0, padsz); 1087260a9803SDavid Howells bp = (void *) bp + padsz; 1088260a9803SDavid Howells } 1089260a9803SDavid Howells *bp++ = htonl(c_namesz); 1090260a9803SDavid Howells memcpy(bp, contents, c_namesz); 1091260a9803SDavid Howells bp = (void *) bp + c_namesz; 1092260a9803SDavid Howells if (c_padsz > 0) { 1093260a9803SDavid Howells memset(bp, 0, c_padsz); 1094260a9803SDavid Howells bp = (void *) bp + c_padsz; 1095260a9803SDavid Howells } 1096ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 1097ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 1098260a9803SDavid Howells *bp++ = 0; /* owner */ 1099260a9803SDavid Howells *bp++ = 0; /* group */ 1100260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 1101260a9803SDavid Howells *bp++ = 0; /* segment size */ 1102260a9803SDavid Howells 1103d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1104025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1105d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1106260a9803SDavid Howells } 1107260a9803SDavid Howells 1108260a9803SDavid Howells /* 1109260a9803SDavid Howells * deliver reply data to an FS.Rename 1110260a9803SDavid Howells */ 1111d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call) 1112260a9803SDavid Howells { 111397e3043aSDavid Howells struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1]; 1114260a9803SDavid Howells const __be32 *bp; 1115372ee163SDavid Howells int ret; 1116260a9803SDavid Howells 1117d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1118260a9803SDavid Howells 1119d001648eSDavid Howells ret = afs_transfer_reply(call); 1120372ee163SDavid Howells if (ret < 0) 1121372ee163SDavid Howells return ret; 1122260a9803SDavid Howells 1123260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 1124260a9803SDavid Howells bp = call->buffer; 1125c875c76aSDavid Howells if (afs_decode_status(call, &bp, &orig_dvnode->status, orig_dvnode, 1126dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 11275f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 1128dd9fbcb8SDavid Howells if (new_dvnode != orig_dvnode && 1129c875c76aSDavid Howells afs_decode_status(call, &bp, &new_dvnode->status, new_dvnode, 1130dd9fbcb8SDavid Howells &call->expected_version_2, NULL) < 0) 11315f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 113297e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 1133260a9803SDavid Howells 1134260a9803SDavid Howells _leave(" = 0 [done]"); 1135260a9803SDavid Howells return 0; 1136260a9803SDavid Howells } 1137260a9803SDavid Howells 1138260a9803SDavid Howells /* 1139260a9803SDavid Howells * FS.Rename operation type 1140260a9803SDavid Howells */ 1141260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 1142260a9803SDavid Howells .name = "FS.Rename", 1143025db80cSDavid Howells .op = afs_FS_Rename, 1144260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 1145260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1146260a9803SDavid Howells }; 1147260a9803SDavid Howells 1148260a9803SDavid Howells /* 1149260a9803SDavid Howells * create a symbolic link 1150260a9803SDavid Howells */ 11518b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc, 1152260a9803SDavid Howells const char *orig_name, 1153260a9803SDavid Howells struct afs_vnode *new_dvnode, 115463a4681fSDavid Howells const char *new_name, 115563a4681fSDavid Howells u64 current_orig_data_version, 115663a4681fSDavid Howells u64 current_new_data_version) 1157260a9803SDavid Howells { 1158d2ddc776SDavid Howells struct afs_vnode *orig_dvnode = fc->vnode; 1159260a9803SDavid Howells struct afs_call *call; 1160f044c884SDavid Howells struct afs_net *net = afs_v2net(orig_dvnode); 1161260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 1162260a9803SDavid Howells __be32 *bp; 1163260a9803SDavid Howells 1164260a9803SDavid Howells _enter(""); 1165260a9803SDavid Howells 1166260a9803SDavid Howells o_namesz = strlen(orig_name); 1167260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 1168260a9803SDavid Howells 1169260a9803SDavid Howells n_namesz = strlen(new_name); 1170260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 1171260a9803SDavid Howells 1172260a9803SDavid Howells reqsz = (4 * 4) + 1173260a9803SDavid Howells 4 + o_namesz + o_padsz + 1174260a9803SDavid Howells (3 * 4) + 1175260a9803SDavid Howells 4 + n_namesz + n_padsz; 1176260a9803SDavid Howells 1177f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1178260a9803SDavid Howells if (!call) 1179260a9803SDavid Howells return -ENOMEM; 1180260a9803SDavid Howells 1181d2ddc776SDavid Howells call->key = fc->key; 118297e3043aSDavid Howells call->reply[0] = orig_dvnode; 118397e3043aSDavid Howells call->reply[1] = new_dvnode; 118463a4681fSDavid Howells call->expected_version = current_orig_data_version + 1; 118563a4681fSDavid Howells call->expected_version_2 = current_new_data_version + 1; 1186260a9803SDavid Howells 1187260a9803SDavid Howells /* marshall the parameters */ 1188260a9803SDavid Howells bp = call->request; 1189260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1190260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 1191260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 1192260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 1193260a9803SDavid Howells *bp++ = htonl(o_namesz); 1194260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 1195260a9803SDavid Howells bp = (void *) bp + o_namesz; 1196260a9803SDavid Howells if (o_padsz > 0) { 1197260a9803SDavid Howells memset(bp, 0, o_padsz); 1198260a9803SDavid Howells bp = (void *) bp + o_padsz; 1199260a9803SDavid Howells } 1200260a9803SDavid Howells 1201260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 1202260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 1203260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 1204260a9803SDavid Howells *bp++ = htonl(n_namesz); 1205260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 1206260a9803SDavid Howells bp = (void *) bp + n_namesz; 1207260a9803SDavid Howells if (n_padsz > 0) { 1208260a9803SDavid Howells memset(bp, 0, n_padsz); 1209260a9803SDavid Howells bp = (void *) bp + n_padsz; 1210260a9803SDavid Howells } 1211260a9803SDavid Howells 1212d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1213025db80cSDavid Howells trace_afs_make_fs_call(call, &orig_dvnode->fid); 1214d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1215260a9803SDavid Howells } 121631143d5dSDavid Howells 121731143d5dSDavid Howells /* 121831143d5dSDavid Howells * deliver reply data to an FS.StoreData 121931143d5dSDavid Howells */ 1220d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call) 122131143d5dSDavid Howells { 122297e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 122331143d5dSDavid Howells const __be32 *bp; 1224372ee163SDavid Howells int ret; 122531143d5dSDavid Howells 1226d001648eSDavid Howells _enter(""); 122731143d5dSDavid Howells 1228d001648eSDavid Howells ret = afs_transfer_reply(call); 1229372ee163SDavid Howells if (ret < 0) 1230372ee163SDavid Howells return ret; 123131143d5dSDavid Howells 123231143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 123331143d5dSDavid Howells bp = call->buffer; 1234c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, 1235dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 12365f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 123797e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 123831143d5dSDavid Howells 123931143d5dSDavid Howells afs_pages_written_back(vnode, call); 124031143d5dSDavid Howells 124131143d5dSDavid Howells _leave(" = 0 [done]"); 124231143d5dSDavid Howells return 0; 124331143d5dSDavid Howells } 124431143d5dSDavid Howells 124531143d5dSDavid Howells /* 124631143d5dSDavid Howells * FS.StoreData operation type 124731143d5dSDavid Howells */ 124831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 124931143d5dSDavid Howells .name = "FS.StoreData", 1250025db80cSDavid Howells .op = afs_FS_StoreData, 125131143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 125231143d5dSDavid Howells .destructor = afs_flat_call_destructor, 125331143d5dSDavid Howells }; 125431143d5dSDavid Howells 1255b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1256b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1257025db80cSDavid Howells .op = afs_FS_StoreData64, 1258b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1259b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1260b9b1f8d5SDavid Howells }; 1261b9b1f8d5SDavid Howells 1262b9b1f8d5SDavid Howells /* 1263b9b1f8d5SDavid Howells * store a set of pages to a very large file 1264b9b1f8d5SDavid Howells */ 12658b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc, 12664343d008SDavid Howells struct address_space *mapping, 1267b9b1f8d5SDavid Howells pgoff_t first, pgoff_t last, 1268b9b1f8d5SDavid Howells unsigned offset, unsigned to, 1269d2ddc776SDavid Howells loff_t size, loff_t pos, loff_t i_size) 1270b9b1f8d5SDavid Howells { 12714343d008SDavid Howells struct afs_vnode *vnode = fc->vnode; 1272b9b1f8d5SDavid Howells struct afs_call *call; 1273f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1274b9b1f8d5SDavid Howells __be32 *bp; 1275b9b1f8d5SDavid Howells 1276b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 12774343d008SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 1278b9b1f8d5SDavid Howells 1279f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64, 1280b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1281b9b1f8d5SDavid Howells (21 + 6) * 4); 1282b9b1f8d5SDavid Howells if (!call) 1283b9b1f8d5SDavid Howells return -ENOMEM; 1284b9b1f8d5SDavid Howells 12854343d008SDavid Howells call->key = fc->key; 12864343d008SDavid Howells call->mapping = mapping; 128797e3043aSDavid Howells call->reply[0] = vnode; 1288b9b1f8d5SDavid Howells call->first = first; 1289b9b1f8d5SDavid Howells call->last = last; 1290b9b1f8d5SDavid Howells call->first_offset = offset; 1291b9b1f8d5SDavid Howells call->last_to = to; 1292b9b1f8d5SDavid Howells call->send_pages = true; 12930c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version + 1; 1294b9b1f8d5SDavid Howells 1295b9b1f8d5SDavid Howells /* marshall the parameters */ 1296b9b1f8d5SDavid Howells bp = call->request; 1297b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1298b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1299b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1300b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1301b9b1f8d5SDavid Howells 1302ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1303ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 1304b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1305b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1306b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1307b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1308b9b1f8d5SDavid Howells 1309b9b1f8d5SDavid Howells *bp++ = htonl(pos >> 32); 1310b9b1f8d5SDavid Howells *bp++ = htonl((u32) pos); 1311b9b1f8d5SDavid Howells *bp++ = htonl(size >> 32); 1312b9b1f8d5SDavid Howells *bp++ = htonl((u32) size); 1313b9b1f8d5SDavid Howells *bp++ = htonl(i_size >> 32); 1314b9b1f8d5SDavid Howells *bp++ = htonl((u32) i_size); 1315b9b1f8d5SDavid Howells 1316025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1317d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1318b9b1f8d5SDavid Howells } 1319b9b1f8d5SDavid Howells 132031143d5dSDavid Howells /* 132131143d5dSDavid Howells * store a set of pages 132231143d5dSDavid Howells */ 13234343d008SDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping, 132431143d5dSDavid Howells pgoff_t first, pgoff_t last, 1325d2ddc776SDavid Howells unsigned offset, unsigned to) 132631143d5dSDavid Howells { 13274343d008SDavid Howells struct afs_vnode *vnode = fc->vnode; 132831143d5dSDavid Howells struct afs_call *call; 1329f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 133031143d5dSDavid Howells loff_t size, pos, i_size; 133131143d5dSDavid Howells __be32 *bp; 133231143d5dSDavid Howells 133331143d5dSDavid Howells _enter(",%x,{%x:%u},,", 13344343d008SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 133531143d5dSDavid Howells 1336146a1192SDavid Howells size = (loff_t)to - (loff_t)offset; 133731143d5dSDavid Howells if (first != last) 133831143d5dSDavid Howells size += (loff_t)(last - first) << PAGE_SHIFT; 133931143d5dSDavid Howells pos = (loff_t)first << PAGE_SHIFT; 134031143d5dSDavid Howells pos += offset; 134131143d5dSDavid Howells 134231143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 134331143d5dSDavid Howells if (pos + size > i_size) 134431143d5dSDavid Howells i_size = size + pos; 134531143d5dSDavid Howells 134631143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 134731143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 134831143d5dSDavid Howells (unsigned long long) i_size); 134931143d5dSDavid Howells 1350b9b1f8d5SDavid Howells if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) 13514343d008SDavid Howells return afs_fs_store_data64(fc, mapping, first, last, offset, to, 1352d2ddc776SDavid Howells size, pos, i_size); 135331143d5dSDavid Howells 1354f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData, 135531143d5dSDavid Howells (4 + 6 + 3) * 4, 135631143d5dSDavid Howells (21 + 6) * 4); 135731143d5dSDavid Howells if (!call) 135831143d5dSDavid Howells return -ENOMEM; 135931143d5dSDavid Howells 13604343d008SDavid Howells call->key = fc->key; 13614343d008SDavid Howells call->mapping = mapping; 136297e3043aSDavid Howells call->reply[0] = vnode; 136331143d5dSDavid Howells call->first = first; 136431143d5dSDavid Howells call->last = last; 136531143d5dSDavid Howells call->first_offset = offset; 136631143d5dSDavid Howells call->last_to = to; 136731143d5dSDavid Howells call->send_pages = true; 13680c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version + 1; 136931143d5dSDavid Howells 137031143d5dSDavid Howells /* marshall the parameters */ 137131143d5dSDavid Howells bp = call->request; 137231143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 137331143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 137431143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 137531143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 137631143d5dSDavid Howells 1377ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1378ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 137931143d5dSDavid Howells *bp++ = 0; /* owner */ 138031143d5dSDavid Howells *bp++ = 0; /* group */ 138131143d5dSDavid Howells *bp++ = 0; /* unix mode */ 138231143d5dSDavid Howells *bp++ = 0; /* segment size */ 138331143d5dSDavid Howells 138431143d5dSDavid Howells *bp++ = htonl(pos); 138531143d5dSDavid Howells *bp++ = htonl(size); 138631143d5dSDavid Howells *bp++ = htonl(i_size); 138731143d5dSDavid Howells 1388d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1389025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1390d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 139131143d5dSDavid Howells } 139231143d5dSDavid Howells 139331143d5dSDavid Howells /* 139431143d5dSDavid Howells * deliver reply data to an FS.StoreStatus 139531143d5dSDavid Howells */ 1396d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call) 139731143d5dSDavid Howells { 139897e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 139931143d5dSDavid Howells const __be32 *bp; 1400372ee163SDavid Howells int ret; 140131143d5dSDavid Howells 1402d001648eSDavid Howells _enter(""); 140331143d5dSDavid Howells 1404d001648eSDavid Howells ret = afs_transfer_reply(call); 1405372ee163SDavid Howells if (ret < 0) 1406372ee163SDavid Howells return ret; 140731143d5dSDavid Howells 140831143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 140931143d5dSDavid Howells bp = call->buffer; 1410c875c76aSDavid Howells if (afs_decode_status(call, &bp, &vnode->status, vnode, 1411dd9fbcb8SDavid Howells &call->expected_version, NULL) < 0) 14125f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 141397e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 141431143d5dSDavid Howells 141531143d5dSDavid Howells _leave(" = 0 [done]"); 141631143d5dSDavid Howells return 0; 141731143d5dSDavid Howells } 141831143d5dSDavid Howells 141931143d5dSDavid Howells /* 142031143d5dSDavid Howells * FS.StoreStatus operation type 142131143d5dSDavid Howells */ 142231143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 142331143d5dSDavid Howells .name = "FS.StoreStatus", 1424025db80cSDavid Howells .op = afs_FS_StoreStatus, 142531143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 142631143d5dSDavid Howells .destructor = afs_flat_call_destructor, 142731143d5dSDavid Howells }; 142831143d5dSDavid Howells 142931143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 143031143d5dSDavid Howells .name = "FS.StoreData", 1431025db80cSDavid Howells .op = afs_FS_StoreData, 143231143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 143331143d5dSDavid Howells .destructor = afs_flat_call_destructor, 143431143d5dSDavid Howells }; 143531143d5dSDavid Howells 1436b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1437b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1438025db80cSDavid Howells .op = afs_FS_StoreData64, 1439b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_status, 1440b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1441b9b1f8d5SDavid Howells }; 1442b9b1f8d5SDavid Howells 1443b9b1f8d5SDavid Howells /* 1444b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1445b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1446b9b1f8d5SDavid Howells */ 1447d2ddc776SDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) 1448b9b1f8d5SDavid Howells { 1449d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1450b9b1f8d5SDavid Howells struct afs_call *call; 1451f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1452b9b1f8d5SDavid Howells __be32 *bp; 1453b9b1f8d5SDavid Howells 1454b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1455d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 1456b9b1f8d5SDavid Howells 1457b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1458b9b1f8d5SDavid Howells 1459f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status, 1460b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1461b9b1f8d5SDavid Howells (21 + 6) * 4); 1462b9b1f8d5SDavid Howells if (!call) 1463b9b1f8d5SDavid Howells return -ENOMEM; 1464b9b1f8d5SDavid Howells 1465d2ddc776SDavid Howells call->key = fc->key; 146697e3043aSDavid Howells call->reply[0] = vnode; 14670c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version + 1; 1468b9b1f8d5SDavid Howells 1469b9b1f8d5SDavid Howells /* marshall the parameters */ 1470b9b1f8d5SDavid Howells bp = call->request; 1471b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1472b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1473b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1474b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1475b9b1f8d5SDavid Howells 1476b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1477b9b1f8d5SDavid Howells 1478b9b1f8d5SDavid Howells *bp++ = 0; /* position of start of write */ 1479b9b1f8d5SDavid Howells *bp++ = 0; 1480b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1481b9b1f8d5SDavid Howells *bp++ = 0; 1482b9b1f8d5SDavid Howells *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1483b9b1f8d5SDavid Howells *bp++ = htonl((u32) attr->ia_size); 1484b9b1f8d5SDavid Howells 1485d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1486025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1487d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1488b9b1f8d5SDavid Howells } 1489b9b1f8d5SDavid Howells 149031143d5dSDavid Howells /* 149131143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 149231143d5dSDavid Howells * so as to alter the file size also 149331143d5dSDavid Howells */ 1494d2ddc776SDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) 149531143d5dSDavid Howells { 1496d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 149731143d5dSDavid Howells struct afs_call *call; 1498f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 149931143d5dSDavid Howells __be32 *bp; 150031143d5dSDavid Howells 150131143d5dSDavid Howells _enter(",%x,{%x:%u},,", 1502d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 150331143d5dSDavid Howells 150431143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1505b9b1f8d5SDavid Howells if (attr->ia_size >> 32) 1506d2ddc776SDavid Howells return afs_fs_setattr_size64(fc, attr); 150731143d5dSDavid Howells 1508f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status, 150931143d5dSDavid Howells (4 + 6 + 3) * 4, 151031143d5dSDavid Howells (21 + 6) * 4); 151131143d5dSDavid Howells if (!call) 151231143d5dSDavid Howells return -ENOMEM; 151331143d5dSDavid Howells 1514d2ddc776SDavid Howells call->key = fc->key; 151597e3043aSDavid Howells call->reply[0] = vnode; 15160c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version + 1; 151731143d5dSDavid Howells 151831143d5dSDavid Howells /* marshall the parameters */ 151931143d5dSDavid Howells bp = call->request; 152031143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 152131143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 152231143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 152331143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 152431143d5dSDavid Howells 152531143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 152631143d5dSDavid Howells 152731143d5dSDavid Howells *bp++ = 0; /* position of start of write */ 152831143d5dSDavid Howells *bp++ = 0; /* size of write */ 152931143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 153031143d5dSDavid Howells 1531d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1532025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1533d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 153431143d5dSDavid Howells } 153531143d5dSDavid Howells 153631143d5dSDavid Howells /* 153731143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 153831143d5dSDavid Howells * size, and FS.StoreStatus otherwise 153931143d5dSDavid Howells */ 1540d2ddc776SDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) 154131143d5dSDavid Howells { 1542d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 154331143d5dSDavid Howells struct afs_call *call; 1544f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 154531143d5dSDavid Howells __be32 *bp; 154631143d5dSDavid Howells 154731143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 1548d2ddc776SDavid Howells return afs_fs_setattr_size(fc, attr); 154931143d5dSDavid Howells 155031143d5dSDavid Howells _enter(",%x,{%x:%u},,", 1551d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 155231143d5dSDavid Howells 1553f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus, 155431143d5dSDavid Howells (4 + 6) * 4, 155531143d5dSDavid Howells (21 + 6) * 4); 155631143d5dSDavid Howells if (!call) 155731143d5dSDavid Howells return -ENOMEM; 155831143d5dSDavid Howells 1559d2ddc776SDavid Howells call->key = fc->key; 156097e3043aSDavid Howells call->reply[0] = vnode; 15610c3a5ac2SDavid Howells call->expected_version = vnode->status.data_version; 156231143d5dSDavid Howells 156331143d5dSDavid Howells /* marshall the parameters */ 156431143d5dSDavid Howells bp = call->request; 156531143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 156631143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 156731143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 156831143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 156931143d5dSDavid Howells 157031143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 157131143d5dSDavid Howells 1572d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1573025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1574d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 157531143d5dSDavid Howells } 157645222b9eSDavid Howells 157745222b9eSDavid Howells /* 157845222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 157945222b9eSDavid Howells */ 1580d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call) 158145222b9eSDavid Howells { 158245222b9eSDavid Howells const __be32 *bp; 158345222b9eSDavid Howells char *p; 158445222b9eSDavid Howells int ret; 158545222b9eSDavid Howells 1586d001648eSDavid Howells _enter("{%u}", call->unmarshall); 158745222b9eSDavid Howells 158845222b9eSDavid Howells switch (call->unmarshall) { 158945222b9eSDavid Howells case 0: 159045222b9eSDavid Howells call->offset = 0; 159145222b9eSDavid Howells call->unmarshall++; 159245222b9eSDavid Howells 159345222b9eSDavid Howells /* extract the returned status record */ 159445222b9eSDavid Howells case 1: 159545222b9eSDavid Howells _debug("extract status"); 1596d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1597d001648eSDavid Howells 12 * 4, true); 1598372ee163SDavid Howells if (ret < 0) 1599372ee163SDavid Howells return ret; 160045222b9eSDavid Howells 160145222b9eSDavid Howells bp = call->buffer; 160297e3043aSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]); 160345222b9eSDavid Howells call->offset = 0; 160445222b9eSDavid Howells call->unmarshall++; 160545222b9eSDavid Howells 160645222b9eSDavid Howells /* extract the volume name length */ 160745222b9eSDavid Howells case 2: 1608d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1609372ee163SDavid Howells if (ret < 0) 1610372ee163SDavid Howells return ret; 161145222b9eSDavid Howells 161245222b9eSDavid Howells call->count = ntohl(call->tmp); 161345222b9eSDavid Howells _debug("volname length: %u", call->count); 161445222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 16155f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 161645222b9eSDavid Howells call->offset = 0; 161745222b9eSDavid Howells call->unmarshall++; 161845222b9eSDavid Howells 161945222b9eSDavid Howells /* extract the volume name */ 162045222b9eSDavid Howells case 3: 162145222b9eSDavid Howells _debug("extract volname"); 162245222b9eSDavid Howells if (call->count > 0) { 162397e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1624d001648eSDavid Howells call->count, true); 1625372ee163SDavid Howells if (ret < 0) 1626372ee163SDavid Howells return ret; 162745222b9eSDavid Howells } 162845222b9eSDavid Howells 162997e3043aSDavid Howells p = call->reply[2]; 163045222b9eSDavid Howells p[call->count] = 0; 163145222b9eSDavid Howells _debug("volname '%s'", p); 163245222b9eSDavid Howells 163345222b9eSDavid Howells call->offset = 0; 163445222b9eSDavid Howells call->unmarshall++; 163545222b9eSDavid Howells 163645222b9eSDavid Howells /* extract the volume name padding */ 163745222b9eSDavid Howells if ((call->count & 3) == 0) { 163845222b9eSDavid Howells call->unmarshall++; 163945222b9eSDavid Howells goto no_volname_padding; 164045222b9eSDavid Howells } 164145222b9eSDavid Howells call->count = 4 - (call->count & 3); 164245222b9eSDavid Howells 164345222b9eSDavid Howells case 4: 1644d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1645d001648eSDavid Howells call->count, true); 1646372ee163SDavid Howells if (ret < 0) 1647372ee163SDavid Howells return ret; 164845222b9eSDavid Howells 164945222b9eSDavid Howells call->offset = 0; 165045222b9eSDavid Howells call->unmarshall++; 165145222b9eSDavid Howells no_volname_padding: 165245222b9eSDavid Howells 165345222b9eSDavid Howells /* extract the offline message length */ 165445222b9eSDavid Howells case 5: 1655d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1656372ee163SDavid Howells if (ret < 0) 1657372ee163SDavid Howells return ret; 165845222b9eSDavid Howells 165945222b9eSDavid Howells call->count = ntohl(call->tmp); 166045222b9eSDavid Howells _debug("offline msg length: %u", call->count); 166145222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 16625f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 166345222b9eSDavid Howells call->offset = 0; 166445222b9eSDavid Howells call->unmarshall++; 166545222b9eSDavid Howells 166645222b9eSDavid Howells /* extract the offline message */ 166745222b9eSDavid Howells case 6: 166845222b9eSDavid Howells _debug("extract offline"); 166945222b9eSDavid Howells if (call->count > 0) { 167097e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1671d001648eSDavid Howells call->count, true); 1672372ee163SDavid Howells if (ret < 0) 1673372ee163SDavid Howells return ret; 167445222b9eSDavid Howells } 167545222b9eSDavid Howells 167697e3043aSDavid Howells p = call->reply[2]; 167745222b9eSDavid Howells p[call->count] = 0; 167845222b9eSDavid Howells _debug("offline '%s'", p); 167945222b9eSDavid Howells 168045222b9eSDavid Howells call->offset = 0; 168145222b9eSDavid Howells call->unmarshall++; 168245222b9eSDavid Howells 168345222b9eSDavid Howells /* extract the offline message padding */ 168445222b9eSDavid Howells if ((call->count & 3) == 0) { 168545222b9eSDavid Howells call->unmarshall++; 168645222b9eSDavid Howells goto no_offline_padding; 168745222b9eSDavid Howells } 168845222b9eSDavid Howells call->count = 4 - (call->count & 3); 168945222b9eSDavid Howells 169045222b9eSDavid Howells case 7: 1691d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1692d001648eSDavid Howells call->count, true); 1693372ee163SDavid Howells if (ret < 0) 1694372ee163SDavid Howells return ret; 169545222b9eSDavid Howells 169645222b9eSDavid Howells call->offset = 0; 169745222b9eSDavid Howells call->unmarshall++; 169845222b9eSDavid Howells no_offline_padding: 169945222b9eSDavid Howells 170045222b9eSDavid Howells /* extract the message of the day length */ 170145222b9eSDavid Howells case 8: 1702d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1703372ee163SDavid Howells if (ret < 0) 1704372ee163SDavid Howells return ret; 170545222b9eSDavid Howells 170645222b9eSDavid Howells call->count = ntohl(call->tmp); 170745222b9eSDavid Howells _debug("motd length: %u", call->count); 170845222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 17095f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 171045222b9eSDavid Howells call->offset = 0; 171145222b9eSDavid Howells call->unmarshall++; 171245222b9eSDavid Howells 171345222b9eSDavid Howells /* extract the message of the day */ 171445222b9eSDavid Howells case 9: 171545222b9eSDavid Howells _debug("extract motd"); 171645222b9eSDavid Howells if (call->count > 0) { 171797e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1718d001648eSDavid Howells call->count, true); 1719372ee163SDavid Howells if (ret < 0) 1720372ee163SDavid Howells return ret; 172145222b9eSDavid Howells } 172245222b9eSDavid Howells 172397e3043aSDavid Howells p = call->reply[2]; 172445222b9eSDavid Howells p[call->count] = 0; 172545222b9eSDavid Howells _debug("motd '%s'", p); 172645222b9eSDavid Howells 172745222b9eSDavid Howells call->offset = 0; 172845222b9eSDavid Howells call->unmarshall++; 172945222b9eSDavid Howells 173045222b9eSDavid Howells /* extract the message of the day padding */ 1731d001648eSDavid Howells call->count = (4 - (call->count & 3)) & 3; 173245222b9eSDavid Howells 173345222b9eSDavid Howells case 10: 1734d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1735d001648eSDavid Howells call->count, false); 1736372ee163SDavid Howells if (ret < 0) 1737372ee163SDavid Howells return ret; 173845222b9eSDavid Howells 173945222b9eSDavid Howells call->offset = 0; 174045222b9eSDavid Howells call->unmarshall++; 174145222b9eSDavid Howells case 11: 174245222b9eSDavid Howells break; 174345222b9eSDavid Howells } 174445222b9eSDavid Howells 174545222b9eSDavid Howells _leave(" = 0 [done]"); 174645222b9eSDavid Howells return 0; 174745222b9eSDavid Howells } 174845222b9eSDavid Howells 174945222b9eSDavid Howells /* 175045222b9eSDavid Howells * destroy an FS.GetVolumeStatus call 175145222b9eSDavid Howells */ 175245222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call) 175345222b9eSDavid Howells { 175497e3043aSDavid Howells kfree(call->reply[2]); 175597e3043aSDavid Howells call->reply[2] = NULL; 175645222b9eSDavid Howells afs_flat_call_destructor(call); 175745222b9eSDavid Howells } 175845222b9eSDavid Howells 175945222b9eSDavid Howells /* 176045222b9eSDavid Howells * FS.GetVolumeStatus operation type 176145222b9eSDavid Howells */ 176245222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 176345222b9eSDavid Howells .name = "FS.GetVolumeStatus", 1764025db80cSDavid Howells .op = afs_FS_GetVolumeStatus, 176545222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 176645222b9eSDavid Howells .destructor = afs_get_volume_status_call_destructor, 176745222b9eSDavid Howells }; 176845222b9eSDavid Howells 176945222b9eSDavid Howells /* 177045222b9eSDavid Howells * fetch the status of a volume 177145222b9eSDavid Howells */ 17728b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc, 1773d2ddc776SDavid Howells struct afs_volume_status *vs) 177445222b9eSDavid Howells { 1775d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 177645222b9eSDavid Howells struct afs_call *call; 1777f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 177845222b9eSDavid Howells __be32 *bp; 177945222b9eSDavid Howells void *tmpbuf; 178045222b9eSDavid Howells 178145222b9eSDavid Howells _enter(""); 178245222b9eSDavid Howells 178345222b9eSDavid Howells tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); 178445222b9eSDavid Howells if (!tmpbuf) 178545222b9eSDavid Howells return -ENOMEM; 178645222b9eSDavid Howells 1787f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); 178845222b9eSDavid Howells if (!call) { 178945222b9eSDavid Howells kfree(tmpbuf); 179045222b9eSDavid Howells return -ENOMEM; 179145222b9eSDavid Howells } 179245222b9eSDavid Howells 1793d2ddc776SDavid Howells call->key = fc->key; 179497e3043aSDavid Howells call->reply[0] = vnode; 179597e3043aSDavid Howells call->reply[1] = vs; 179697e3043aSDavid Howells call->reply[2] = tmpbuf; 179745222b9eSDavid Howells 179845222b9eSDavid Howells /* marshall the parameters */ 179945222b9eSDavid Howells bp = call->request; 180045222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 180145222b9eSDavid Howells bp[1] = htonl(vnode->fid.vid); 180245222b9eSDavid Howells 1803d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1804025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1805d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 180645222b9eSDavid Howells } 1807e8d6c554SDavid Howells 1808e8d6c554SDavid Howells /* 1809e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1810e8d6c554SDavid Howells */ 1811d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call) 1812e8d6c554SDavid Howells { 1813e8d6c554SDavid Howells const __be32 *bp; 1814372ee163SDavid Howells int ret; 1815e8d6c554SDavid Howells 1816d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1817e8d6c554SDavid Howells 1818d001648eSDavid Howells ret = afs_transfer_reply(call); 1819372ee163SDavid Howells if (ret < 0) 1820372ee163SDavid Howells return ret; 1821e8d6c554SDavid Howells 1822e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1823e8d6c554SDavid Howells bp = call->buffer; 182497e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 1825e8d6c554SDavid Howells 1826e8d6c554SDavid Howells _leave(" = 0 [done]"); 1827e8d6c554SDavid Howells return 0; 1828e8d6c554SDavid Howells } 1829e8d6c554SDavid Howells 1830e8d6c554SDavid Howells /* 1831e8d6c554SDavid Howells * FS.SetLock operation type 1832e8d6c554SDavid Howells */ 1833e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1834e8d6c554SDavid Howells .name = "FS.SetLock", 1835025db80cSDavid Howells .op = afs_FS_SetLock, 1836e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1837e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1838e8d6c554SDavid Howells }; 1839e8d6c554SDavid Howells 1840e8d6c554SDavid Howells /* 1841e8d6c554SDavid Howells * FS.ExtendLock operation type 1842e8d6c554SDavid Howells */ 1843e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1844e8d6c554SDavid Howells .name = "FS.ExtendLock", 1845025db80cSDavid Howells .op = afs_FS_ExtendLock, 1846e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1847e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1848e8d6c554SDavid Howells }; 1849e8d6c554SDavid Howells 1850e8d6c554SDavid Howells /* 1851e8d6c554SDavid Howells * FS.ReleaseLock operation type 1852e8d6c554SDavid Howells */ 1853e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1854e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1855025db80cSDavid Howells .op = afs_FS_ReleaseLock, 1856e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1857e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1858e8d6c554SDavid Howells }; 1859e8d6c554SDavid Howells 1860e8d6c554SDavid Howells /* 1861d2ddc776SDavid Howells * Set a lock on a file 1862e8d6c554SDavid Howells */ 1863d2ddc776SDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) 1864e8d6c554SDavid Howells { 1865d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1866e8d6c554SDavid Howells struct afs_call *call; 1867f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1868e8d6c554SDavid Howells __be32 *bp; 1869e8d6c554SDavid Howells 1870e8d6c554SDavid Howells _enter(""); 1871e8d6c554SDavid Howells 1872f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4); 1873e8d6c554SDavid Howells if (!call) 1874e8d6c554SDavid Howells return -ENOMEM; 1875e8d6c554SDavid Howells 1876d2ddc776SDavid Howells call->key = fc->key; 187797e3043aSDavid Howells call->reply[0] = vnode; 1878e8d6c554SDavid Howells 1879e8d6c554SDavid Howells /* marshall the parameters */ 1880e8d6c554SDavid Howells bp = call->request; 1881e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1882e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1883e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1884e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1885e8d6c554SDavid Howells *bp++ = htonl(type); 1886e8d6c554SDavid Howells 1887d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1888025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1889d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1890e8d6c554SDavid Howells } 1891e8d6c554SDavid Howells 1892e8d6c554SDavid Howells /* 1893e8d6c554SDavid Howells * extend a lock on a file 1894e8d6c554SDavid Howells */ 1895d2ddc776SDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc) 1896e8d6c554SDavid Howells { 1897d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1898e8d6c554SDavid Howells struct afs_call *call; 1899f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1900e8d6c554SDavid Howells __be32 *bp; 1901e8d6c554SDavid Howells 1902e8d6c554SDavid Howells _enter(""); 1903e8d6c554SDavid Howells 1904f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); 1905e8d6c554SDavid Howells if (!call) 1906e8d6c554SDavid Howells return -ENOMEM; 1907e8d6c554SDavid Howells 1908d2ddc776SDavid Howells call->key = fc->key; 190997e3043aSDavid Howells call->reply[0] = vnode; 1910e8d6c554SDavid Howells 1911e8d6c554SDavid Howells /* marshall the parameters */ 1912e8d6c554SDavid Howells bp = call->request; 1913e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1914e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1915e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1916e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1917e8d6c554SDavid Howells 1918d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1919025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1920d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1921e8d6c554SDavid Howells } 1922e8d6c554SDavid Howells 1923e8d6c554SDavid Howells /* 1924e8d6c554SDavid Howells * release a lock on a file 1925e8d6c554SDavid Howells */ 1926d2ddc776SDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc) 1927e8d6c554SDavid Howells { 1928d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1929e8d6c554SDavid Howells struct afs_call *call; 1930f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1931e8d6c554SDavid Howells __be32 *bp; 1932e8d6c554SDavid Howells 1933e8d6c554SDavid Howells _enter(""); 1934e8d6c554SDavid Howells 1935f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1936e8d6c554SDavid Howells if (!call) 1937e8d6c554SDavid Howells return -ENOMEM; 1938e8d6c554SDavid Howells 1939d2ddc776SDavid Howells call->key = fc->key; 194097e3043aSDavid Howells call->reply[0] = vnode; 1941e8d6c554SDavid Howells 1942e8d6c554SDavid Howells /* marshall the parameters */ 1943e8d6c554SDavid Howells bp = call->request; 1944e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1945e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1946e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1947e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1948e8d6c554SDavid Howells 1949d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1950025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1951d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1952c435ee34SDavid Howells } 1953c435ee34SDavid Howells 1954c435ee34SDavid Howells /* 1955c435ee34SDavid Howells * Deliver reply data to an FS.GiveUpAllCallBacks operation. 1956c435ee34SDavid Howells */ 1957c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call) 1958c435ee34SDavid Howells { 1959c435ee34SDavid Howells return afs_transfer_reply(call); 1960c435ee34SDavid Howells } 1961c435ee34SDavid Howells 1962c435ee34SDavid Howells /* 1963c435ee34SDavid Howells * FS.GiveUpAllCallBacks operation type 1964c435ee34SDavid Howells */ 1965c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = { 1966c435ee34SDavid Howells .name = "FS.GiveUpAllCallBacks", 1967025db80cSDavid Howells .op = afs_FS_GiveUpAllCallBacks, 1968c435ee34SDavid Howells .deliver = afs_deliver_fs_give_up_all_callbacks, 1969c435ee34SDavid Howells .destructor = afs_flat_call_destructor, 1970c435ee34SDavid Howells }; 1971c435ee34SDavid Howells 1972c435ee34SDavid Howells /* 1973c435ee34SDavid Howells * Flush all the callbacks we have on a server. 1974c435ee34SDavid Howells */ 1975d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net, 1976d2ddc776SDavid Howells struct afs_server *server, 19778b2a464cSDavid Howells struct afs_addr_cursor *ac, 1978d2ddc776SDavid Howells struct key *key) 1979c435ee34SDavid Howells { 1980c435ee34SDavid Howells struct afs_call *call; 1981c435ee34SDavid Howells __be32 *bp; 1982c435ee34SDavid Howells 1983c435ee34SDavid Howells _enter(""); 1984c435ee34SDavid Howells 1985d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0); 1986c435ee34SDavid Howells if (!call) 1987c435ee34SDavid Howells return -ENOMEM; 1988c435ee34SDavid Howells 1989c435ee34SDavid Howells call->key = key; 1990c435ee34SDavid Howells 1991c435ee34SDavid Howells /* marshall the parameters */ 1992c435ee34SDavid Howells bp = call->request; 1993c435ee34SDavid Howells *bp++ = htonl(FSGIVEUPALLCALLBACKS); 1994c435ee34SDavid Howells 1995c435ee34SDavid Howells /* Can't take a ref on server */ 1996d2ddc776SDavid Howells return afs_make_call(ac, call, GFP_NOFS, false); 1997d2ddc776SDavid Howells } 1998d2ddc776SDavid Howells 1999d2ddc776SDavid Howells /* 2000d2ddc776SDavid Howells * Deliver reply data to an FS.GetCapabilities operation. 2001d2ddc776SDavid Howells */ 2002d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call) 2003d2ddc776SDavid Howells { 2004d2ddc776SDavid Howells u32 count; 2005d2ddc776SDavid Howells int ret; 2006d2ddc776SDavid Howells 2007d2ddc776SDavid Howells _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); 2008d2ddc776SDavid Howells 2009d2ddc776SDavid Howells again: 2010d2ddc776SDavid Howells switch (call->unmarshall) { 2011d2ddc776SDavid Howells case 0: 2012d2ddc776SDavid Howells call->offset = 0; 2013d2ddc776SDavid Howells call->unmarshall++; 2014d2ddc776SDavid Howells 2015d2ddc776SDavid Howells /* Extract the capabilities word count */ 2016d2ddc776SDavid Howells case 1: 2017d2ddc776SDavid Howells ret = afs_extract_data(call, &call->tmp, 2018d2ddc776SDavid Howells 1 * sizeof(__be32), 2019d2ddc776SDavid Howells true); 2020d2ddc776SDavid Howells if (ret < 0) 2021d2ddc776SDavid Howells return ret; 2022d2ddc776SDavid Howells 2023d2ddc776SDavid Howells count = ntohl(call->tmp); 2024d2ddc776SDavid Howells 2025d2ddc776SDavid Howells call->count = count; 2026d2ddc776SDavid Howells call->count2 = count; 2027d2ddc776SDavid Howells call->offset = 0; 2028d2ddc776SDavid Howells call->unmarshall++; 2029d2ddc776SDavid Howells 2030d2ddc776SDavid Howells /* Extract capabilities words */ 2031d2ddc776SDavid Howells case 2: 2032d2ddc776SDavid Howells count = min(call->count, 16U); 2033d2ddc776SDavid Howells ret = afs_extract_data(call, call->buffer, 2034d2ddc776SDavid Howells count * sizeof(__be32), 2035d2ddc776SDavid Howells call->count > 16); 2036d2ddc776SDavid Howells if (ret < 0) 2037d2ddc776SDavid Howells return ret; 2038d2ddc776SDavid Howells 2039d2ddc776SDavid Howells /* TODO: Examine capabilities */ 2040d2ddc776SDavid Howells 2041d2ddc776SDavid Howells call->count -= count; 2042d2ddc776SDavid Howells if (call->count > 0) 2043d2ddc776SDavid Howells goto again; 2044d2ddc776SDavid Howells call->offset = 0; 2045d2ddc776SDavid Howells call->unmarshall++; 2046d2ddc776SDavid Howells break; 2047d2ddc776SDavid Howells } 2048d2ddc776SDavid Howells 2049d2ddc776SDavid Howells _leave(" = 0 [done]"); 2050d2ddc776SDavid Howells return 0; 2051d2ddc776SDavid Howells } 2052d2ddc776SDavid Howells 2053d2ddc776SDavid Howells /* 2054d2ddc776SDavid Howells * FS.GetCapabilities operation type 2055d2ddc776SDavid Howells */ 2056d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = { 2057d2ddc776SDavid Howells .name = "FS.GetCapabilities", 2058025db80cSDavid Howells .op = afs_FS_GetCapabilities, 2059d2ddc776SDavid Howells .deliver = afs_deliver_fs_get_capabilities, 2060d2ddc776SDavid Howells .destructor = afs_flat_call_destructor, 2061d2ddc776SDavid Howells }; 2062d2ddc776SDavid Howells 2063d2ddc776SDavid Howells /* 2064d2ddc776SDavid Howells * Probe a fileserver for the capabilities that it supports. This can 2065d2ddc776SDavid Howells * return up to 196 words. 2066d2ddc776SDavid Howells */ 2067d2ddc776SDavid Howells int afs_fs_get_capabilities(struct afs_net *net, 2068d2ddc776SDavid Howells struct afs_server *server, 2069d2ddc776SDavid Howells struct afs_addr_cursor *ac, 2070d2ddc776SDavid Howells struct key *key) 2071d2ddc776SDavid Howells { 2072d2ddc776SDavid Howells struct afs_call *call; 2073d2ddc776SDavid Howells __be32 *bp; 2074d2ddc776SDavid Howells 2075d2ddc776SDavid Howells _enter(""); 2076d2ddc776SDavid Howells 2077d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4); 2078d2ddc776SDavid Howells if (!call) 2079d2ddc776SDavid Howells return -ENOMEM; 2080d2ddc776SDavid Howells 2081d2ddc776SDavid Howells call->key = key; 2082d2ddc776SDavid Howells 2083d2ddc776SDavid Howells /* marshall the parameters */ 2084d2ddc776SDavid Howells bp = call->request; 2085d2ddc776SDavid Howells *bp++ = htonl(FSGETCAPABILITIES); 2086d2ddc776SDavid Howells 2087d2ddc776SDavid Howells /* Can't take a ref on server */ 2088025db80cSDavid Howells trace_afs_make_fs_call(call, NULL); 2089d2ddc776SDavid Howells return afs_make_call(ac, call, GFP_NOFS, false); 2090e8d6c554SDavid Howells } 20915cf9dd55SDavid Howells 20925cf9dd55SDavid Howells /* 20935cf9dd55SDavid Howells * Deliver reply data to an FS.FetchStatus with no vnode. 20945cf9dd55SDavid Howells */ 20955cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call) 20965cf9dd55SDavid Howells { 20975cf9dd55SDavid Howells struct afs_file_status *status = call->reply[1]; 20985cf9dd55SDavid Howells struct afs_callback *callback = call->reply[2]; 20995cf9dd55SDavid Howells struct afs_volsync *volsync = call->reply[3]; 21005cf9dd55SDavid Howells struct afs_vnode *vnode = call->reply[0]; 21015cf9dd55SDavid Howells const __be32 *bp; 21025cf9dd55SDavid Howells int ret; 21035cf9dd55SDavid Howells 21045cf9dd55SDavid Howells ret = afs_transfer_reply(call); 21055cf9dd55SDavid Howells if (ret < 0) 21065cf9dd55SDavid Howells return ret; 21075cf9dd55SDavid Howells 21085cf9dd55SDavid Howells _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); 21095cf9dd55SDavid Howells 21105cf9dd55SDavid Howells /* unmarshall the reply once we've received all of it */ 21115cf9dd55SDavid Howells bp = call->buffer; 2112c875c76aSDavid Howells afs_decode_status(call, &bp, status, vnode, 21130c3a5ac2SDavid Howells &call->expected_version, NULL); 21145cf9dd55SDavid Howells callback[call->count].version = ntohl(bp[0]); 21155cf9dd55SDavid Howells callback[call->count].expiry = ntohl(bp[1]); 21165cf9dd55SDavid Howells callback[call->count].type = ntohl(bp[2]); 21175cf9dd55SDavid Howells if (vnode) 21185cf9dd55SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 21195cf9dd55SDavid Howells else 21205cf9dd55SDavid Howells bp += 3; 21215cf9dd55SDavid Howells if (volsync) 21225cf9dd55SDavid Howells xdr_decode_AFSVolSync(&bp, volsync); 21235cf9dd55SDavid Howells 21245cf9dd55SDavid Howells _leave(" = 0 [done]"); 21255cf9dd55SDavid Howells return 0; 21265cf9dd55SDavid Howells } 21275cf9dd55SDavid Howells 21285cf9dd55SDavid Howells /* 21295cf9dd55SDavid Howells * FS.FetchStatus operation type 21305cf9dd55SDavid Howells */ 21315cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 21325cf9dd55SDavid Howells .name = "FS.FetchStatus", 21335cf9dd55SDavid Howells .op = afs_FS_FetchStatus, 21345cf9dd55SDavid Howells .deliver = afs_deliver_fs_fetch_status, 21355cf9dd55SDavid Howells .destructor = afs_flat_call_destructor, 21365cf9dd55SDavid Howells }; 21375cf9dd55SDavid Howells 21385cf9dd55SDavid Howells /* 21395cf9dd55SDavid Howells * Fetch the status information for a fid without needing a vnode handle. 21405cf9dd55SDavid Howells */ 21415cf9dd55SDavid Howells int afs_fs_fetch_status(struct afs_fs_cursor *fc, 21425cf9dd55SDavid Howells struct afs_net *net, 21435cf9dd55SDavid Howells struct afs_fid *fid, 21445cf9dd55SDavid Howells struct afs_file_status *status, 21455cf9dd55SDavid Howells struct afs_callback *callback, 21465cf9dd55SDavid Howells struct afs_volsync *volsync) 21475cf9dd55SDavid Howells { 21485cf9dd55SDavid Howells struct afs_call *call; 21495cf9dd55SDavid Howells __be32 *bp; 21505cf9dd55SDavid Howells 21515cf9dd55SDavid Howells _enter(",%x,{%x:%u},,", 21525cf9dd55SDavid Howells key_serial(fc->key), fid->vid, fid->vnode); 21535cf9dd55SDavid Howells 21545cf9dd55SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 21555cf9dd55SDavid Howells if (!call) { 21565cf9dd55SDavid Howells fc->ac.error = -ENOMEM; 21575cf9dd55SDavid Howells return -ENOMEM; 21585cf9dd55SDavid Howells } 21595cf9dd55SDavid Howells 21605cf9dd55SDavid Howells call->key = fc->key; 21615cf9dd55SDavid Howells call->reply[0] = NULL; /* vnode for fid[0] */ 21625cf9dd55SDavid Howells call->reply[1] = status; 21635cf9dd55SDavid Howells call->reply[2] = callback; 21645cf9dd55SDavid Howells call->reply[3] = volsync; 21650c3a5ac2SDavid Howells call->expected_version = 1; /* vnode->status.data_version */ 21665cf9dd55SDavid Howells 21675cf9dd55SDavid Howells /* marshall the parameters */ 21685cf9dd55SDavid Howells bp = call->request; 21695cf9dd55SDavid Howells bp[0] = htonl(FSFETCHSTATUS); 21705cf9dd55SDavid Howells bp[1] = htonl(fid->vid); 21715cf9dd55SDavid Howells bp[2] = htonl(fid->vnode); 21725cf9dd55SDavid Howells bp[3] = htonl(fid->unique); 21735cf9dd55SDavid Howells 21745cf9dd55SDavid Howells call->cb_break = fc->cb_break; 21755cf9dd55SDavid Howells afs_use_fs_server(call, fc->cbi); 21765cf9dd55SDavid Howells trace_afs_make_fs_call(call, fid); 21775cf9dd55SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 21785cf9dd55SDavid Howells } 21795cf9dd55SDavid Howells 21805cf9dd55SDavid Howells /* 21815cf9dd55SDavid Howells * Deliver reply data to an FS.InlineBulkStatus call 21825cf9dd55SDavid Howells */ 21835cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call) 21845cf9dd55SDavid Howells { 21855cf9dd55SDavid Howells struct afs_file_status *statuses; 21865cf9dd55SDavid Howells struct afs_callback *callbacks; 21875cf9dd55SDavid Howells struct afs_vnode *vnode = call->reply[0]; 21885cf9dd55SDavid Howells const __be32 *bp; 21895cf9dd55SDavid Howells u32 tmp; 21905cf9dd55SDavid Howells int ret; 21915cf9dd55SDavid Howells 21925cf9dd55SDavid Howells _enter("{%u}", call->unmarshall); 21935cf9dd55SDavid Howells 21945cf9dd55SDavid Howells switch (call->unmarshall) { 21955cf9dd55SDavid Howells case 0: 21965cf9dd55SDavid Howells call->offset = 0; 21975cf9dd55SDavid Howells call->unmarshall++; 21985cf9dd55SDavid Howells 21995cf9dd55SDavid Howells /* Extract the file status count and array in two steps */ 22005cf9dd55SDavid Howells case 1: 22015cf9dd55SDavid Howells _debug("extract status count"); 22025cf9dd55SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 22035cf9dd55SDavid Howells if (ret < 0) 22045cf9dd55SDavid Howells return ret; 22055cf9dd55SDavid Howells 22065cf9dd55SDavid Howells tmp = ntohl(call->tmp); 22075cf9dd55SDavid Howells _debug("status count: %u/%u", tmp, call->count2); 22085cf9dd55SDavid Howells if (tmp != call->count2) 22095f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 22105cf9dd55SDavid Howells 22115cf9dd55SDavid Howells call->count = 0; 22125cf9dd55SDavid Howells call->unmarshall++; 22135cf9dd55SDavid Howells more_counts: 22145cf9dd55SDavid Howells call->offset = 0; 22155cf9dd55SDavid Howells 22165cf9dd55SDavid Howells case 2: 22175cf9dd55SDavid Howells _debug("extract status array %u", call->count); 22185cf9dd55SDavid Howells ret = afs_extract_data(call, call->buffer, 21 * 4, true); 22195cf9dd55SDavid Howells if (ret < 0) 22205cf9dd55SDavid Howells return ret; 22215cf9dd55SDavid Howells 22225cf9dd55SDavid Howells bp = call->buffer; 22235cf9dd55SDavid Howells statuses = call->reply[1]; 2224c875c76aSDavid Howells if (afs_decode_status(call, &bp, &statuses[call->count], 22255cf9dd55SDavid Howells call->count == 0 ? vnode : NULL, 2226dd9fbcb8SDavid Howells NULL, NULL) < 0) 22275f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 22285cf9dd55SDavid Howells 22295cf9dd55SDavid Howells call->count++; 22305cf9dd55SDavid Howells if (call->count < call->count2) 22315cf9dd55SDavid Howells goto more_counts; 22325cf9dd55SDavid Howells 22335cf9dd55SDavid Howells call->count = 0; 22345cf9dd55SDavid Howells call->unmarshall++; 22355cf9dd55SDavid Howells call->offset = 0; 22365cf9dd55SDavid Howells 22375cf9dd55SDavid Howells /* Extract the callback count and array in two steps */ 22385cf9dd55SDavid Howells case 3: 22395cf9dd55SDavid Howells _debug("extract CB count"); 22405cf9dd55SDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 22415cf9dd55SDavid Howells if (ret < 0) 22425cf9dd55SDavid Howells return ret; 22435cf9dd55SDavid Howells 22445cf9dd55SDavid Howells tmp = ntohl(call->tmp); 22455cf9dd55SDavid Howells _debug("CB count: %u", tmp); 22465cf9dd55SDavid Howells if (tmp != call->count2) 22475f702c8eSDavid Howells return afs_protocol_error(call, -EBADMSG); 22485cf9dd55SDavid Howells call->count = 0; 22495cf9dd55SDavid Howells call->unmarshall++; 22505cf9dd55SDavid Howells more_cbs: 22515cf9dd55SDavid Howells call->offset = 0; 22525cf9dd55SDavid Howells 22535cf9dd55SDavid Howells case 4: 22545cf9dd55SDavid Howells _debug("extract CB array"); 22555cf9dd55SDavid Howells ret = afs_extract_data(call, call->buffer, 3 * 4, true); 22565cf9dd55SDavid Howells if (ret < 0) 22575cf9dd55SDavid Howells return ret; 22585cf9dd55SDavid Howells 22595cf9dd55SDavid Howells _debug("unmarshall CB array"); 22605cf9dd55SDavid Howells bp = call->buffer; 22615cf9dd55SDavid Howells callbacks = call->reply[2]; 22625cf9dd55SDavid Howells callbacks[call->count].version = ntohl(bp[0]); 22635cf9dd55SDavid Howells callbacks[call->count].expiry = ntohl(bp[1]); 22645cf9dd55SDavid Howells callbacks[call->count].type = ntohl(bp[2]); 22655cf9dd55SDavid Howells statuses = call->reply[1]; 22665cf9dd55SDavid Howells if (call->count == 0 && vnode && statuses[0].abort_code == 0) 22675cf9dd55SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 22685cf9dd55SDavid Howells call->count++; 22695cf9dd55SDavid Howells if (call->count < call->count2) 22705cf9dd55SDavid Howells goto more_cbs; 22715cf9dd55SDavid Howells 22725cf9dd55SDavid Howells call->offset = 0; 22735cf9dd55SDavid Howells call->unmarshall++; 22745cf9dd55SDavid Howells 22755cf9dd55SDavid Howells case 5: 22765cf9dd55SDavid Howells ret = afs_extract_data(call, call->buffer, 6 * 4, false); 22775cf9dd55SDavid Howells if (ret < 0) 22785cf9dd55SDavid Howells return ret; 22795cf9dd55SDavid Howells 22805cf9dd55SDavid Howells bp = call->buffer; 22815cf9dd55SDavid Howells if (call->reply[3]) 22825cf9dd55SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply[3]); 22835cf9dd55SDavid Howells 22845cf9dd55SDavid Howells call->offset = 0; 22855cf9dd55SDavid Howells call->unmarshall++; 22865cf9dd55SDavid Howells 22875cf9dd55SDavid Howells case 6: 22885cf9dd55SDavid Howells break; 22895cf9dd55SDavid Howells } 22905cf9dd55SDavid Howells 22915cf9dd55SDavid Howells _leave(" = 0 [done]"); 22925cf9dd55SDavid Howells return 0; 22935cf9dd55SDavid Howells } 22945cf9dd55SDavid Howells 22955cf9dd55SDavid Howells /* 22965cf9dd55SDavid Howells * FS.InlineBulkStatus operation type 22975cf9dd55SDavid Howells */ 22985cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = { 22995cf9dd55SDavid Howells .name = "FS.InlineBulkStatus", 23005cf9dd55SDavid Howells .op = afs_FS_InlineBulkStatus, 23015cf9dd55SDavid Howells .deliver = afs_deliver_fs_inline_bulk_status, 23025cf9dd55SDavid Howells .destructor = afs_flat_call_destructor, 23035cf9dd55SDavid Howells }; 23045cf9dd55SDavid Howells 23055cf9dd55SDavid Howells /* 23065cf9dd55SDavid Howells * Fetch the status information for up to 50 files 23075cf9dd55SDavid Howells */ 23085cf9dd55SDavid Howells int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, 23095cf9dd55SDavid Howells struct afs_net *net, 23105cf9dd55SDavid Howells struct afs_fid *fids, 23115cf9dd55SDavid Howells struct afs_file_status *statuses, 23125cf9dd55SDavid Howells struct afs_callback *callbacks, 23135cf9dd55SDavid Howells unsigned int nr_fids, 23145cf9dd55SDavid Howells struct afs_volsync *volsync) 23155cf9dd55SDavid Howells { 23165cf9dd55SDavid Howells struct afs_call *call; 23175cf9dd55SDavid Howells __be32 *bp; 23185cf9dd55SDavid Howells int i; 23195cf9dd55SDavid Howells 23205cf9dd55SDavid Howells _enter(",%x,{%x:%u},%u", 23215cf9dd55SDavid Howells key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids); 23225cf9dd55SDavid Howells 23235cf9dd55SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus, 23245cf9dd55SDavid Howells (2 + nr_fids * 3) * 4, 23255cf9dd55SDavid Howells 21 * 4); 23265cf9dd55SDavid Howells if (!call) { 23275cf9dd55SDavid Howells fc->ac.error = -ENOMEM; 23285cf9dd55SDavid Howells return -ENOMEM; 23295cf9dd55SDavid Howells } 23305cf9dd55SDavid Howells 23315cf9dd55SDavid Howells call->key = fc->key; 23325cf9dd55SDavid Howells call->reply[0] = NULL; /* vnode for fid[0] */ 23335cf9dd55SDavid Howells call->reply[1] = statuses; 23345cf9dd55SDavid Howells call->reply[2] = callbacks; 23355cf9dd55SDavid Howells call->reply[3] = volsync; 23365cf9dd55SDavid Howells call->count2 = nr_fids; 23375cf9dd55SDavid Howells 23385cf9dd55SDavid Howells /* marshall the parameters */ 23395cf9dd55SDavid Howells bp = call->request; 23405cf9dd55SDavid Howells *bp++ = htonl(FSINLINEBULKSTATUS); 23415cf9dd55SDavid Howells *bp++ = htonl(nr_fids); 23425cf9dd55SDavid Howells for (i = 0; i < nr_fids; i++) { 23435cf9dd55SDavid Howells *bp++ = htonl(fids[i].vid); 23445cf9dd55SDavid Howells *bp++ = htonl(fids[i].vnode); 23455cf9dd55SDavid Howells *bp++ = htonl(fids[i].unique); 23465cf9dd55SDavid Howells } 23475cf9dd55SDavid Howells 23485cf9dd55SDavid Howells call->cb_break = fc->cb_break; 23495cf9dd55SDavid Howells afs_use_fs_server(call, fc->cbi); 23505cf9dd55SDavid Howells trace_afs_make_fs_call(call, &fids[0]); 23515cf9dd55SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 23525cf9dd55SDavid Howells } 2353