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> 161da177e4SLinus Torvalds #include "internal.h" 1708e0e7c8SDavid Howells #include "afs_fs.h" 181da177e4SLinus Torvalds 19025db80cSDavid Howells static const struct afs_fid afs_zero_fid; 20025db80cSDavid Howells 211da177e4SLinus Torvalds /* 226db3ac3cSDavid Howells * We need somewhere to discard into in case the server helpfully returns more 236db3ac3cSDavid Howells * than we asked for in FS.FetchData{,64}. 246db3ac3cSDavid Howells */ 256db3ac3cSDavid Howells static u8 afs_discard_buffer[64]; 266db3ac3cSDavid Howells 27d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi) 28c435ee34SDavid Howells { 29d2ddc776SDavid Howells call->cbi = afs_get_cb_interest(cbi); 30c435ee34SDavid Howells } 31c435ee34SDavid Howells 326db3ac3cSDavid Howells /* 33260a9803SDavid Howells * decode an AFSFid block 34260a9803SDavid Howells */ 35260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 36260a9803SDavid Howells { 37260a9803SDavid Howells const __be32 *bp = *_bp; 38260a9803SDavid Howells 39260a9803SDavid Howells fid->vid = ntohl(*bp++); 40260a9803SDavid Howells fid->vnode = ntohl(*bp++); 41260a9803SDavid Howells fid->unique = ntohl(*bp++); 42260a9803SDavid Howells *_bp = bp; 43260a9803SDavid Howells } 44260a9803SDavid Howells 45260a9803SDavid Howells /* 4608e0e7c8SDavid Howells * decode an AFSFetchStatus block 471da177e4SLinus Torvalds */ 4808e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 49260a9803SDavid Howells struct afs_file_status *status, 5031143d5dSDavid Howells struct afs_vnode *vnode, 5131143d5dSDavid Howells afs_dataversion_t *store_version) 521da177e4SLinus Torvalds { 5331143d5dSDavid Howells afs_dataversion_t expected_version; 5408e0e7c8SDavid Howells const __be32 *bp = *_bp; 5508e0e7c8SDavid Howells umode_t mode; 56260a9803SDavid Howells u64 data_version, size; 57c435ee34SDavid Howells bool changed = false; 58a0a5386aSEric W. Biederman kuid_t owner; 59a0a5386aSEric W. Biederman kgid_t group; 6008e0e7c8SDavid Howells 61d2ddc776SDavid Howells if (vnode) 62c435ee34SDavid Howells write_seqlock(&vnode->cb_lock); 63c435ee34SDavid Howells 6408e0e7c8SDavid Howells #define EXTRACT(DST) \ 6508e0e7c8SDavid Howells do { \ 6608e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 67c435ee34SDavid Howells if (DST != x) \ 68c435ee34SDavid Howells changed |= true; \ 6908e0e7c8SDavid Howells DST = x; \ 7008e0e7c8SDavid Howells } while (0) 7108e0e7c8SDavid Howells 72260a9803SDavid Howells status->if_version = ntohl(*bp++); 73260a9803SDavid Howells EXTRACT(status->type); 74260a9803SDavid Howells EXTRACT(status->nlink); 75260a9803SDavid Howells size = ntohl(*bp++); 7608e0e7c8SDavid Howells data_version = ntohl(*bp++); 77260a9803SDavid Howells EXTRACT(status->author); 78a0a5386aSEric W. Biederman owner = make_kuid(&init_user_ns, ntohl(*bp++)); 79a0a5386aSEric W. Biederman changed |= !uid_eq(owner, status->owner); 80a0a5386aSEric W. Biederman status->owner = owner; 81260a9803SDavid Howells EXTRACT(status->caller_access); /* call ticket dependent */ 82260a9803SDavid Howells EXTRACT(status->anon_access); 83260a9803SDavid Howells EXTRACT(status->mode); 84be080a6fSDavid Howells bp++; /* parent.vnode */ 85be080a6fSDavid Howells bp++; /* parent.unique */ 8608e0e7c8SDavid Howells bp++; /* seg size */ 87260a9803SDavid Howells status->mtime_client = ntohl(*bp++); 88260a9803SDavid Howells status->mtime_server = ntohl(*bp++); 89a0a5386aSEric W. Biederman group = make_kgid(&init_user_ns, ntohl(*bp++)); 90a0a5386aSEric W. Biederman changed |= !gid_eq(group, status->group); 91a0a5386aSEric W. Biederman status->group = group; 9208e0e7c8SDavid Howells bp++; /* sync counter */ 9308e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 94e8d6c554SDavid Howells EXTRACT(status->lock_count); 95260a9803SDavid Howells size |= (u64) ntohl(*bp++) << 32; 9608e0e7c8SDavid Howells bp++; /* spare 4 */ 9708e0e7c8SDavid Howells *_bp = bp; 9808e0e7c8SDavid Howells 99260a9803SDavid Howells if (size != status->size) { 100260a9803SDavid Howells status->size = size; 101260a9803SDavid Howells changed |= true; 102260a9803SDavid Howells } 103260a9803SDavid Howells status->mode &= S_IALLUGO; 10408e0e7c8SDavid Howells 105260a9803SDavid Howells _debug("vnode time %lx, %lx", 106260a9803SDavid Howells status->mtime_client, status->mtime_server); 107260a9803SDavid Howells 108260a9803SDavid Howells if (vnode) { 109260a9803SDavid Howells if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 110260a9803SDavid Howells _debug("vnode changed"); 111260a9803SDavid Howells i_size_write(&vnode->vfs_inode, size); 112260a9803SDavid Howells vnode->vfs_inode.i_uid = status->owner; 113260a9803SDavid Howells vnode->vfs_inode.i_gid = status->group; 114d6e43f75SDavid Howells vnode->vfs_inode.i_generation = vnode->fid.unique; 115bfe86848SMiklos Szeredi set_nlink(&vnode->vfs_inode, status->nlink); 116260a9803SDavid Howells 11708e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 11808e0e7c8SDavid Howells mode &= ~S_IALLUGO; 119260a9803SDavid Howells mode |= status->mode; 120260a9803SDavid Howells barrier(); 12108e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 12208e0e7c8SDavid Howells } 12308e0e7c8SDavid Howells 124ab94f5d0SMarc Dionne vnode->vfs_inode.i_ctime.tv_sec = status->mtime_client; 12508e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 12608e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 127d6e43f75SDavid Howells vnode->vfs_inode.i_version = data_version; 128260a9803SDavid Howells } 12908e0e7c8SDavid Howells 13031143d5dSDavid Howells expected_version = status->data_version; 13131143d5dSDavid Howells if (store_version) 13231143d5dSDavid Howells expected_version = *store_version; 13331143d5dSDavid Howells 13431143d5dSDavid Howells if (expected_version != data_version) { 135260a9803SDavid Howells status->data_version = data_version; 136260a9803SDavid Howells if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 137260a9803SDavid Howells _debug("vnode modified %llx on {%x:%u}", 138ba3e0e1aSDavid S. Miller (unsigned long long) data_version, 139ba3e0e1aSDavid S. Miller vnode->fid.vid, vnode->fid.vnode); 140c435ee34SDavid Howells set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags); 14108e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1421da177e4SLinus Torvalds } 14331143d5dSDavid Howells } else if (store_version) { 14431143d5dSDavid Howells status->data_version = data_version; 145ec26815aSDavid Howells } 146c435ee34SDavid Howells 147d2ddc776SDavid Howells if (vnode) 148c435ee34SDavid Howells write_sequnlock(&vnode->cb_lock); 149260a9803SDavid Howells } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* 15208e0e7c8SDavid Howells * decode an AFSCallBack block 1531da177e4SLinus Torvalds */ 154c435ee34SDavid Howells static void xdr_decode_AFSCallBack(struct afs_call *call, 155c435ee34SDavid Howells struct afs_vnode *vnode, 156c435ee34SDavid Howells const __be32 **_bp) 1571da177e4SLinus Torvalds { 158d2ddc776SDavid Howells struct afs_cb_interest *old, *cbi = call->cbi; 15908e0e7c8SDavid Howells const __be32 *bp = *_bp; 160c435ee34SDavid Howells u32 cb_expiry; 1611da177e4SLinus Torvalds 162c435ee34SDavid Howells write_seqlock(&vnode->cb_lock); 163c435ee34SDavid Howells 164d2ddc776SDavid Howells if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) { 16508e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 166c435ee34SDavid Howells cb_expiry = ntohl(*bp++); 16708e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 168c435ee34SDavid Howells vnode->cb_expires_at = cb_expiry + ktime_get_real_seconds(); 169d2ddc776SDavid Howells old = vnode->cb_interest; 170d2ddc776SDavid Howells if (old != call->cbi) { 171d2ddc776SDavid Howells vnode->cb_interest = cbi; 172d2ddc776SDavid Howells cbi = old; 173d2ddc776SDavid Howells } 174c435ee34SDavid Howells set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); 175c435ee34SDavid Howells } else { 176c435ee34SDavid Howells bp += 3; 177c435ee34SDavid Howells } 178c435ee34SDavid Howells 179c435ee34SDavid Howells write_sequnlock(&vnode->cb_lock); 180d2ddc776SDavid Howells call->cbi = cbi; 18108e0e7c8SDavid Howells *_bp = bp; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 184260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 185260a9803SDavid Howells struct afs_callback *cb) 186260a9803SDavid Howells { 187260a9803SDavid Howells const __be32 *bp = *_bp; 188260a9803SDavid Howells 189260a9803SDavid Howells cb->version = ntohl(*bp++); 190260a9803SDavid Howells cb->expiry = ntohl(*bp++); 191260a9803SDavid Howells cb->type = ntohl(*bp++); 192260a9803SDavid Howells *_bp = bp; 193260a9803SDavid Howells } 194260a9803SDavid Howells 1951da177e4SLinus Torvalds /* 19608e0e7c8SDavid Howells * decode an AFSVolSync block 1971da177e4SLinus Torvalds */ 19808e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 19908e0e7c8SDavid Howells struct afs_volsync *volsync) 2001da177e4SLinus Torvalds { 20108e0e7c8SDavid Howells const __be32 *bp = *_bp; 2021da177e4SLinus Torvalds 20308e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 20408e0e7c8SDavid Howells bp++; /* spare2 */ 20508e0e7c8SDavid Howells bp++; /* spare3 */ 20608e0e7c8SDavid Howells bp++; /* spare4 */ 20708e0e7c8SDavid Howells bp++; /* spare5 */ 20808e0e7c8SDavid Howells bp++; /* spare6 */ 20908e0e7c8SDavid Howells *_bp = bp; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 21208e0e7c8SDavid Howells /* 21331143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 21431143d5dSDavid Howells */ 21531143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 21631143d5dSDavid Howells { 21731143d5dSDavid Howells __be32 *bp = *_bp; 21831143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 21931143d5dSDavid Howells 22031143d5dSDavid Howells mask = 0; 22131143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 22231143d5dSDavid Howells mask |= AFS_SET_MTIME; 22331143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 22431143d5dSDavid Howells } 22531143d5dSDavid Howells 22631143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 22731143d5dSDavid Howells mask |= AFS_SET_OWNER; 228a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 22931143d5dSDavid Howells } 23031143d5dSDavid Howells 23131143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 23231143d5dSDavid Howells mask |= AFS_SET_GROUP; 233a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 23431143d5dSDavid Howells } 23531143d5dSDavid Howells 23631143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 23731143d5dSDavid Howells mask |= AFS_SET_MODE; 23831143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 23931143d5dSDavid Howells } 24031143d5dSDavid Howells 24131143d5dSDavid Howells *bp++ = htonl(mask); 24231143d5dSDavid Howells *bp++ = htonl(mtime); 24331143d5dSDavid Howells *bp++ = htonl(owner); 24431143d5dSDavid Howells *bp++ = htonl(group); 24531143d5dSDavid Howells *bp++ = htonl(mode); 24631143d5dSDavid Howells *bp++ = 0; /* segment size */ 24731143d5dSDavid Howells *_bp = bp; 24831143d5dSDavid Howells } 24931143d5dSDavid Howells 25031143d5dSDavid Howells /* 25145222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 25245222b9eSDavid Howells */ 25345222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 25445222b9eSDavid Howells struct afs_volume_status *vs) 25545222b9eSDavid Howells { 25645222b9eSDavid Howells const __be32 *bp = *_bp; 25745222b9eSDavid Howells 25845222b9eSDavid Howells vs->vid = ntohl(*bp++); 25945222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 26045222b9eSDavid Howells vs->online = ntohl(*bp++); 26145222b9eSDavid Howells vs->in_service = ntohl(*bp++); 26245222b9eSDavid Howells vs->blessed = ntohl(*bp++); 26345222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 26445222b9eSDavid Howells vs->type = ntohl(*bp++); 26545222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 26645222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 26745222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 26845222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 26945222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 27045222b9eSDavid Howells *_bp = bp; 27145222b9eSDavid Howells } 27245222b9eSDavid Howells 27345222b9eSDavid Howells /* 27408e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 27508e0e7c8SDavid Howells */ 276d001648eSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call) 27708e0e7c8SDavid Howells { 27897e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 27908e0e7c8SDavid Howells const __be32 *bp; 280372ee163SDavid Howells int ret; 2811da177e4SLinus Torvalds 282d001648eSDavid Howells ret = afs_transfer_reply(call); 283372ee163SDavid Howells if (ret < 0) 284372ee163SDavid Howells return ret; 2851da177e4SLinus Torvalds 286c435ee34SDavid Howells _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); 287c435ee34SDavid Howells 28808e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 28908e0e7c8SDavid Howells bp = call->buffer; 29031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 291c435ee34SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 29297e3043aSDavid Howells if (call->reply[1]) 29397e3043aSDavid Howells xdr_decode_AFSVolSync(&bp, call->reply[1]); 2941da177e4SLinus Torvalds 29508e0e7c8SDavid Howells _leave(" = 0 [done]"); 29608e0e7c8SDavid Howells return 0; 297ec26815aSDavid Howells } 29808e0e7c8SDavid Howells 29908e0e7c8SDavid Howells /* 30008e0e7c8SDavid Howells * FS.FetchStatus operation type 30108e0e7c8SDavid Howells */ 30208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 30300d3b7a4SDavid Howells .name = "FS.FetchStatus", 304025db80cSDavid Howells .op = afs_FS_FetchStatus, 30508e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 30608e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 30708e0e7c8SDavid Howells }; 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /* 3101da177e4SLinus Torvalds * fetch the status information for a file 3111da177e4SLinus Torvalds */ 312d2ddc776SDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync) 3131da177e4SLinus Torvalds { 314d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 31508e0e7c8SDavid Howells struct afs_call *call; 316f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 3171da177e4SLinus Torvalds __be32 *bp; 3181da177e4SLinus Torvalds 319416351f2SDavid Howells _enter(",%x,{%x:%u},,", 320d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 3211da177e4SLinus Torvalds 322f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 323d2ddc776SDavid Howells if (!call) { 324d2ddc776SDavid Howells fc->ac.error = -ENOMEM; 32508e0e7c8SDavid Howells return -ENOMEM; 326d2ddc776SDavid Howells } 3271da177e4SLinus Torvalds 328d2ddc776SDavid Howells call->key = fc->key; 32997e3043aSDavid Howells call->reply[0] = vnode; 33097e3043aSDavid Howells call->reply[1] = volsync; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds /* marshall the parameters */ 33308e0e7c8SDavid Howells bp = call->request; 3341da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 3351da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 3361da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 3371da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 3381da177e4SLinus Torvalds 339d2ddc776SDavid Howells call->cb_break = fc->cb_break; 340d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 341025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 342d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 343ec26815aSDavid Howells } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* 34608e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 3471da177e4SLinus Torvalds */ 348d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call) 3491da177e4SLinus Torvalds { 35097e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 35197e3043aSDavid Howells struct afs_read *req = call->reply[2]; 35208e0e7c8SDavid Howells const __be32 *bp; 353196ee9cdSDavid Howells unsigned int size; 35408e0e7c8SDavid Howells void *buffer; 3551da177e4SLinus Torvalds int ret; 3561da177e4SLinus Torvalds 3576a0e3999SDavid Howells _enter("{%u,%zu/%u;%llu/%llu}", 358196ee9cdSDavid Howells call->unmarshall, call->offset, call->count, 359196ee9cdSDavid Howells req->remain, req->actual_len); 3601da177e4SLinus Torvalds 36108e0e7c8SDavid Howells switch (call->unmarshall) { 36208e0e7c8SDavid Howells case 0: 363196ee9cdSDavid Howells req->actual_len = 0; 36408e0e7c8SDavid Howells call->offset = 0; 36508e0e7c8SDavid Howells call->unmarshall++; 366b9b1f8d5SDavid Howells if (call->operation_ID != FSFETCHDATA64) { 367b9b1f8d5SDavid Howells call->unmarshall++; 368b9b1f8d5SDavid Howells goto no_msw; 369b9b1f8d5SDavid Howells } 3701da177e4SLinus Torvalds 371b9b1f8d5SDavid Howells /* extract the upper part of the returned data length of an 372b9b1f8d5SDavid Howells * FSFETCHDATA64 op (which should always be 0 using this 373b9b1f8d5SDavid Howells * client) */ 37408e0e7c8SDavid Howells case 1: 375b9b1f8d5SDavid Howells _debug("extract data length (MSW)"); 376d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 377372ee163SDavid Howells if (ret < 0) 378372ee163SDavid Howells return ret; 379b9b1f8d5SDavid Howells 380196ee9cdSDavid Howells req->actual_len = ntohl(call->tmp); 381196ee9cdSDavid Howells req->actual_len <<= 32; 382b9b1f8d5SDavid Howells call->offset = 0; 383b9b1f8d5SDavid Howells call->unmarshall++; 384b9b1f8d5SDavid Howells 385b9b1f8d5SDavid Howells no_msw: 386b9b1f8d5SDavid Howells /* extract the returned data length */ 387b9b1f8d5SDavid Howells case 2: 38808e0e7c8SDavid Howells _debug("extract data length"); 389d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 390372ee163SDavid Howells if (ret < 0) 391372ee163SDavid Howells return ret; 3921da177e4SLinus Torvalds 393196ee9cdSDavid Howells req->actual_len |= ntohl(call->tmp); 394196ee9cdSDavid Howells _debug("DATA length: %llu", req->actual_len); 395196ee9cdSDavid Howells 396196ee9cdSDavid Howells req->remain = req->actual_len; 397196ee9cdSDavid Howells call->offset = req->pos & (PAGE_SIZE - 1); 398196ee9cdSDavid Howells req->index = 0; 399196ee9cdSDavid Howells if (req->actual_len == 0) 400196ee9cdSDavid Howells goto no_more_data; 40108e0e7c8SDavid Howells call->unmarshall++; 4021da177e4SLinus Torvalds 403196ee9cdSDavid Howells begin_page: 4046db3ac3cSDavid Howells ASSERTCMP(req->index, <, req->nr_pages); 405196ee9cdSDavid Howells if (req->remain > PAGE_SIZE - call->offset) 406196ee9cdSDavid Howells size = PAGE_SIZE - call->offset; 407196ee9cdSDavid Howells else 408196ee9cdSDavid Howells size = req->remain; 409196ee9cdSDavid Howells call->count = call->offset + size; 410196ee9cdSDavid Howells ASSERTCMP(call->count, <=, PAGE_SIZE); 411196ee9cdSDavid Howells req->remain -= size; 412196ee9cdSDavid Howells 41308e0e7c8SDavid Howells /* extract the returned data */ 414b9b1f8d5SDavid Howells case 3: 4156a0e3999SDavid Howells _debug("extract data %llu/%llu %zu/%u", 416196ee9cdSDavid Howells req->remain, req->actual_len, call->offset, call->count); 417196ee9cdSDavid Howells 418196ee9cdSDavid Howells buffer = kmap(req->pages[req->index]); 419196ee9cdSDavid Howells ret = afs_extract_data(call, buffer, call->count, true); 420196ee9cdSDavid Howells kunmap(req->pages[req->index]); 421372ee163SDavid Howells if (ret < 0) 422372ee163SDavid Howells return ret; 423196ee9cdSDavid Howells if (call->offset == PAGE_SIZE) { 424196ee9cdSDavid Howells if (req->page_done) 425196ee9cdSDavid Howells req->page_done(call, req); 42629f06985SDavid Howells req->index++; 427196ee9cdSDavid Howells if (req->remain > 0) { 428196ee9cdSDavid Howells call->offset = 0; 429e8e581a8SDavid Howells if (req->index >= req->nr_pages) { 430e8e581a8SDavid Howells call->unmarshall = 4; 4316db3ac3cSDavid Howells goto begin_discard; 432e8e581a8SDavid Howells } 433196ee9cdSDavid Howells goto begin_page; 434196ee9cdSDavid Howells } 435416351f2SDavid Howells } 4366db3ac3cSDavid Howells goto no_more_data; 4376db3ac3cSDavid Howells 4386db3ac3cSDavid Howells /* Discard any excess data the server gave us */ 4396db3ac3cSDavid Howells begin_discard: 4406db3ac3cSDavid Howells case 4: 4416a0e3999SDavid Howells size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain); 4426db3ac3cSDavid Howells call->count = size; 4436a0e3999SDavid Howells _debug("extract discard %llu/%llu %zu/%u", 4446db3ac3cSDavid Howells req->remain, req->actual_len, call->offset, call->count); 4456db3ac3cSDavid Howells 4466db3ac3cSDavid Howells call->offset = 0; 4476db3ac3cSDavid Howells ret = afs_extract_data(call, afs_discard_buffer, call->count, true); 4486db3ac3cSDavid Howells req->remain -= call->offset; 4496db3ac3cSDavid Howells if (ret < 0) 4506db3ac3cSDavid Howells return ret; 4516db3ac3cSDavid Howells if (req->remain > 0) 4526db3ac3cSDavid Howells goto begin_discard; 4531da177e4SLinus Torvalds 454196ee9cdSDavid Howells no_more_data: 45508e0e7c8SDavid Howells call->offset = 0; 4566db3ac3cSDavid Howells call->unmarshall = 5; 45708e0e7c8SDavid Howells 45808e0e7c8SDavid Howells /* extract the metadata */ 4596db3ac3cSDavid Howells case 5: 460d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 461d001648eSDavid Howells (21 + 3 + 6) * 4, false); 462372ee163SDavid Howells if (ret < 0) 463372ee163SDavid Howells return ret; 4641da177e4SLinus Torvalds 46508e0e7c8SDavid Howells bp = call->buffer; 46631143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 467c435ee34SDavid Howells xdr_decode_AFSCallBack(call, vnode, &bp); 46897e3043aSDavid Howells if (call->reply[1]) 46997e3043aSDavid Howells xdr_decode_AFSVolSync(&bp, call->reply[1]); 4701da177e4SLinus Torvalds 47108e0e7c8SDavid Howells call->offset = 0; 47208e0e7c8SDavid Howells call->unmarshall++; 4731da177e4SLinus Torvalds 4746db3ac3cSDavid Howells case 6: 4751da177e4SLinus Torvalds break; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4786db3ac3cSDavid Howells for (; req->index < req->nr_pages; req->index++) { 4796db3ac3cSDavid Howells if (call->count < PAGE_SIZE) 4806db3ac3cSDavid Howells zero_user_segment(req->pages[req->index], 4816db3ac3cSDavid Howells call->count, PAGE_SIZE); 482196ee9cdSDavid Howells if (req->page_done) 483196ee9cdSDavid Howells req->page_done(call, req); 4846db3ac3cSDavid Howells call->count = 0; 485416351f2SDavid Howells } 486416351f2SDavid Howells 48708e0e7c8SDavid Howells _leave(" = 0 [done]"); 48808e0e7c8SDavid Howells return 0; 489ec26815aSDavid Howells } 4901da177e4SLinus Torvalds 491196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call) 492196ee9cdSDavid Howells { 49397e3043aSDavid Howells struct afs_read *req = call->reply[2]; 494196ee9cdSDavid Howells 495196ee9cdSDavid Howells afs_put_read(req); 496196ee9cdSDavid Howells afs_flat_call_destructor(call); 497196ee9cdSDavid Howells } 498196ee9cdSDavid Howells 4991da177e4SLinus Torvalds /* 50008e0e7c8SDavid Howells * FS.FetchData operation type 5011da177e4SLinus Torvalds */ 50208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 50300d3b7a4SDavid Howells .name = "FS.FetchData", 504025db80cSDavid Howells .op = afs_FS_FetchData, 50508e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 506196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 50708e0e7c8SDavid Howells }; 50808e0e7c8SDavid Howells 509b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 510b9b1f8d5SDavid Howells .name = "FS.FetchData64", 511025db80cSDavid Howells .op = afs_FS_FetchData64, 512b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 513196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 514b9b1f8d5SDavid Howells }; 515b9b1f8d5SDavid Howells 516b9b1f8d5SDavid Howells /* 517b9b1f8d5SDavid Howells * fetch data from a very large file 518b9b1f8d5SDavid Howells */ 519d2ddc776SDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req) 520b9b1f8d5SDavid Howells { 521d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 522b9b1f8d5SDavid Howells struct afs_call *call; 523f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 524b9b1f8d5SDavid Howells __be32 *bp; 525b9b1f8d5SDavid Howells 526b9b1f8d5SDavid Howells _enter(""); 527b9b1f8d5SDavid Howells 528f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 529b9b1f8d5SDavid Howells if (!call) 530b9b1f8d5SDavid Howells return -ENOMEM; 531b9b1f8d5SDavid Howells 532d2ddc776SDavid Howells call->key = fc->key; 53397e3043aSDavid Howells call->reply[0] = vnode; 53497e3043aSDavid Howells call->reply[1] = NULL; /* volsync */ 53597e3043aSDavid Howells call->reply[2] = req; 536b9b1f8d5SDavid Howells 537b9b1f8d5SDavid Howells /* marshall the parameters */ 538b9b1f8d5SDavid Howells bp = call->request; 539b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 540b9b1f8d5SDavid Howells bp[1] = htonl(vnode->fid.vid); 541b9b1f8d5SDavid Howells bp[2] = htonl(vnode->fid.vnode); 542b9b1f8d5SDavid Howells bp[3] = htonl(vnode->fid.unique); 543196ee9cdSDavid Howells bp[4] = htonl(upper_32_bits(req->pos)); 544196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->pos)); 545b9b1f8d5SDavid Howells bp[6] = 0; 546196ee9cdSDavid Howells bp[7] = htonl(lower_32_bits(req->len)); 547b9b1f8d5SDavid Howells 548196ee9cdSDavid Howells atomic_inc(&req->usage); 549d2ddc776SDavid Howells call->cb_break = fc->cb_break; 550d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 551025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 552d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 553b9b1f8d5SDavid Howells } 554b9b1f8d5SDavid Howells 55508e0e7c8SDavid Howells /* 55608e0e7c8SDavid Howells * fetch data from a file 55708e0e7c8SDavid Howells */ 558d2ddc776SDavid Howells int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req) 5591da177e4SLinus Torvalds { 560d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 56108e0e7c8SDavid Howells struct afs_call *call; 562f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 56308e0e7c8SDavid Howells __be32 *bp; 5641da177e4SLinus Torvalds 565196ee9cdSDavid Howells if (upper_32_bits(req->pos) || 566196ee9cdSDavid Howells upper_32_bits(req->len) || 567196ee9cdSDavid Howells upper_32_bits(req->pos + req->len)) 568d2ddc776SDavid Howells return afs_fs_fetch_data64(fc, req); 569b9b1f8d5SDavid Howells 57008e0e7c8SDavid Howells _enter(""); 5711da177e4SLinus Torvalds 572f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 57308e0e7c8SDavid Howells if (!call) 57408e0e7c8SDavid Howells return -ENOMEM; 5751da177e4SLinus Torvalds 576d2ddc776SDavid Howells call->key = fc->key; 57797e3043aSDavid Howells call->reply[0] = vnode; 57897e3043aSDavid Howells call->reply[1] = NULL; /* volsync */ 57997e3043aSDavid Howells call->reply[2] = req; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds /* marshall the parameters */ 58208e0e7c8SDavid Howells bp = call->request; 58308e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 58408e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 58508e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 58608e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 587196ee9cdSDavid Howells bp[4] = htonl(lower_32_bits(req->pos)); 588196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->len)); 5891da177e4SLinus Torvalds 590196ee9cdSDavid Howells atomic_inc(&req->usage); 591d2ddc776SDavid Howells call->cb_break = fc->cb_break; 592d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 593025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 594d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 59508e0e7c8SDavid Howells } 596260a9803SDavid Howells 597260a9803SDavid Howells /* 598260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 599260a9803SDavid Howells */ 600d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call) 601260a9803SDavid Howells { 60297e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 603260a9803SDavid Howells const __be32 *bp; 604372ee163SDavid Howells int ret; 605260a9803SDavid Howells 606d001648eSDavid Howells _enter("{%u}", call->unmarshall); 607260a9803SDavid Howells 608d001648eSDavid Howells ret = afs_transfer_reply(call); 609372ee163SDavid Howells if (ret < 0) 610372ee163SDavid Howells return ret; 611260a9803SDavid Howells 612260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 613260a9803SDavid Howells bp = call->buffer; 61497e3043aSDavid Howells xdr_decode_AFSFid(&bp, call->reply[1]); 61597e3043aSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL); 61631143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 61797e3043aSDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply[3]); 61897e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 619260a9803SDavid Howells 620260a9803SDavid Howells _leave(" = 0 [done]"); 621260a9803SDavid Howells return 0; 622260a9803SDavid Howells } 623260a9803SDavid Howells 624260a9803SDavid Howells /* 625260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 626260a9803SDavid Howells */ 627025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = { 628025db80cSDavid Howells .name = "FS.CreateFile", 629025db80cSDavid Howells .op = afs_FS_CreateFile, 630025db80cSDavid Howells .deliver = afs_deliver_fs_create_vnode, 631025db80cSDavid Howells .destructor = afs_flat_call_destructor, 632025db80cSDavid Howells }; 633025db80cSDavid Howells 634025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = { 635025db80cSDavid Howells .name = "FS.MakeDir", 636025db80cSDavid Howells .op = afs_FS_MakeDir, 637260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 638260a9803SDavid Howells .destructor = afs_flat_call_destructor, 639260a9803SDavid Howells }; 640260a9803SDavid Howells 641260a9803SDavid Howells /* 642260a9803SDavid Howells * create a file or make a directory 643260a9803SDavid Howells */ 6448b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc, 645260a9803SDavid Howells const char *name, 646260a9803SDavid Howells umode_t mode, 647260a9803SDavid Howells struct afs_fid *newfid, 648260a9803SDavid Howells struct afs_file_status *newstatus, 649d2ddc776SDavid Howells struct afs_callback *newcb) 650260a9803SDavid Howells { 651d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 652260a9803SDavid Howells struct afs_call *call; 653f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 654260a9803SDavid Howells size_t namesz, reqsz, padsz; 655260a9803SDavid Howells __be32 *bp; 656260a9803SDavid Howells 657260a9803SDavid Howells _enter(""); 658260a9803SDavid Howells 659260a9803SDavid Howells namesz = strlen(name); 660260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 661260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 662260a9803SDavid Howells 663025db80cSDavid Howells call = afs_alloc_flat_call( 664025db80cSDavid Howells net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile, 665025db80cSDavid Howells reqsz, (3 + 21 + 21 + 3 + 6) * 4); 666260a9803SDavid Howells if (!call) 667260a9803SDavid Howells return -ENOMEM; 668260a9803SDavid Howells 669d2ddc776SDavid Howells call->key = fc->key; 67097e3043aSDavid Howells call->reply[0] = vnode; 67197e3043aSDavid Howells call->reply[1] = newfid; 67297e3043aSDavid Howells call->reply[2] = newstatus; 67397e3043aSDavid Howells call->reply[3] = newcb; 674260a9803SDavid Howells 675260a9803SDavid Howells /* marshall the parameters */ 676260a9803SDavid Howells bp = call->request; 677260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 678260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 679260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 680260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 681260a9803SDavid Howells *bp++ = htonl(namesz); 682260a9803SDavid Howells memcpy(bp, name, namesz); 683260a9803SDavid Howells bp = (void *) bp + namesz; 684260a9803SDavid Howells if (padsz > 0) { 685260a9803SDavid Howells memset(bp, 0, padsz); 686260a9803SDavid Howells bp = (void *) bp + padsz; 687260a9803SDavid Howells } 688ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 689ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 690260a9803SDavid Howells *bp++ = 0; /* owner */ 691260a9803SDavid Howells *bp++ = 0; /* group */ 692260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 693260a9803SDavid Howells *bp++ = 0; /* segment size */ 694260a9803SDavid Howells 695d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 696025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 697d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 698260a9803SDavid Howells } 699260a9803SDavid Howells 700260a9803SDavid Howells /* 701260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 702260a9803SDavid Howells */ 703d001648eSDavid Howells static int afs_deliver_fs_remove(struct afs_call *call) 704260a9803SDavid Howells { 70597e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 706260a9803SDavid Howells const __be32 *bp; 707372ee163SDavid Howells int ret; 708260a9803SDavid Howells 709d001648eSDavid Howells _enter("{%u}", call->unmarshall); 710260a9803SDavid Howells 711d001648eSDavid Howells ret = afs_transfer_reply(call); 712372ee163SDavid Howells if (ret < 0) 713372ee163SDavid Howells return ret; 714260a9803SDavid Howells 715260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 716260a9803SDavid Howells bp = call->buffer; 71731143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 71897e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 719260a9803SDavid Howells 720260a9803SDavid Howells _leave(" = 0 [done]"); 721260a9803SDavid Howells return 0; 722260a9803SDavid Howells } 723260a9803SDavid Howells 724260a9803SDavid Howells /* 725260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 726260a9803SDavid Howells */ 727025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = { 728025db80cSDavid Howells .name = "FS.RemoveFile", 729025db80cSDavid Howells .op = afs_FS_RemoveFile, 730025db80cSDavid Howells .deliver = afs_deliver_fs_remove, 731025db80cSDavid Howells .destructor = afs_flat_call_destructor, 732025db80cSDavid Howells }; 733025db80cSDavid Howells 734025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = { 735025db80cSDavid Howells .name = "FS.RemoveDir", 736025db80cSDavid Howells .op = afs_FS_RemoveDir, 737260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 738260a9803SDavid Howells .destructor = afs_flat_call_destructor, 739260a9803SDavid Howells }; 740260a9803SDavid Howells 741260a9803SDavid Howells /* 742260a9803SDavid Howells * remove a file or directory 743260a9803SDavid Howells */ 744d2ddc776SDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir) 745260a9803SDavid Howells { 746d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 747260a9803SDavid Howells struct afs_call *call; 748f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 749260a9803SDavid Howells size_t namesz, reqsz, padsz; 750260a9803SDavid Howells __be32 *bp; 751260a9803SDavid Howells 752260a9803SDavid Howells _enter(""); 753260a9803SDavid Howells 754260a9803SDavid Howells namesz = strlen(name); 755260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 756260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 757260a9803SDavid Howells 758025db80cSDavid Howells call = afs_alloc_flat_call( 759025db80cSDavid Howells net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile, 760025db80cSDavid Howells reqsz, (21 + 6) * 4); 761260a9803SDavid Howells if (!call) 762260a9803SDavid Howells return -ENOMEM; 763260a9803SDavid Howells 764d2ddc776SDavid Howells call->key = fc->key; 76597e3043aSDavid Howells call->reply[0] = vnode; 766260a9803SDavid Howells 767260a9803SDavid Howells /* marshall the parameters */ 768260a9803SDavid Howells bp = call->request; 769260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 770260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 771260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 772260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 773260a9803SDavid Howells *bp++ = htonl(namesz); 774260a9803SDavid Howells memcpy(bp, name, namesz); 775260a9803SDavid Howells bp = (void *) bp + namesz; 776260a9803SDavid Howells if (padsz > 0) { 777260a9803SDavid Howells memset(bp, 0, padsz); 778260a9803SDavid Howells bp = (void *) bp + padsz; 779260a9803SDavid Howells } 780260a9803SDavid Howells 781d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 782025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 783d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 784260a9803SDavid Howells } 785260a9803SDavid Howells 786260a9803SDavid Howells /* 787260a9803SDavid Howells * deliver reply data to an FS.Link 788260a9803SDavid Howells */ 789d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call) 790260a9803SDavid Howells { 79197e3043aSDavid Howells struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1]; 792260a9803SDavid Howells const __be32 *bp; 793372ee163SDavid Howells int ret; 794260a9803SDavid Howells 795d001648eSDavid Howells _enter("{%u}", call->unmarshall); 796260a9803SDavid Howells 797d001648eSDavid Howells ret = afs_transfer_reply(call); 798372ee163SDavid Howells if (ret < 0) 799372ee163SDavid Howells return ret; 800260a9803SDavid Howells 801260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 802260a9803SDavid Howells bp = call->buffer; 80331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 80431143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); 80597e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 806260a9803SDavid Howells 807260a9803SDavid Howells _leave(" = 0 [done]"); 808260a9803SDavid Howells return 0; 809260a9803SDavid Howells } 810260a9803SDavid Howells 811260a9803SDavid Howells /* 812260a9803SDavid Howells * FS.Link operation type 813260a9803SDavid Howells */ 814260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 815260a9803SDavid Howells .name = "FS.Link", 816025db80cSDavid Howells .op = afs_FS_Link, 817260a9803SDavid Howells .deliver = afs_deliver_fs_link, 818260a9803SDavid Howells .destructor = afs_flat_call_destructor, 819260a9803SDavid Howells }; 820260a9803SDavid Howells 821260a9803SDavid Howells /* 822260a9803SDavid Howells * make a hard link 823260a9803SDavid Howells */ 824d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode, 825d2ddc776SDavid Howells const char *name) 826260a9803SDavid Howells { 827d2ddc776SDavid Howells struct afs_vnode *dvnode = fc->vnode; 828260a9803SDavid Howells struct afs_call *call; 829f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 830260a9803SDavid Howells size_t namesz, reqsz, padsz; 831260a9803SDavid Howells __be32 *bp; 832260a9803SDavid Howells 833260a9803SDavid Howells _enter(""); 834260a9803SDavid Howells 835260a9803SDavid Howells namesz = strlen(name); 836260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 837260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 838260a9803SDavid Howells 839f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 840260a9803SDavid Howells if (!call) 841260a9803SDavid Howells return -ENOMEM; 842260a9803SDavid Howells 843d2ddc776SDavid Howells call->key = fc->key; 84497e3043aSDavid Howells call->reply[0] = dvnode; 84597e3043aSDavid Howells call->reply[1] = vnode; 846260a9803SDavid Howells 847260a9803SDavid Howells /* marshall the parameters */ 848260a9803SDavid Howells bp = call->request; 849260a9803SDavid Howells *bp++ = htonl(FSLINK); 850260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 851260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 852260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 853260a9803SDavid Howells *bp++ = htonl(namesz); 854260a9803SDavid Howells memcpy(bp, name, namesz); 855260a9803SDavid Howells bp = (void *) bp + namesz; 856260a9803SDavid Howells if (padsz > 0) { 857260a9803SDavid Howells memset(bp, 0, padsz); 858260a9803SDavid Howells bp = (void *) bp + padsz; 859260a9803SDavid Howells } 860260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 861260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 862260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 863260a9803SDavid Howells 864d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 865025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 866d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 867260a9803SDavid Howells } 868260a9803SDavid Howells 869260a9803SDavid Howells /* 870260a9803SDavid Howells * deliver reply data to an FS.Symlink 871260a9803SDavid Howells */ 872d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call) 873260a9803SDavid Howells { 87497e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 875260a9803SDavid Howells const __be32 *bp; 876372ee163SDavid Howells int ret; 877260a9803SDavid Howells 878d001648eSDavid Howells _enter("{%u}", call->unmarshall); 879260a9803SDavid Howells 880d001648eSDavid Howells ret = afs_transfer_reply(call); 881372ee163SDavid Howells if (ret < 0) 882372ee163SDavid Howells return ret; 883260a9803SDavid Howells 884260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 885260a9803SDavid Howells bp = call->buffer; 88697e3043aSDavid Howells xdr_decode_AFSFid(&bp, call->reply[1]); 88797e3043aSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL); 88831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 88997e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 890260a9803SDavid Howells 891260a9803SDavid Howells _leave(" = 0 [done]"); 892260a9803SDavid Howells return 0; 893260a9803SDavid Howells } 894260a9803SDavid Howells 895260a9803SDavid Howells /* 896260a9803SDavid Howells * FS.Symlink operation type 897260a9803SDavid Howells */ 898260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 899260a9803SDavid Howells .name = "FS.Symlink", 900025db80cSDavid Howells .op = afs_FS_Symlink, 901260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 902260a9803SDavid Howells .destructor = afs_flat_call_destructor, 903260a9803SDavid Howells }; 904260a9803SDavid Howells 905260a9803SDavid Howells /* 906260a9803SDavid Howells * create a symbolic link 907260a9803SDavid Howells */ 9088b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc, 909260a9803SDavid Howells const char *name, 910260a9803SDavid Howells const char *contents, 911260a9803SDavid Howells struct afs_fid *newfid, 912d2ddc776SDavid Howells struct afs_file_status *newstatus) 913260a9803SDavid Howells { 914d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 915260a9803SDavid Howells struct afs_call *call; 916f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 917260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 918260a9803SDavid Howells __be32 *bp; 919260a9803SDavid Howells 920260a9803SDavid Howells _enter(""); 921260a9803SDavid Howells 922260a9803SDavid Howells namesz = strlen(name); 923260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 924260a9803SDavid Howells 925260a9803SDavid Howells c_namesz = strlen(contents); 926260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 927260a9803SDavid Howells 928260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 929260a9803SDavid Howells 930f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz, 931260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 932260a9803SDavid Howells if (!call) 933260a9803SDavid Howells return -ENOMEM; 934260a9803SDavid Howells 935d2ddc776SDavid Howells call->key = fc->key; 93697e3043aSDavid Howells call->reply[0] = vnode; 93797e3043aSDavid Howells call->reply[1] = newfid; 93897e3043aSDavid Howells call->reply[2] = newstatus; 939260a9803SDavid Howells 940260a9803SDavid Howells /* marshall the parameters */ 941260a9803SDavid Howells bp = call->request; 942260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 943260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 944260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 945260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 946260a9803SDavid Howells *bp++ = htonl(namesz); 947260a9803SDavid Howells memcpy(bp, name, namesz); 948260a9803SDavid Howells bp = (void *) bp + namesz; 949260a9803SDavid Howells if (padsz > 0) { 950260a9803SDavid Howells memset(bp, 0, padsz); 951260a9803SDavid Howells bp = (void *) bp + padsz; 952260a9803SDavid Howells } 953260a9803SDavid Howells *bp++ = htonl(c_namesz); 954260a9803SDavid Howells memcpy(bp, contents, c_namesz); 955260a9803SDavid Howells bp = (void *) bp + c_namesz; 956260a9803SDavid Howells if (c_padsz > 0) { 957260a9803SDavid Howells memset(bp, 0, c_padsz); 958260a9803SDavid Howells bp = (void *) bp + c_padsz; 959260a9803SDavid Howells } 960ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 961ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 962260a9803SDavid Howells *bp++ = 0; /* owner */ 963260a9803SDavid Howells *bp++ = 0; /* group */ 964260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 965260a9803SDavid Howells *bp++ = 0; /* segment size */ 966260a9803SDavid Howells 967d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 968025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 969d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 970260a9803SDavid Howells } 971260a9803SDavid Howells 972260a9803SDavid Howells /* 973260a9803SDavid Howells * deliver reply data to an FS.Rename 974260a9803SDavid Howells */ 975d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call) 976260a9803SDavid Howells { 97797e3043aSDavid Howells struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1]; 978260a9803SDavid Howells const __be32 *bp; 979372ee163SDavid Howells int ret; 980260a9803SDavid Howells 981d001648eSDavid Howells _enter("{%u}", call->unmarshall); 982260a9803SDavid Howells 983d001648eSDavid Howells ret = afs_transfer_reply(call); 984372ee163SDavid Howells if (ret < 0) 985372ee163SDavid Howells return ret; 986260a9803SDavid Howells 987260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 988260a9803SDavid Howells bp = call->buffer; 98931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); 990260a9803SDavid Howells if (new_dvnode != orig_dvnode) 99131143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, 99231143d5dSDavid Howells NULL); 99397e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 994260a9803SDavid Howells 995260a9803SDavid Howells _leave(" = 0 [done]"); 996260a9803SDavid Howells return 0; 997260a9803SDavid Howells } 998260a9803SDavid Howells 999260a9803SDavid Howells /* 1000260a9803SDavid Howells * FS.Rename operation type 1001260a9803SDavid Howells */ 1002260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 1003260a9803SDavid Howells .name = "FS.Rename", 1004025db80cSDavid Howells .op = afs_FS_Rename, 1005260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 1006260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1007260a9803SDavid Howells }; 1008260a9803SDavid Howells 1009260a9803SDavid Howells /* 1010260a9803SDavid Howells * create a symbolic link 1011260a9803SDavid Howells */ 10128b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc, 1013260a9803SDavid Howells const char *orig_name, 1014260a9803SDavid Howells struct afs_vnode *new_dvnode, 1015d2ddc776SDavid Howells const char *new_name) 1016260a9803SDavid Howells { 1017d2ddc776SDavid Howells struct afs_vnode *orig_dvnode = fc->vnode; 1018260a9803SDavid Howells struct afs_call *call; 1019f044c884SDavid Howells struct afs_net *net = afs_v2net(orig_dvnode); 1020260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 1021260a9803SDavid Howells __be32 *bp; 1022260a9803SDavid Howells 1023260a9803SDavid Howells _enter(""); 1024260a9803SDavid Howells 1025260a9803SDavid Howells o_namesz = strlen(orig_name); 1026260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 1027260a9803SDavid Howells 1028260a9803SDavid Howells n_namesz = strlen(new_name); 1029260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 1030260a9803SDavid Howells 1031260a9803SDavid Howells reqsz = (4 * 4) + 1032260a9803SDavid Howells 4 + o_namesz + o_padsz + 1033260a9803SDavid Howells (3 * 4) + 1034260a9803SDavid Howells 4 + n_namesz + n_padsz; 1035260a9803SDavid Howells 1036f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1037260a9803SDavid Howells if (!call) 1038260a9803SDavid Howells return -ENOMEM; 1039260a9803SDavid Howells 1040d2ddc776SDavid Howells call->key = fc->key; 104197e3043aSDavid Howells call->reply[0] = orig_dvnode; 104297e3043aSDavid Howells call->reply[1] = new_dvnode; 1043260a9803SDavid Howells 1044260a9803SDavid Howells /* marshall the parameters */ 1045260a9803SDavid Howells bp = call->request; 1046260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1047260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 1048260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 1049260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 1050260a9803SDavid Howells *bp++ = htonl(o_namesz); 1051260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 1052260a9803SDavid Howells bp = (void *) bp + o_namesz; 1053260a9803SDavid Howells if (o_padsz > 0) { 1054260a9803SDavid Howells memset(bp, 0, o_padsz); 1055260a9803SDavid Howells bp = (void *) bp + o_padsz; 1056260a9803SDavid Howells } 1057260a9803SDavid Howells 1058260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 1059260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 1060260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 1061260a9803SDavid Howells *bp++ = htonl(n_namesz); 1062260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 1063260a9803SDavid Howells bp = (void *) bp + n_namesz; 1064260a9803SDavid Howells if (n_padsz > 0) { 1065260a9803SDavid Howells memset(bp, 0, n_padsz); 1066260a9803SDavid Howells bp = (void *) bp + n_padsz; 1067260a9803SDavid Howells } 1068260a9803SDavid Howells 1069d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1070025db80cSDavid Howells trace_afs_make_fs_call(call, &orig_dvnode->fid); 1071d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1072260a9803SDavid Howells } 107331143d5dSDavid Howells 107431143d5dSDavid Howells /* 107531143d5dSDavid Howells * deliver reply data to an FS.StoreData 107631143d5dSDavid Howells */ 1077d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call) 107831143d5dSDavid Howells { 107997e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 108031143d5dSDavid Howells const __be32 *bp; 1081372ee163SDavid Howells int ret; 108231143d5dSDavid Howells 1083d001648eSDavid Howells _enter(""); 108431143d5dSDavid Howells 1085d001648eSDavid Howells ret = afs_transfer_reply(call); 1086372ee163SDavid Howells if (ret < 0) 1087372ee163SDavid Howells return ret; 108831143d5dSDavid Howells 108931143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 109031143d5dSDavid Howells bp = call->buffer; 109131143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, 109231143d5dSDavid Howells &call->store_version); 109397e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 109431143d5dSDavid Howells 109531143d5dSDavid Howells afs_pages_written_back(vnode, call); 109631143d5dSDavid Howells 109731143d5dSDavid Howells _leave(" = 0 [done]"); 109831143d5dSDavid Howells return 0; 109931143d5dSDavid Howells } 110031143d5dSDavid Howells 110131143d5dSDavid Howells /* 110231143d5dSDavid Howells * FS.StoreData operation type 110331143d5dSDavid Howells */ 110431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 110531143d5dSDavid Howells .name = "FS.StoreData", 1106025db80cSDavid Howells .op = afs_FS_StoreData, 110731143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 110831143d5dSDavid Howells .destructor = afs_flat_call_destructor, 110931143d5dSDavid Howells }; 111031143d5dSDavid Howells 1111b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1112b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1113025db80cSDavid Howells .op = afs_FS_StoreData64, 1114b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1115b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1116b9b1f8d5SDavid Howells }; 1117b9b1f8d5SDavid Howells 1118b9b1f8d5SDavid Howells /* 1119b9b1f8d5SDavid Howells * store a set of pages to a very large file 1120b9b1f8d5SDavid Howells */ 11218b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc, 1122b9b1f8d5SDavid Howells struct afs_writeback *wb, 1123b9b1f8d5SDavid Howells pgoff_t first, pgoff_t last, 1124b9b1f8d5SDavid Howells unsigned offset, unsigned to, 1125d2ddc776SDavid Howells loff_t size, loff_t pos, loff_t i_size) 1126b9b1f8d5SDavid Howells { 1127b9b1f8d5SDavid Howells struct afs_vnode *vnode = wb->vnode; 1128b9b1f8d5SDavid Howells struct afs_call *call; 1129f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1130b9b1f8d5SDavid Howells __be32 *bp; 1131b9b1f8d5SDavid Howells 1132b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1133b9b1f8d5SDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 1134b9b1f8d5SDavid Howells 1135f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64, 1136b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1137b9b1f8d5SDavid Howells (21 + 6) * 4); 1138b9b1f8d5SDavid Howells if (!call) 1139b9b1f8d5SDavid Howells return -ENOMEM; 1140b9b1f8d5SDavid Howells 1141b9b1f8d5SDavid Howells call->wb = wb; 1142b9b1f8d5SDavid Howells call->key = wb->key; 114397e3043aSDavid Howells call->reply[0] = vnode; 1144b9b1f8d5SDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 1145b9b1f8d5SDavid Howells call->first = first; 1146b9b1f8d5SDavid Howells call->last = last; 1147b9b1f8d5SDavid Howells call->first_offset = offset; 1148b9b1f8d5SDavid Howells call->last_to = to; 1149b9b1f8d5SDavid Howells call->send_pages = true; 1150b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1151b9b1f8d5SDavid Howells 1152b9b1f8d5SDavid Howells /* marshall the parameters */ 1153b9b1f8d5SDavid Howells bp = call->request; 1154b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1155b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1156b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1157b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1158b9b1f8d5SDavid Howells 1159ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1160ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 1161b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1162b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1163b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1164b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1165b9b1f8d5SDavid Howells 1166b9b1f8d5SDavid Howells *bp++ = htonl(pos >> 32); 1167b9b1f8d5SDavid Howells *bp++ = htonl((u32) pos); 1168b9b1f8d5SDavid Howells *bp++ = htonl(size >> 32); 1169b9b1f8d5SDavid Howells *bp++ = htonl((u32) size); 1170b9b1f8d5SDavid Howells *bp++ = htonl(i_size >> 32); 1171b9b1f8d5SDavid Howells *bp++ = htonl((u32) i_size); 1172b9b1f8d5SDavid Howells 1173025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1174d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1175b9b1f8d5SDavid Howells } 1176b9b1f8d5SDavid Howells 117731143d5dSDavid Howells /* 117831143d5dSDavid Howells * store a set of pages 117931143d5dSDavid Howells */ 11808b2a464cSDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb, 118131143d5dSDavid Howells pgoff_t first, pgoff_t last, 1182d2ddc776SDavid Howells unsigned offset, unsigned to) 118331143d5dSDavid Howells { 118431143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 118531143d5dSDavid Howells struct afs_call *call; 1186f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 118731143d5dSDavid Howells loff_t size, pos, i_size; 118831143d5dSDavid Howells __be32 *bp; 118931143d5dSDavid Howells 119031143d5dSDavid Howells _enter(",%x,{%x:%u},,", 119131143d5dSDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 119231143d5dSDavid Howells 1193146a1192SDavid Howells size = (loff_t)to - (loff_t)offset; 119431143d5dSDavid Howells if (first != last) 119531143d5dSDavid Howells size += (loff_t)(last - first) << PAGE_SHIFT; 119631143d5dSDavid Howells pos = (loff_t)first << PAGE_SHIFT; 119731143d5dSDavid Howells pos += offset; 119831143d5dSDavid Howells 119931143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 120031143d5dSDavid Howells if (pos + size > i_size) 120131143d5dSDavid Howells i_size = size + pos; 120231143d5dSDavid Howells 120331143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 120431143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 120531143d5dSDavid Howells (unsigned long long) i_size); 120631143d5dSDavid Howells 1207b9b1f8d5SDavid Howells if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) 12088b2a464cSDavid Howells return afs_fs_store_data64(fc, wb, first, last, offset, to, 1209d2ddc776SDavid Howells size, pos, i_size); 121031143d5dSDavid Howells 1211f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData, 121231143d5dSDavid Howells (4 + 6 + 3) * 4, 121331143d5dSDavid Howells (21 + 6) * 4); 121431143d5dSDavid Howells if (!call) 121531143d5dSDavid Howells return -ENOMEM; 121631143d5dSDavid Howells 121731143d5dSDavid Howells call->wb = wb; 121831143d5dSDavid Howells call->key = wb->key; 121997e3043aSDavid Howells call->reply[0] = vnode; 122031143d5dSDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 122131143d5dSDavid Howells call->first = first; 122231143d5dSDavid Howells call->last = last; 122331143d5dSDavid Howells call->first_offset = offset; 122431143d5dSDavid Howells call->last_to = to; 122531143d5dSDavid Howells call->send_pages = true; 122631143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 122731143d5dSDavid Howells 122831143d5dSDavid Howells /* marshall the parameters */ 122931143d5dSDavid Howells bp = call->request; 123031143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 123131143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 123231143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 123331143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 123431143d5dSDavid Howells 1235ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1236ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 123731143d5dSDavid Howells *bp++ = 0; /* owner */ 123831143d5dSDavid Howells *bp++ = 0; /* group */ 123931143d5dSDavid Howells *bp++ = 0; /* unix mode */ 124031143d5dSDavid Howells *bp++ = 0; /* segment size */ 124131143d5dSDavid Howells 124231143d5dSDavid Howells *bp++ = htonl(pos); 124331143d5dSDavid Howells *bp++ = htonl(size); 124431143d5dSDavid Howells *bp++ = htonl(i_size); 124531143d5dSDavid Howells 1246d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1247025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1248d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 124931143d5dSDavid Howells } 125031143d5dSDavid Howells 125131143d5dSDavid Howells /* 125231143d5dSDavid Howells * deliver reply data to an FS.StoreStatus 125331143d5dSDavid Howells */ 1254d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call) 125531143d5dSDavid Howells { 125631143d5dSDavid Howells afs_dataversion_t *store_version; 125797e3043aSDavid Howells struct afs_vnode *vnode = call->reply[0]; 125831143d5dSDavid Howells const __be32 *bp; 1259372ee163SDavid Howells int ret; 126031143d5dSDavid Howells 1261d001648eSDavid Howells _enter(""); 126231143d5dSDavid Howells 1263d001648eSDavid Howells ret = afs_transfer_reply(call); 1264372ee163SDavid Howells if (ret < 0) 1265372ee163SDavid Howells return ret; 126631143d5dSDavid Howells 126731143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 126831143d5dSDavid Howells store_version = NULL; 126931143d5dSDavid Howells if (call->operation_ID == FSSTOREDATA) 127031143d5dSDavid Howells store_version = &call->store_version; 127131143d5dSDavid Howells 127231143d5dSDavid Howells bp = call->buffer; 127331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); 127497e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 127531143d5dSDavid Howells 127631143d5dSDavid Howells _leave(" = 0 [done]"); 127731143d5dSDavid Howells return 0; 127831143d5dSDavid Howells } 127931143d5dSDavid Howells 128031143d5dSDavid Howells /* 128131143d5dSDavid Howells * FS.StoreStatus operation type 128231143d5dSDavid Howells */ 128331143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 128431143d5dSDavid Howells .name = "FS.StoreStatus", 1285025db80cSDavid Howells .op = afs_FS_StoreStatus, 128631143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 128731143d5dSDavid Howells .destructor = afs_flat_call_destructor, 128831143d5dSDavid Howells }; 128931143d5dSDavid Howells 129031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 129131143d5dSDavid Howells .name = "FS.StoreData", 1292025db80cSDavid Howells .op = afs_FS_StoreData, 129331143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 129431143d5dSDavid Howells .destructor = afs_flat_call_destructor, 129531143d5dSDavid Howells }; 129631143d5dSDavid Howells 1297b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1298b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1299025db80cSDavid Howells .op = afs_FS_StoreData64, 1300b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_status, 1301b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1302b9b1f8d5SDavid Howells }; 1303b9b1f8d5SDavid Howells 1304b9b1f8d5SDavid Howells /* 1305b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1306b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1307b9b1f8d5SDavid Howells */ 1308d2ddc776SDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr) 1309b9b1f8d5SDavid Howells { 1310d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1311b9b1f8d5SDavid Howells struct afs_call *call; 1312f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1313b9b1f8d5SDavid Howells __be32 *bp; 1314b9b1f8d5SDavid Howells 1315b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1316d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 1317b9b1f8d5SDavid Howells 1318b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1319b9b1f8d5SDavid Howells 1320f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status, 1321b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1322b9b1f8d5SDavid Howells (21 + 6) * 4); 1323b9b1f8d5SDavid Howells if (!call) 1324b9b1f8d5SDavid Howells return -ENOMEM; 1325b9b1f8d5SDavid Howells 1326d2ddc776SDavid Howells call->key = fc->key; 132797e3043aSDavid Howells call->reply[0] = vnode; 1328b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1329b9b1f8d5SDavid Howells 1330b9b1f8d5SDavid Howells /* marshall the parameters */ 1331b9b1f8d5SDavid Howells bp = call->request; 1332b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1333b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1334b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1335b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1336b9b1f8d5SDavid Howells 1337b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1338b9b1f8d5SDavid Howells 1339b9b1f8d5SDavid Howells *bp++ = 0; /* position of start of write */ 1340b9b1f8d5SDavid Howells *bp++ = 0; 1341b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1342b9b1f8d5SDavid Howells *bp++ = 0; 1343b9b1f8d5SDavid Howells *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1344b9b1f8d5SDavid Howells *bp++ = htonl((u32) attr->ia_size); 1345b9b1f8d5SDavid Howells 1346d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1347025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1348d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1349b9b1f8d5SDavid Howells } 1350b9b1f8d5SDavid Howells 135131143d5dSDavid Howells /* 135231143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 135331143d5dSDavid Howells * so as to alter the file size also 135431143d5dSDavid Howells */ 1355d2ddc776SDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr) 135631143d5dSDavid Howells { 1357d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 135831143d5dSDavid Howells struct afs_call *call; 1359f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 136031143d5dSDavid Howells __be32 *bp; 136131143d5dSDavid Howells 136231143d5dSDavid Howells _enter(",%x,{%x:%u},,", 1363d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 136431143d5dSDavid Howells 136531143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1366b9b1f8d5SDavid Howells if (attr->ia_size >> 32) 1367d2ddc776SDavid Howells return afs_fs_setattr_size64(fc, attr); 136831143d5dSDavid Howells 1369f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status, 137031143d5dSDavid Howells (4 + 6 + 3) * 4, 137131143d5dSDavid Howells (21 + 6) * 4); 137231143d5dSDavid Howells if (!call) 137331143d5dSDavid Howells return -ENOMEM; 137431143d5dSDavid Howells 1375d2ddc776SDavid Howells call->key = fc->key; 137697e3043aSDavid Howells call->reply[0] = vnode; 137731143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 137831143d5dSDavid Howells 137931143d5dSDavid Howells /* marshall the parameters */ 138031143d5dSDavid Howells bp = call->request; 138131143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 138231143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 138331143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 138431143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 138531143d5dSDavid Howells 138631143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 138731143d5dSDavid Howells 138831143d5dSDavid Howells *bp++ = 0; /* position of start of write */ 138931143d5dSDavid Howells *bp++ = 0; /* size of write */ 139031143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 139131143d5dSDavid Howells 1392d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1393025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1394d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 139531143d5dSDavid Howells } 139631143d5dSDavid Howells 139731143d5dSDavid Howells /* 139831143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 139931143d5dSDavid Howells * size, and FS.StoreStatus otherwise 140031143d5dSDavid Howells */ 1401d2ddc776SDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr) 140231143d5dSDavid Howells { 1403d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 140431143d5dSDavid Howells struct afs_call *call; 1405f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 140631143d5dSDavid Howells __be32 *bp; 140731143d5dSDavid Howells 140831143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 1409d2ddc776SDavid Howells return afs_fs_setattr_size(fc, attr); 141031143d5dSDavid Howells 141131143d5dSDavid Howells _enter(",%x,{%x:%u},,", 1412d2ddc776SDavid Howells key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); 141331143d5dSDavid Howells 1414f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus, 141531143d5dSDavid Howells (4 + 6) * 4, 141631143d5dSDavid Howells (21 + 6) * 4); 141731143d5dSDavid Howells if (!call) 141831143d5dSDavid Howells return -ENOMEM; 141931143d5dSDavid Howells 1420d2ddc776SDavid Howells call->key = fc->key; 142197e3043aSDavid Howells call->reply[0] = vnode; 142231143d5dSDavid Howells 142331143d5dSDavid Howells /* marshall the parameters */ 142431143d5dSDavid Howells bp = call->request; 142531143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 142631143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 142731143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 142831143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 142931143d5dSDavid Howells 143031143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 143131143d5dSDavid Howells 1432d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1433025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1434d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 143531143d5dSDavid Howells } 143645222b9eSDavid Howells 143745222b9eSDavid Howells /* 143845222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 143945222b9eSDavid Howells */ 1440d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call) 144145222b9eSDavid Howells { 144245222b9eSDavid Howells const __be32 *bp; 144345222b9eSDavid Howells char *p; 144445222b9eSDavid Howells int ret; 144545222b9eSDavid Howells 1446d001648eSDavid Howells _enter("{%u}", call->unmarshall); 144745222b9eSDavid Howells 144845222b9eSDavid Howells switch (call->unmarshall) { 144945222b9eSDavid Howells case 0: 145045222b9eSDavid Howells call->offset = 0; 145145222b9eSDavid Howells call->unmarshall++; 145245222b9eSDavid Howells 145345222b9eSDavid Howells /* extract the returned status record */ 145445222b9eSDavid Howells case 1: 145545222b9eSDavid Howells _debug("extract status"); 1456d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1457d001648eSDavid Howells 12 * 4, true); 1458372ee163SDavid Howells if (ret < 0) 1459372ee163SDavid Howells return ret; 146045222b9eSDavid Howells 146145222b9eSDavid Howells bp = call->buffer; 146297e3043aSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]); 146345222b9eSDavid Howells call->offset = 0; 146445222b9eSDavid Howells call->unmarshall++; 146545222b9eSDavid Howells 146645222b9eSDavid Howells /* extract the volume name length */ 146745222b9eSDavid Howells case 2: 1468d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1469372ee163SDavid Howells if (ret < 0) 1470372ee163SDavid Howells return ret; 147145222b9eSDavid Howells 147245222b9eSDavid Howells call->count = ntohl(call->tmp); 147345222b9eSDavid Howells _debug("volname length: %u", call->count); 147445222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 147545222b9eSDavid Howells return -EBADMSG; 147645222b9eSDavid Howells call->offset = 0; 147745222b9eSDavid Howells call->unmarshall++; 147845222b9eSDavid Howells 147945222b9eSDavid Howells /* extract the volume name */ 148045222b9eSDavid Howells case 3: 148145222b9eSDavid Howells _debug("extract volname"); 148245222b9eSDavid Howells if (call->count > 0) { 148397e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1484d001648eSDavid Howells call->count, true); 1485372ee163SDavid Howells if (ret < 0) 1486372ee163SDavid Howells return ret; 148745222b9eSDavid Howells } 148845222b9eSDavid Howells 148997e3043aSDavid Howells p = call->reply[2]; 149045222b9eSDavid Howells p[call->count] = 0; 149145222b9eSDavid Howells _debug("volname '%s'", p); 149245222b9eSDavid Howells 149345222b9eSDavid Howells call->offset = 0; 149445222b9eSDavid Howells call->unmarshall++; 149545222b9eSDavid Howells 149645222b9eSDavid Howells /* extract the volume name padding */ 149745222b9eSDavid Howells if ((call->count & 3) == 0) { 149845222b9eSDavid Howells call->unmarshall++; 149945222b9eSDavid Howells goto no_volname_padding; 150045222b9eSDavid Howells } 150145222b9eSDavid Howells call->count = 4 - (call->count & 3); 150245222b9eSDavid Howells 150345222b9eSDavid Howells case 4: 1504d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1505d001648eSDavid Howells call->count, true); 1506372ee163SDavid Howells if (ret < 0) 1507372ee163SDavid Howells return ret; 150845222b9eSDavid Howells 150945222b9eSDavid Howells call->offset = 0; 151045222b9eSDavid Howells call->unmarshall++; 151145222b9eSDavid Howells no_volname_padding: 151245222b9eSDavid Howells 151345222b9eSDavid Howells /* extract the offline message length */ 151445222b9eSDavid Howells case 5: 1515d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1516372ee163SDavid Howells if (ret < 0) 1517372ee163SDavid Howells return ret; 151845222b9eSDavid Howells 151945222b9eSDavid Howells call->count = ntohl(call->tmp); 152045222b9eSDavid Howells _debug("offline msg length: %u", call->count); 152145222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 152245222b9eSDavid Howells return -EBADMSG; 152345222b9eSDavid Howells call->offset = 0; 152445222b9eSDavid Howells call->unmarshall++; 152545222b9eSDavid Howells 152645222b9eSDavid Howells /* extract the offline message */ 152745222b9eSDavid Howells case 6: 152845222b9eSDavid Howells _debug("extract offline"); 152945222b9eSDavid Howells if (call->count > 0) { 153097e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1531d001648eSDavid Howells call->count, true); 1532372ee163SDavid Howells if (ret < 0) 1533372ee163SDavid Howells return ret; 153445222b9eSDavid Howells } 153545222b9eSDavid Howells 153697e3043aSDavid Howells p = call->reply[2]; 153745222b9eSDavid Howells p[call->count] = 0; 153845222b9eSDavid Howells _debug("offline '%s'", p); 153945222b9eSDavid Howells 154045222b9eSDavid Howells call->offset = 0; 154145222b9eSDavid Howells call->unmarshall++; 154245222b9eSDavid Howells 154345222b9eSDavid Howells /* extract the offline message padding */ 154445222b9eSDavid Howells if ((call->count & 3) == 0) { 154545222b9eSDavid Howells call->unmarshall++; 154645222b9eSDavid Howells goto no_offline_padding; 154745222b9eSDavid Howells } 154845222b9eSDavid Howells call->count = 4 - (call->count & 3); 154945222b9eSDavid Howells 155045222b9eSDavid Howells case 7: 1551d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1552d001648eSDavid Howells call->count, true); 1553372ee163SDavid Howells if (ret < 0) 1554372ee163SDavid Howells return ret; 155545222b9eSDavid Howells 155645222b9eSDavid Howells call->offset = 0; 155745222b9eSDavid Howells call->unmarshall++; 155845222b9eSDavid Howells no_offline_padding: 155945222b9eSDavid Howells 156045222b9eSDavid Howells /* extract the message of the day length */ 156145222b9eSDavid Howells case 8: 1562d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1563372ee163SDavid Howells if (ret < 0) 1564372ee163SDavid Howells return ret; 156545222b9eSDavid Howells 156645222b9eSDavid Howells call->count = ntohl(call->tmp); 156745222b9eSDavid Howells _debug("motd length: %u", call->count); 156845222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 156945222b9eSDavid Howells return -EBADMSG; 157045222b9eSDavid Howells call->offset = 0; 157145222b9eSDavid Howells call->unmarshall++; 157245222b9eSDavid Howells 157345222b9eSDavid Howells /* extract the message of the day */ 157445222b9eSDavid Howells case 9: 157545222b9eSDavid Howells _debug("extract motd"); 157645222b9eSDavid Howells if (call->count > 0) { 157797e3043aSDavid Howells ret = afs_extract_data(call, call->reply[2], 1578d001648eSDavid Howells call->count, true); 1579372ee163SDavid Howells if (ret < 0) 1580372ee163SDavid Howells return ret; 158145222b9eSDavid Howells } 158245222b9eSDavid Howells 158397e3043aSDavid Howells p = call->reply[2]; 158445222b9eSDavid Howells p[call->count] = 0; 158545222b9eSDavid Howells _debug("motd '%s'", p); 158645222b9eSDavid Howells 158745222b9eSDavid Howells call->offset = 0; 158845222b9eSDavid Howells call->unmarshall++; 158945222b9eSDavid Howells 159045222b9eSDavid Howells /* extract the message of the day padding */ 1591d001648eSDavid Howells call->count = (4 - (call->count & 3)) & 3; 159245222b9eSDavid Howells 159345222b9eSDavid Howells case 10: 1594d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1595d001648eSDavid Howells call->count, false); 1596372ee163SDavid Howells if (ret < 0) 1597372ee163SDavid Howells return ret; 159845222b9eSDavid Howells 159945222b9eSDavid Howells call->offset = 0; 160045222b9eSDavid Howells call->unmarshall++; 160145222b9eSDavid Howells case 11: 160245222b9eSDavid Howells break; 160345222b9eSDavid Howells } 160445222b9eSDavid Howells 160545222b9eSDavid Howells _leave(" = 0 [done]"); 160645222b9eSDavid Howells return 0; 160745222b9eSDavid Howells } 160845222b9eSDavid Howells 160945222b9eSDavid Howells /* 161045222b9eSDavid Howells * destroy an FS.GetVolumeStatus call 161145222b9eSDavid Howells */ 161245222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call) 161345222b9eSDavid Howells { 161497e3043aSDavid Howells kfree(call->reply[2]); 161597e3043aSDavid Howells call->reply[2] = NULL; 161645222b9eSDavid Howells afs_flat_call_destructor(call); 161745222b9eSDavid Howells } 161845222b9eSDavid Howells 161945222b9eSDavid Howells /* 162045222b9eSDavid Howells * FS.GetVolumeStatus operation type 162145222b9eSDavid Howells */ 162245222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 162345222b9eSDavid Howells .name = "FS.GetVolumeStatus", 1624025db80cSDavid Howells .op = afs_FS_GetVolumeStatus, 162545222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 162645222b9eSDavid Howells .destructor = afs_get_volume_status_call_destructor, 162745222b9eSDavid Howells }; 162845222b9eSDavid Howells 162945222b9eSDavid Howells /* 163045222b9eSDavid Howells * fetch the status of a volume 163145222b9eSDavid Howells */ 16328b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc, 1633d2ddc776SDavid Howells struct afs_volume_status *vs) 163445222b9eSDavid Howells { 1635d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 163645222b9eSDavid Howells struct afs_call *call; 1637f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 163845222b9eSDavid Howells __be32 *bp; 163945222b9eSDavid Howells void *tmpbuf; 164045222b9eSDavid Howells 164145222b9eSDavid Howells _enter(""); 164245222b9eSDavid Howells 164345222b9eSDavid Howells tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); 164445222b9eSDavid Howells if (!tmpbuf) 164545222b9eSDavid Howells return -ENOMEM; 164645222b9eSDavid Howells 1647f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); 164845222b9eSDavid Howells if (!call) { 164945222b9eSDavid Howells kfree(tmpbuf); 165045222b9eSDavid Howells return -ENOMEM; 165145222b9eSDavid Howells } 165245222b9eSDavid Howells 1653d2ddc776SDavid Howells call->key = fc->key; 165497e3043aSDavid Howells call->reply[0] = vnode; 165597e3043aSDavid Howells call->reply[1] = vs; 165697e3043aSDavid Howells call->reply[2] = tmpbuf; 165745222b9eSDavid Howells 165845222b9eSDavid Howells /* marshall the parameters */ 165945222b9eSDavid Howells bp = call->request; 166045222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 166145222b9eSDavid Howells bp[1] = htonl(vnode->fid.vid); 166245222b9eSDavid Howells 1663d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1664025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1665d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 166645222b9eSDavid Howells } 1667e8d6c554SDavid Howells 1668e8d6c554SDavid Howells /* 1669e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1670e8d6c554SDavid Howells */ 1671d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call) 1672e8d6c554SDavid Howells { 1673e8d6c554SDavid Howells const __be32 *bp; 1674372ee163SDavid Howells int ret; 1675e8d6c554SDavid Howells 1676d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1677e8d6c554SDavid Howells 1678d001648eSDavid Howells ret = afs_transfer_reply(call); 1679372ee163SDavid Howells if (ret < 0) 1680372ee163SDavid Howells return ret; 1681e8d6c554SDavid Howells 1682e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1683e8d6c554SDavid Howells bp = call->buffer; 168497e3043aSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->reply[X]); */ 1685e8d6c554SDavid Howells 1686e8d6c554SDavid Howells _leave(" = 0 [done]"); 1687e8d6c554SDavid Howells return 0; 1688e8d6c554SDavid Howells } 1689e8d6c554SDavid Howells 1690e8d6c554SDavid Howells /* 1691e8d6c554SDavid Howells * FS.SetLock operation type 1692e8d6c554SDavid Howells */ 1693e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1694e8d6c554SDavid Howells .name = "FS.SetLock", 1695025db80cSDavid Howells .op = afs_FS_SetLock, 1696e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1697e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1698e8d6c554SDavid Howells }; 1699e8d6c554SDavid Howells 1700e8d6c554SDavid Howells /* 1701e8d6c554SDavid Howells * FS.ExtendLock operation type 1702e8d6c554SDavid Howells */ 1703e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1704e8d6c554SDavid Howells .name = "FS.ExtendLock", 1705025db80cSDavid Howells .op = afs_FS_ExtendLock, 1706e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1707e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1708e8d6c554SDavid Howells }; 1709e8d6c554SDavid Howells 1710e8d6c554SDavid Howells /* 1711e8d6c554SDavid Howells * FS.ReleaseLock operation type 1712e8d6c554SDavid Howells */ 1713e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1714e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1715025db80cSDavid Howells .op = afs_FS_ReleaseLock, 1716e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1717e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1718e8d6c554SDavid Howells }; 1719e8d6c554SDavid Howells 1720e8d6c554SDavid Howells /* 1721d2ddc776SDavid Howells * Set a lock on a file 1722e8d6c554SDavid Howells */ 1723d2ddc776SDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type) 1724e8d6c554SDavid Howells { 1725d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1726e8d6c554SDavid Howells struct afs_call *call; 1727f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1728e8d6c554SDavid Howells __be32 *bp; 1729e8d6c554SDavid Howells 1730e8d6c554SDavid Howells _enter(""); 1731e8d6c554SDavid Howells 1732f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4); 1733e8d6c554SDavid Howells if (!call) 1734e8d6c554SDavid Howells return -ENOMEM; 1735e8d6c554SDavid Howells 1736d2ddc776SDavid Howells call->key = fc->key; 173797e3043aSDavid Howells call->reply[0] = vnode; 1738e8d6c554SDavid Howells 1739e8d6c554SDavid Howells /* marshall the parameters */ 1740e8d6c554SDavid Howells bp = call->request; 1741e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1742e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1743e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1744e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1745e8d6c554SDavid Howells *bp++ = htonl(type); 1746e8d6c554SDavid Howells 1747d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1748025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1749d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1750e8d6c554SDavid Howells } 1751e8d6c554SDavid Howells 1752e8d6c554SDavid Howells /* 1753e8d6c554SDavid Howells * extend a lock on a file 1754e8d6c554SDavid Howells */ 1755d2ddc776SDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc) 1756e8d6c554SDavid Howells { 1757d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1758e8d6c554SDavid Howells struct afs_call *call; 1759f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1760e8d6c554SDavid Howells __be32 *bp; 1761e8d6c554SDavid Howells 1762e8d6c554SDavid Howells _enter(""); 1763e8d6c554SDavid Howells 1764f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); 1765e8d6c554SDavid Howells if (!call) 1766e8d6c554SDavid Howells return -ENOMEM; 1767e8d6c554SDavid Howells 1768d2ddc776SDavid Howells call->key = fc->key; 176997e3043aSDavid Howells call->reply[0] = vnode; 1770e8d6c554SDavid Howells 1771e8d6c554SDavid Howells /* marshall the parameters */ 1772e8d6c554SDavid Howells bp = call->request; 1773e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1774e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1775e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1776e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1777e8d6c554SDavid Howells 1778d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1779025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1780d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1781e8d6c554SDavid Howells } 1782e8d6c554SDavid Howells 1783e8d6c554SDavid Howells /* 1784e8d6c554SDavid Howells * release a lock on a file 1785e8d6c554SDavid Howells */ 1786d2ddc776SDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc) 1787e8d6c554SDavid Howells { 1788d2ddc776SDavid Howells struct afs_vnode *vnode = fc->vnode; 1789e8d6c554SDavid Howells struct afs_call *call; 1790f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1791e8d6c554SDavid Howells __be32 *bp; 1792e8d6c554SDavid Howells 1793e8d6c554SDavid Howells _enter(""); 1794e8d6c554SDavid Howells 1795f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1796e8d6c554SDavid Howells if (!call) 1797e8d6c554SDavid Howells return -ENOMEM; 1798e8d6c554SDavid Howells 1799d2ddc776SDavid Howells call->key = fc->key; 180097e3043aSDavid Howells call->reply[0] = vnode; 1801e8d6c554SDavid Howells 1802e8d6c554SDavid Howells /* marshall the parameters */ 1803e8d6c554SDavid Howells bp = call->request; 1804e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1805e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1806e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1807e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1808e8d6c554SDavid Howells 1809d2ddc776SDavid Howells afs_use_fs_server(call, fc->cbi); 1810025db80cSDavid Howells trace_afs_make_fs_call(call, &vnode->fid); 1811d2ddc776SDavid Howells return afs_make_call(&fc->ac, call, GFP_NOFS, false); 1812c435ee34SDavid Howells } 1813c435ee34SDavid Howells 1814c435ee34SDavid Howells /* 1815c435ee34SDavid Howells * Deliver reply data to an FS.GiveUpAllCallBacks operation. 1816c435ee34SDavid Howells */ 1817c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call) 1818c435ee34SDavid Howells { 1819c435ee34SDavid Howells return afs_transfer_reply(call); 1820c435ee34SDavid Howells } 1821c435ee34SDavid Howells 1822c435ee34SDavid Howells /* 1823c435ee34SDavid Howells * FS.GiveUpAllCallBacks operation type 1824c435ee34SDavid Howells */ 1825c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = { 1826c435ee34SDavid Howells .name = "FS.GiveUpAllCallBacks", 1827025db80cSDavid Howells .op = afs_FS_GiveUpAllCallBacks, 1828c435ee34SDavid Howells .deliver = afs_deliver_fs_give_up_all_callbacks, 1829c435ee34SDavid Howells .destructor = afs_flat_call_destructor, 1830c435ee34SDavid Howells }; 1831c435ee34SDavid Howells 1832c435ee34SDavid Howells /* 1833c435ee34SDavid Howells * Flush all the callbacks we have on a server. 1834c435ee34SDavid Howells */ 1835d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net, 1836d2ddc776SDavid Howells struct afs_server *server, 18378b2a464cSDavid Howells struct afs_addr_cursor *ac, 1838d2ddc776SDavid Howells struct key *key) 1839c435ee34SDavid Howells { 1840c435ee34SDavid Howells struct afs_call *call; 1841c435ee34SDavid Howells __be32 *bp; 1842c435ee34SDavid Howells 1843c435ee34SDavid Howells _enter(""); 1844c435ee34SDavid Howells 1845d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0); 1846c435ee34SDavid Howells if (!call) 1847c435ee34SDavid Howells return -ENOMEM; 1848c435ee34SDavid Howells 1849c435ee34SDavid Howells call->key = key; 1850c435ee34SDavid Howells 1851c435ee34SDavid Howells /* marshall the parameters */ 1852c435ee34SDavid Howells bp = call->request; 1853c435ee34SDavid Howells *bp++ = htonl(FSGIVEUPALLCALLBACKS); 1854c435ee34SDavid Howells 1855c435ee34SDavid Howells /* Can't take a ref on server */ 1856d2ddc776SDavid Howells return afs_make_call(ac, call, GFP_NOFS, false); 1857d2ddc776SDavid Howells } 1858d2ddc776SDavid Howells 1859d2ddc776SDavid Howells /* 1860d2ddc776SDavid Howells * Deliver reply data to an FS.GetCapabilities operation. 1861d2ddc776SDavid Howells */ 1862d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call) 1863d2ddc776SDavid Howells { 1864d2ddc776SDavid Howells u32 count; 1865d2ddc776SDavid Howells int ret; 1866d2ddc776SDavid Howells 1867d2ddc776SDavid Howells _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); 1868d2ddc776SDavid Howells 1869d2ddc776SDavid Howells again: 1870d2ddc776SDavid Howells switch (call->unmarshall) { 1871d2ddc776SDavid Howells case 0: 1872d2ddc776SDavid Howells call->offset = 0; 1873d2ddc776SDavid Howells call->unmarshall++; 1874d2ddc776SDavid Howells 1875d2ddc776SDavid Howells /* Extract the capabilities word count */ 1876d2ddc776SDavid Howells case 1: 1877d2ddc776SDavid Howells ret = afs_extract_data(call, &call->tmp, 1878d2ddc776SDavid Howells 1 * sizeof(__be32), 1879d2ddc776SDavid Howells true); 1880d2ddc776SDavid Howells if (ret < 0) 1881d2ddc776SDavid Howells return ret; 1882d2ddc776SDavid Howells 1883d2ddc776SDavid Howells count = ntohl(call->tmp); 1884d2ddc776SDavid Howells 1885d2ddc776SDavid Howells call->count = count; 1886d2ddc776SDavid Howells call->count2 = count; 1887d2ddc776SDavid Howells call->offset = 0; 1888d2ddc776SDavid Howells call->unmarshall++; 1889d2ddc776SDavid Howells 1890d2ddc776SDavid Howells /* Extract capabilities words */ 1891d2ddc776SDavid Howells case 2: 1892d2ddc776SDavid Howells count = min(call->count, 16U); 1893d2ddc776SDavid Howells ret = afs_extract_data(call, call->buffer, 1894d2ddc776SDavid Howells count * sizeof(__be32), 1895d2ddc776SDavid Howells call->count > 16); 1896d2ddc776SDavid Howells if (ret < 0) 1897d2ddc776SDavid Howells return ret; 1898d2ddc776SDavid Howells 1899d2ddc776SDavid Howells /* TODO: Examine capabilities */ 1900d2ddc776SDavid Howells 1901d2ddc776SDavid Howells call->count -= count; 1902d2ddc776SDavid Howells if (call->count > 0) 1903d2ddc776SDavid Howells goto again; 1904d2ddc776SDavid Howells call->offset = 0; 1905d2ddc776SDavid Howells call->unmarshall++; 1906d2ddc776SDavid Howells break; 1907d2ddc776SDavid Howells } 1908d2ddc776SDavid Howells 1909d2ddc776SDavid Howells _leave(" = 0 [done]"); 1910d2ddc776SDavid Howells return 0; 1911d2ddc776SDavid Howells } 1912d2ddc776SDavid Howells 1913d2ddc776SDavid Howells /* 1914d2ddc776SDavid Howells * FS.GetCapabilities operation type 1915d2ddc776SDavid Howells */ 1916d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = { 1917d2ddc776SDavid Howells .name = "FS.GetCapabilities", 1918025db80cSDavid Howells .op = afs_FS_GetCapabilities, 1919d2ddc776SDavid Howells .deliver = afs_deliver_fs_get_capabilities, 1920d2ddc776SDavid Howells .destructor = afs_flat_call_destructor, 1921d2ddc776SDavid Howells }; 1922d2ddc776SDavid Howells 1923d2ddc776SDavid Howells /* 1924d2ddc776SDavid Howells * Probe a fileserver for the capabilities that it supports. This can 1925d2ddc776SDavid Howells * return up to 196 words. 1926d2ddc776SDavid Howells */ 1927d2ddc776SDavid Howells int afs_fs_get_capabilities(struct afs_net *net, 1928d2ddc776SDavid Howells struct afs_server *server, 1929d2ddc776SDavid Howells struct afs_addr_cursor *ac, 1930d2ddc776SDavid Howells struct key *key) 1931d2ddc776SDavid Howells { 1932d2ddc776SDavid Howells struct afs_call *call; 1933d2ddc776SDavid Howells __be32 *bp; 1934d2ddc776SDavid Howells 1935d2ddc776SDavid Howells _enter(""); 1936d2ddc776SDavid Howells 1937d2ddc776SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4); 1938d2ddc776SDavid Howells if (!call) 1939d2ddc776SDavid Howells return -ENOMEM; 1940d2ddc776SDavid Howells 1941d2ddc776SDavid Howells call->key = key; 1942d2ddc776SDavid Howells 1943d2ddc776SDavid Howells /* marshall the parameters */ 1944d2ddc776SDavid Howells bp = call->request; 1945d2ddc776SDavid Howells *bp++ = htonl(FSGETCAPABILITIES); 1946d2ddc776SDavid Howells 1947d2ddc776SDavid Howells /* Can't take a ref on server */ 1948025db80cSDavid Howells trace_afs_make_fs_call(call, NULL); 1949d2ddc776SDavid Howells return afs_make_call(ac, call, GFP_NOFS, false); 1950e8d6c554SDavid Howells } 1951