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 191da177e4SLinus Torvalds /* 20260a9803SDavid Howells * decode an AFSFid block 21260a9803SDavid Howells */ 22260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 23260a9803SDavid Howells { 24260a9803SDavid Howells const __be32 *bp = *_bp; 25260a9803SDavid Howells 26260a9803SDavid Howells fid->vid = ntohl(*bp++); 27260a9803SDavid Howells fid->vnode = ntohl(*bp++); 28260a9803SDavid Howells fid->unique = ntohl(*bp++); 29260a9803SDavid Howells *_bp = bp; 30260a9803SDavid Howells } 31260a9803SDavid Howells 32260a9803SDavid Howells /* 3308e0e7c8SDavid Howells * decode an AFSFetchStatus block 341da177e4SLinus Torvalds */ 3508e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 36260a9803SDavid Howells struct afs_file_status *status, 3731143d5dSDavid Howells struct afs_vnode *vnode, 3831143d5dSDavid Howells afs_dataversion_t *store_version) 391da177e4SLinus Torvalds { 4031143d5dSDavid Howells afs_dataversion_t expected_version; 4108e0e7c8SDavid Howells const __be32 *bp = *_bp; 4208e0e7c8SDavid Howells umode_t mode; 43260a9803SDavid Howells u64 data_version, size; 4408e0e7c8SDavid Howells u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ 45a0a5386aSEric W. Biederman kuid_t owner; 46a0a5386aSEric W. Biederman kgid_t group; 4708e0e7c8SDavid Howells 4808e0e7c8SDavid Howells #define EXTRACT(DST) \ 4908e0e7c8SDavid Howells do { \ 5008e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 5108e0e7c8SDavid Howells changed |= DST - x; \ 5208e0e7c8SDavid Howells DST = x; \ 5308e0e7c8SDavid Howells } while (0) 5408e0e7c8SDavid Howells 55260a9803SDavid Howells status->if_version = ntohl(*bp++); 56260a9803SDavid Howells EXTRACT(status->type); 57260a9803SDavid Howells EXTRACT(status->nlink); 58260a9803SDavid Howells size = ntohl(*bp++); 5908e0e7c8SDavid Howells data_version = ntohl(*bp++); 60260a9803SDavid Howells EXTRACT(status->author); 61a0a5386aSEric W. Biederman owner = make_kuid(&init_user_ns, ntohl(*bp++)); 62a0a5386aSEric W. Biederman changed |= !uid_eq(owner, status->owner); 63a0a5386aSEric W. Biederman status->owner = owner; 64260a9803SDavid Howells EXTRACT(status->caller_access); /* call ticket dependent */ 65260a9803SDavid Howells EXTRACT(status->anon_access); 66260a9803SDavid Howells EXTRACT(status->mode); 67260a9803SDavid Howells EXTRACT(status->parent.vnode); 68260a9803SDavid Howells EXTRACT(status->parent.unique); 6908e0e7c8SDavid Howells bp++; /* seg size */ 70260a9803SDavid Howells status->mtime_client = ntohl(*bp++); 71260a9803SDavid Howells status->mtime_server = ntohl(*bp++); 72a0a5386aSEric W. Biederman group = make_kgid(&init_user_ns, ntohl(*bp++)); 73a0a5386aSEric W. Biederman changed |= !gid_eq(group, status->group); 74a0a5386aSEric W. Biederman status->group = group; 7508e0e7c8SDavid Howells bp++; /* sync counter */ 7608e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 77e8d6c554SDavid Howells EXTRACT(status->lock_count); 78260a9803SDavid Howells size |= (u64) ntohl(*bp++) << 32; 7908e0e7c8SDavid Howells bp++; /* spare 4 */ 8008e0e7c8SDavid Howells *_bp = bp; 8108e0e7c8SDavid Howells 82260a9803SDavid Howells if (size != status->size) { 83260a9803SDavid Howells status->size = size; 84260a9803SDavid Howells changed |= true; 85260a9803SDavid Howells } 86260a9803SDavid Howells status->mode &= S_IALLUGO; 8708e0e7c8SDavid Howells 88260a9803SDavid Howells _debug("vnode time %lx, %lx", 89260a9803SDavid Howells status->mtime_client, status->mtime_server); 90260a9803SDavid Howells 91260a9803SDavid Howells if (vnode) { 92260a9803SDavid Howells status->parent.vid = vnode->fid.vid; 93260a9803SDavid Howells if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 94260a9803SDavid Howells _debug("vnode changed"); 95260a9803SDavid Howells i_size_write(&vnode->vfs_inode, size); 96260a9803SDavid Howells vnode->vfs_inode.i_uid = status->owner; 97260a9803SDavid Howells vnode->vfs_inode.i_gid = status->group; 98d6e43f75SDavid Howells vnode->vfs_inode.i_generation = vnode->fid.unique; 99bfe86848SMiklos Szeredi set_nlink(&vnode->vfs_inode, status->nlink); 100260a9803SDavid Howells 10108e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 10208e0e7c8SDavid Howells mode &= ~S_IALLUGO; 103260a9803SDavid Howells mode |= status->mode; 104260a9803SDavid Howells barrier(); 10508e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 10608e0e7c8SDavid Howells } 10708e0e7c8SDavid Howells 108260a9803SDavid Howells vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; 10908e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 11008e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 111d6e43f75SDavid Howells vnode->vfs_inode.i_version = data_version; 112260a9803SDavid Howells } 11308e0e7c8SDavid Howells 11431143d5dSDavid Howells expected_version = status->data_version; 11531143d5dSDavid Howells if (store_version) 11631143d5dSDavid Howells expected_version = *store_version; 11731143d5dSDavid Howells 11831143d5dSDavid Howells if (expected_version != data_version) { 119260a9803SDavid Howells status->data_version = data_version; 120260a9803SDavid Howells if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 121260a9803SDavid Howells _debug("vnode modified %llx on {%x:%u}", 122ba3e0e1aSDavid S. Miller (unsigned long long) data_version, 123ba3e0e1aSDavid S. Miller vnode->fid.vid, vnode->fid.vnode); 12408e0e7c8SDavid Howells set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 12508e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1261da177e4SLinus Torvalds } 12731143d5dSDavid Howells } else if (store_version) { 12831143d5dSDavid Howells status->data_version = data_version; 129ec26815aSDavid Howells } 130260a9803SDavid Howells } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds /* 13308e0e7c8SDavid Howells * decode an AFSCallBack block 1341da177e4SLinus Torvalds */ 13508e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) 1361da177e4SLinus Torvalds { 13708e0e7c8SDavid Howells const __be32 *bp = *_bp; 1381da177e4SLinus Torvalds 13908e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 14008e0e7c8SDavid Howells vnode->cb_expiry = ntohl(*bp++); 14108e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 14208e0e7c8SDavid Howells vnode->cb_expires = vnode->cb_expiry + get_seconds(); 14308e0e7c8SDavid Howells *_bp = bp; 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 146260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 147260a9803SDavid Howells struct afs_callback *cb) 148260a9803SDavid Howells { 149260a9803SDavid Howells const __be32 *bp = *_bp; 150260a9803SDavid Howells 151260a9803SDavid Howells cb->version = ntohl(*bp++); 152260a9803SDavid Howells cb->expiry = ntohl(*bp++); 153260a9803SDavid Howells cb->type = ntohl(*bp++); 154260a9803SDavid Howells *_bp = bp; 155260a9803SDavid Howells } 156260a9803SDavid Howells 1571da177e4SLinus Torvalds /* 15808e0e7c8SDavid Howells * decode an AFSVolSync block 1591da177e4SLinus Torvalds */ 16008e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 16108e0e7c8SDavid Howells struct afs_volsync *volsync) 1621da177e4SLinus Torvalds { 16308e0e7c8SDavid Howells const __be32 *bp = *_bp; 1641da177e4SLinus Torvalds 16508e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 16608e0e7c8SDavid Howells bp++; /* spare2 */ 16708e0e7c8SDavid Howells bp++; /* spare3 */ 16808e0e7c8SDavid Howells bp++; /* spare4 */ 16908e0e7c8SDavid Howells bp++; /* spare5 */ 17008e0e7c8SDavid Howells bp++; /* spare6 */ 17108e0e7c8SDavid Howells *_bp = bp; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 17408e0e7c8SDavid Howells /* 17531143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 17631143d5dSDavid Howells */ 17731143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 17831143d5dSDavid Howells { 17931143d5dSDavid Howells __be32 *bp = *_bp; 18031143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 18131143d5dSDavid Howells 18231143d5dSDavid Howells mask = 0; 18331143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 18431143d5dSDavid Howells mask |= AFS_SET_MTIME; 18531143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 18631143d5dSDavid Howells } 18731143d5dSDavid Howells 18831143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 18931143d5dSDavid Howells mask |= AFS_SET_OWNER; 190a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 19131143d5dSDavid Howells } 19231143d5dSDavid Howells 19331143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 19431143d5dSDavid Howells mask |= AFS_SET_GROUP; 195a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 19631143d5dSDavid Howells } 19731143d5dSDavid Howells 19831143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 19931143d5dSDavid Howells mask |= AFS_SET_MODE; 20031143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 20131143d5dSDavid Howells } 20231143d5dSDavid Howells 20331143d5dSDavid Howells *bp++ = htonl(mask); 20431143d5dSDavid Howells *bp++ = htonl(mtime); 20531143d5dSDavid Howells *bp++ = htonl(owner); 20631143d5dSDavid Howells *bp++ = htonl(group); 20731143d5dSDavid Howells *bp++ = htonl(mode); 20831143d5dSDavid Howells *bp++ = 0; /* segment size */ 20931143d5dSDavid Howells *_bp = bp; 21031143d5dSDavid Howells } 21131143d5dSDavid Howells 21231143d5dSDavid Howells /* 21345222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 21445222b9eSDavid Howells */ 21545222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 21645222b9eSDavid Howells struct afs_volume_status *vs) 21745222b9eSDavid Howells { 21845222b9eSDavid Howells const __be32 *bp = *_bp; 21945222b9eSDavid Howells 22045222b9eSDavid Howells vs->vid = ntohl(*bp++); 22145222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 22245222b9eSDavid Howells vs->online = ntohl(*bp++); 22345222b9eSDavid Howells vs->in_service = ntohl(*bp++); 22445222b9eSDavid Howells vs->blessed = ntohl(*bp++); 22545222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 22645222b9eSDavid Howells vs->type = ntohl(*bp++); 22745222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 22845222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 22945222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 23045222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 23145222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 23245222b9eSDavid Howells *_bp = bp; 23345222b9eSDavid Howells } 23445222b9eSDavid Howells 23545222b9eSDavid Howells /* 23608e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 23708e0e7c8SDavid Howells */ 23808e0e7c8SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call, 23908e0e7c8SDavid Howells struct sk_buff *skb, bool last) 24008e0e7c8SDavid Howells { 241260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 24208e0e7c8SDavid Howells const __be32 *bp; 2431da177e4SLinus Torvalds 24408e0e7c8SDavid Howells _enter(",,%u", last); 2451da177e4SLinus Torvalds 24608e0e7c8SDavid Howells afs_transfer_reply(call, skb); 24708e0e7c8SDavid Howells if (!last) 24808e0e7c8SDavid Howells return 0; 2491da177e4SLinus Torvalds 25008e0e7c8SDavid Howells if (call->reply_size != call->reply_max) 25108e0e7c8SDavid Howells return -EBADMSG; 2521da177e4SLinus Torvalds 25308e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 25408e0e7c8SDavid Howells bp = call->buffer; 25531143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 256260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 25708e0e7c8SDavid Howells if (call->reply2) 25808e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 2591da177e4SLinus Torvalds 26008e0e7c8SDavid Howells _leave(" = 0 [done]"); 26108e0e7c8SDavid Howells return 0; 262ec26815aSDavid Howells } 26308e0e7c8SDavid Howells 26408e0e7c8SDavid Howells /* 26508e0e7c8SDavid Howells * FS.FetchStatus operation type 26608e0e7c8SDavid Howells */ 26708e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 26800d3b7a4SDavid Howells .name = "FS.FetchStatus", 26908e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 27008e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 27108e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 27208e0e7c8SDavid Howells }; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds /* 2751da177e4SLinus Torvalds * fetch the status information for a file 2761da177e4SLinus Torvalds */ 27708e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server, 27800d3b7a4SDavid Howells struct key *key, 2791da177e4SLinus Torvalds struct afs_vnode *vnode, 28008e0e7c8SDavid Howells struct afs_volsync *volsync, 28108e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 2821da177e4SLinus Torvalds { 28308e0e7c8SDavid Howells struct afs_call *call; 2841da177e4SLinus Torvalds __be32 *bp; 2851da177e4SLinus Torvalds 286416351f2SDavid Howells _enter(",%x,{%x:%u},,", 287260a9803SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 2881da177e4SLinus Torvalds 289260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 29008e0e7c8SDavid Howells if (!call) 29108e0e7c8SDavid Howells return -ENOMEM; 2921da177e4SLinus Torvalds 29300d3b7a4SDavid Howells call->key = key; 29408e0e7c8SDavid Howells call->reply = vnode; 29508e0e7c8SDavid Howells call->reply2 = volsync; 29608e0e7c8SDavid Howells call->service_id = FS_SERVICE; 29708e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds /* marshall the parameters */ 30008e0e7c8SDavid Howells bp = call->request; 3011da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 3021da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 3031da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 3041da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 3051da177e4SLinus Torvalds 30608e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 307ec26815aSDavid Howells } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds /* 31008e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 3111da177e4SLinus Torvalds */ 31208e0e7c8SDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call, 31308e0e7c8SDavid Howells struct sk_buff *skb, bool last) 3141da177e4SLinus Torvalds { 315260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 31608e0e7c8SDavid Howells const __be32 *bp; 31708e0e7c8SDavid Howells struct page *page; 31808e0e7c8SDavid Howells void *buffer; 3191da177e4SLinus Torvalds int ret; 3201da177e4SLinus Torvalds 32108e0e7c8SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 3221da177e4SLinus Torvalds 32308e0e7c8SDavid Howells switch (call->unmarshall) { 32408e0e7c8SDavid Howells case 0: 32508e0e7c8SDavid Howells call->offset = 0; 32608e0e7c8SDavid Howells call->unmarshall++; 327b9b1f8d5SDavid Howells if (call->operation_ID != FSFETCHDATA64) { 328b9b1f8d5SDavid Howells call->unmarshall++; 329b9b1f8d5SDavid Howells goto no_msw; 330b9b1f8d5SDavid Howells } 3311da177e4SLinus Torvalds 332b9b1f8d5SDavid Howells /* extract the upper part of the returned data length of an 333b9b1f8d5SDavid Howells * FSFETCHDATA64 op (which should always be 0 using this 334b9b1f8d5SDavid Howells * client) */ 33508e0e7c8SDavid Howells case 1: 336b9b1f8d5SDavid Howells _debug("extract data length (MSW)"); 337b9b1f8d5SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 338b9b1f8d5SDavid Howells switch (ret) { 339b9b1f8d5SDavid Howells case 0: break; 340b9b1f8d5SDavid Howells case -EAGAIN: return 0; 341b9b1f8d5SDavid Howells default: return ret; 342b9b1f8d5SDavid Howells } 343b9b1f8d5SDavid Howells 344b9b1f8d5SDavid Howells call->count = ntohl(call->tmp); 345b9b1f8d5SDavid Howells _debug("DATA length MSW: %u", call->count); 346b9b1f8d5SDavid Howells if (call->count > 0) 347b9b1f8d5SDavid Howells return -EBADMSG; 348b9b1f8d5SDavid Howells call->offset = 0; 349b9b1f8d5SDavid Howells call->unmarshall++; 350b9b1f8d5SDavid Howells 351b9b1f8d5SDavid Howells no_msw: 352b9b1f8d5SDavid Howells /* extract the returned data length */ 353b9b1f8d5SDavid Howells case 2: 35408e0e7c8SDavid Howells _debug("extract data length"); 35508e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 35608e0e7c8SDavid Howells switch (ret) { 35708e0e7c8SDavid Howells case 0: break; 35808e0e7c8SDavid Howells case -EAGAIN: return 0; 35908e0e7c8SDavid Howells default: return ret; 3601da177e4SLinus Torvalds } 3611da177e4SLinus Torvalds 36208e0e7c8SDavid Howells call->count = ntohl(call->tmp); 36308e0e7c8SDavid Howells _debug("DATA length: %u", call->count); 36408e0e7c8SDavid Howells if (call->count > PAGE_SIZE) 36508e0e7c8SDavid Howells return -EBADMSG; 36608e0e7c8SDavid Howells call->offset = 0; 36708e0e7c8SDavid Howells call->unmarshall++; 3681da177e4SLinus Torvalds 36908e0e7c8SDavid Howells /* extract the returned data */ 370b9b1f8d5SDavid Howells case 3: 37108e0e7c8SDavid Howells _debug("extract data"); 372416351f2SDavid Howells if (call->count > 0) { 37308e0e7c8SDavid Howells page = call->reply3; 374da4aa36dSCong Wang buffer = kmap_atomic(page); 375416351f2SDavid Howells ret = afs_extract_data(call, skb, last, buffer, 376416351f2SDavid Howells call->count); 377da4aa36dSCong Wang kunmap_atomic(buffer); 37808e0e7c8SDavid Howells switch (ret) { 37908e0e7c8SDavid Howells case 0: break; 38008e0e7c8SDavid Howells case -EAGAIN: return 0; 38108e0e7c8SDavid Howells default: return ret; 3821da177e4SLinus Torvalds } 383416351f2SDavid Howells } 3841da177e4SLinus Torvalds 38508e0e7c8SDavid Howells call->offset = 0; 38608e0e7c8SDavid Howells call->unmarshall++; 38708e0e7c8SDavid Howells 38808e0e7c8SDavid Howells /* extract the metadata */ 389b9b1f8d5SDavid Howells case 4: 390260a9803SDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 391260a9803SDavid Howells (21 + 3 + 6) * 4); 39208e0e7c8SDavid Howells switch (ret) { 39308e0e7c8SDavid Howells case 0: break; 39408e0e7c8SDavid Howells case -EAGAIN: return 0; 39508e0e7c8SDavid Howells default: return ret; 396ec26815aSDavid Howells } 3971da177e4SLinus Torvalds 39808e0e7c8SDavid Howells bp = call->buffer; 39931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 400260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 40108e0e7c8SDavid Howells if (call->reply2) 40208e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 4031da177e4SLinus Torvalds 40408e0e7c8SDavid Howells call->offset = 0; 40508e0e7c8SDavid Howells call->unmarshall++; 4061da177e4SLinus Torvalds 407b9b1f8d5SDavid Howells case 5: 40808e0e7c8SDavid Howells _debug("trailer"); 40908e0e7c8SDavid Howells if (skb->len != 0) 41008e0e7c8SDavid Howells return -EBADMSG; 4111da177e4SLinus Torvalds break; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 41408e0e7c8SDavid Howells if (!last) 41508e0e7c8SDavid Howells return 0; 4161da177e4SLinus Torvalds 417416351f2SDavid Howells if (call->count < PAGE_SIZE) { 418416351f2SDavid Howells _debug("clear"); 419416351f2SDavid Howells page = call->reply3; 420da4aa36dSCong Wang buffer = kmap_atomic(page); 421416351f2SDavid Howells memset(buffer + call->count, 0, PAGE_SIZE - call->count); 422da4aa36dSCong Wang kunmap_atomic(buffer); 423416351f2SDavid Howells } 424416351f2SDavid Howells 42508e0e7c8SDavid Howells _leave(" = 0 [done]"); 42608e0e7c8SDavid Howells return 0; 427ec26815aSDavid Howells } 4281da177e4SLinus Torvalds 4291da177e4SLinus Torvalds /* 43008e0e7c8SDavid Howells * FS.FetchData operation type 4311da177e4SLinus Torvalds */ 43208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 43300d3b7a4SDavid Howells .name = "FS.FetchData", 43408e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 43508e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 43608e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 43708e0e7c8SDavid Howells }; 43808e0e7c8SDavid Howells 439b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 440b9b1f8d5SDavid Howells .name = "FS.FetchData64", 441b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 442b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 443b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 444b9b1f8d5SDavid Howells }; 445b9b1f8d5SDavid Howells 446b9b1f8d5SDavid Howells /* 447b9b1f8d5SDavid Howells * fetch data from a very large file 448b9b1f8d5SDavid Howells */ 449b9b1f8d5SDavid Howells static int afs_fs_fetch_data64(struct afs_server *server, 450b9b1f8d5SDavid Howells struct key *key, 451b9b1f8d5SDavid Howells struct afs_vnode *vnode, 452b9b1f8d5SDavid Howells off_t offset, size_t length, 453b9b1f8d5SDavid Howells struct page *buffer, 454b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 455b9b1f8d5SDavid Howells { 456b9b1f8d5SDavid Howells struct afs_call *call; 457b9b1f8d5SDavid Howells __be32 *bp; 458b9b1f8d5SDavid Howells 459b9b1f8d5SDavid Howells _enter(""); 460b9b1f8d5SDavid Howells 461b9b1f8d5SDavid Howells ASSERTCMP(length, <, ULONG_MAX); 462b9b1f8d5SDavid Howells 463b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 464b9b1f8d5SDavid Howells if (!call) 465b9b1f8d5SDavid Howells return -ENOMEM; 466b9b1f8d5SDavid Howells 467b9b1f8d5SDavid Howells call->key = key; 468b9b1f8d5SDavid Howells call->reply = vnode; 469b9b1f8d5SDavid Howells call->reply2 = NULL; /* volsync */ 470b9b1f8d5SDavid Howells call->reply3 = buffer; 471b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 472b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 473b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA64; 474b9b1f8d5SDavid Howells 475b9b1f8d5SDavid Howells /* marshall the parameters */ 476b9b1f8d5SDavid Howells bp = call->request; 477b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 478b9b1f8d5SDavid Howells bp[1] = htonl(vnode->fid.vid); 479b9b1f8d5SDavid Howells bp[2] = htonl(vnode->fid.vnode); 480b9b1f8d5SDavid Howells bp[3] = htonl(vnode->fid.unique); 481b9b1f8d5SDavid Howells bp[4] = htonl(upper_32_bits(offset)); 482b9b1f8d5SDavid Howells bp[5] = htonl((u32) offset); 483b9b1f8d5SDavid Howells bp[6] = 0; 484b9b1f8d5SDavid Howells bp[7] = htonl((u32) length); 485b9b1f8d5SDavid Howells 486b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 487b9b1f8d5SDavid Howells } 488b9b1f8d5SDavid Howells 48908e0e7c8SDavid Howells /* 49008e0e7c8SDavid Howells * fetch data from a file 49108e0e7c8SDavid Howells */ 49208e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 49300d3b7a4SDavid Howells struct key *key, 4941da177e4SLinus Torvalds struct afs_vnode *vnode, 49508e0e7c8SDavid Howells off_t offset, size_t length, 49608e0e7c8SDavid Howells struct page *buffer, 49708e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 4981da177e4SLinus Torvalds { 49908e0e7c8SDavid Howells struct afs_call *call; 50008e0e7c8SDavid Howells __be32 *bp; 5011da177e4SLinus Torvalds 502b9b1f8d5SDavid Howells if (upper_32_bits(offset) || upper_32_bits(offset + length)) 503b9b1f8d5SDavid Howells return afs_fs_fetch_data64(server, key, vnode, offset, length, 504b9b1f8d5SDavid Howells buffer, wait_mode); 505b9b1f8d5SDavid Howells 50608e0e7c8SDavid Howells _enter(""); 5071da177e4SLinus Torvalds 508260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 50908e0e7c8SDavid Howells if (!call) 51008e0e7c8SDavid Howells return -ENOMEM; 5111da177e4SLinus Torvalds 51200d3b7a4SDavid Howells call->key = key; 51308e0e7c8SDavid Howells call->reply = vnode; 514260a9803SDavid Howells call->reply2 = NULL; /* volsync */ 51508e0e7c8SDavid Howells call->reply3 = buffer; 51608e0e7c8SDavid Howells call->service_id = FS_SERVICE; 51708e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 518b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* marshall the parameters */ 52108e0e7c8SDavid Howells bp = call->request; 52208e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 52308e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 52408e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 52508e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 52608e0e7c8SDavid Howells bp[4] = htonl(offset); 52708e0e7c8SDavid Howells bp[5] = htonl(length); 5281da177e4SLinus Torvalds 52908e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 53208e0e7c8SDavid Howells /* 53308e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 53408e0e7c8SDavid Howells */ 53508e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, 53608e0e7c8SDavid Howells struct sk_buff *skb, bool last) 53708e0e7c8SDavid Howells { 53808e0e7c8SDavid Howells _enter(",{%u},%d", skb->len, last); 5391da177e4SLinus Torvalds 54008e0e7c8SDavid Howells if (skb->len > 0) 54108e0e7c8SDavid Howells return -EBADMSG; /* shouldn't be any reply data */ 54208e0e7c8SDavid Howells return 0; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 54508e0e7c8SDavid Howells /* 54608e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 54708e0e7c8SDavid Howells */ 54808e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 54900d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 55008e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 55108e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 55208e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 55308e0e7c8SDavid Howells }; 5541da177e4SLinus Torvalds 55508e0e7c8SDavid Howells /* 55608e0e7c8SDavid Howells * give up a set of callbacks 55708e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 55808e0e7c8SDavid Howells */ 55908e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server, 56008e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 56108e0e7c8SDavid Howells { 56208e0e7c8SDavid Howells struct afs_call *call; 56308e0e7c8SDavid Howells size_t ncallbacks; 56408e0e7c8SDavid Howells __be32 *bp, *tp; 56508e0e7c8SDavid Howells int loop; 5661da177e4SLinus Torvalds 56708e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 56808e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 56908e0e7c8SDavid Howells 57008e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 57108e0e7c8SDavid Howells 57208e0e7c8SDavid Howells if (ncallbacks == 0) 57308e0e7c8SDavid Howells return 0; 57408e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 57508e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 57608e0e7c8SDavid Howells 57708e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 57808e0e7c8SDavid Howells 57908e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, 58008e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 58108e0e7c8SDavid Howells if (!call) 58208e0e7c8SDavid Howells return -ENOMEM; 58308e0e7c8SDavid Howells 58408e0e7c8SDavid Howells call->service_id = FS_SERVICE; 58508e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 58608e0e7c8SDavid Howells 58708e0e7c8SDavid Howells /* marshall the parameters */ 58808e0e7c8SDavid Howells bp = call->request; 58908e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 59008e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 59108e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 59208e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 59308e0e7c8SDavid Howells 59408e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 59508e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 59608e0e7c8SDavid Howells struct afs_callback *cb = 59708e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 59808e0e7c8SDavid Howells 59908e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 60008e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 60108e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 60208e0e7c8SDavid Howells *tp++ = htonl(cb->version); 60308e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 60408e0e7c8SDavid Howells *tp++ = htonl(cb->type); 60508e0e7c8SDavid Howells smp_mb(); 60608e0e7c8SDavid Howells server->cb_break_tail = 60708e0e7c8SDavid Howells (server->cb_break_tail + 1) & 60808e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 609ec26815aSDavid Howells } 61008e0e7c8SDavid Howells 61108e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 61208e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 61308e0e7c8SDavid Howells 61408e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 61508e0e7c8SDavid Howells } 616260a9803SDavid Howells 617260a9803SDavid Howells /* 618260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 619260a9803SDavid Howells */ 620260a9803SDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call, 621260a9803SDavid Howells struct sk_buff *skb, bool last) 622260a9803SDavid Howells { 623260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 624260a9803SDavid Howells const __be32 *bp; 625260a9803SDavid Howells 626260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 627260a9803SDavid Howells 628260a9803SDavid Howells afs_transfer_reply(call, skb); 629260a9803SDavid Howells if (!last) 630260a9803SDavid Howells return 0; 631260a9803SDavid Howells 632260a9803SDavid Howells if (call->reply_size != call->reply_max) 633260a9803SDavid Howells return -EBADMSG; 634260a9803SDavid Howells 635260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 636260a9803SDavid Howells bp = call->buffer; 637260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 63831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 63931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 640260a9803SDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply4); 641260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 642260a9803SDavid Howells 643260a9803SDavid Howells _leave(" = 0 [done]"); 644260a9803SDavid Howells return 0; 645260a9803SDavid Howells } 646260a9803SDavid Howells 647260a9803SDavid Howells /* 648260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 649260a9803SDavid Howells */ 650260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = { 651260a9803SDavid Howells .name = "FS.CreateXXXX", 652260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 653260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 654260a9803SDavid Howells .destructor = afs_flat_call_destructor, 655260a9803SDavid Howells }; 656260a9803SDavid Howells 657260a9803SDavid Howells /* 658260a9803SDavid Howells * create a file or make a directory 659260a9803SDavid Howells */ 660260a9803SDavid Howells int afs_fs_create(struct afs_server *server, 661260a9803SDavid Howells struct key *key, 662260a9803SDavid Howells struct afs_vnode *vnode, 663260a9803SDavid Howells const char *name, 664260a9803SDavid Howells umode_t mode, 665260a9803SDavid Howells struct afs_fid *newfid, 666260a9803SDavid Howells struct afs_file_status *newstatus, 667260a9803SDavid Howells struct afs_callback *newcb, 668260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 669260a9803SDavid Howells { 670260a9803SDavid Howells struct afs_call *call; 671260a9803SDavid Howells size_t namesz, reqsz, padsz; 672260a9803SDavid Howells __be32 *bp; 673260a9803SDavid Howells 674260a9803SDavid Howells _enter(""); 675260a9803SDavid Howells 676260a9803SDavid Howells namesz = strlen(name); 677260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 678260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 679260a9803SDavid Howells 680260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, 681260a9803SDavid Howells (3 + 21 + 21 + 3 + 6) * 4); 682260a9803SDavid Howells if (!call) 683260a9803SDavid Howells return -ENOMEM; 684260a9803SDavid Howells 685260a9803SDavid Howells call->key = key; 686260a9803SDavid Howells call->reply = vnode; 687260a9803SDavid Howells call->reply2 = newfid; 688260a9803SDavid Howells call->reply3 = newstatus; 689260a9803SDavid Howells call->reply4 = newcb; 690260a9803SDavid Howells call->service_id = FS_SERVICE; 691260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 692260a9803SDavid Howells 693260a9803SDavid Howells /* marshall the parameters */ 694260a9803SDavid Howells bp = call->request; 695260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 696260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 697260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 698260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 699260a9803SDavid Howells *bp++ = htonl(namesz); 700260a9803SDavid Howells memcpy(bp, name, namesz); 701260a9803SDavid Howells bp = (void *) bp + namesz; 702260a9803SDavid Howells if (padsz > 0) { 703260a9803SDavid Howells memset(bp, 0, padsz); 704260a9803SDavid Howells bp = (void *) bp + padsz; 705260a9803SDavid Howells } 706260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 707260a9803SDavid Howells *bp++ = 0; /* mtime */ 708260a9803SDavid Howells *bp++ = 0; /* owner */ 709260a9803SDavid Howells *bp++ = 0; /* group */ 710260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 711260a9803SDavid Howells *bp++ = 0; /* segment size */ 712260a9803SDavid Howells 713260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 714260a9803SDavid Howells } 715260a9803SDavid Howells 716260a9803SDavid Howells /* 717260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 718260a9803SDavid Howells */ 719260a9803SDavid Howells static int afs_deliver_fs_remove(struct afs_call *call, 720260a9803SDavid Howells struct sk_buff *skb, bool last) 721260a9803SDavid Howells { 722260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 723260a9803SDavid Howells const __be32 *bp; 724260a9803SDavid Howells 725260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 726260a9803SDavid Howells 727260a9803SDavid Howells afs_transfer_reply(call, skb); 728260a9803SDavid Howells if (!last) 729260a9803SDavid Howells return 0; 730260a9803SDavid Howells 731260a9803SDavid Howells if (call->reply_size != call->reply_max) 732260a9803SDavid Howells return -EBADMSG; 733260a9803SDavid Howells 734260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 735260a9803SDavid Howells bp = call->buffer; 73631143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 737260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 738260a9803SDavid Howells 739260a9803SDavid Howells _leave(" = 0 [done]"); 740260a9803SDavid Howells return 0; 741260a9803SDavid Howells } 742260a9803SDavid Howells 743260a9803SDavid Howells /* 744260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 745260a9803SDavid Howells */ 746260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = { 747260a9803SDavid Howells .name = "FS.RemoveXXXX", 748260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 749260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 750260a9803SDavid Howells .destructor = afs_flat_call_destructor, 751260a9803SDavid Howells }; 752260a9803SDavid Howells 753260a9803SDavid Howells /* 754260a9803SDavid Howells * remove a file or directory 755260a9803SDavid Howells */ 756260a9803SDavid Howells int afs_fs_remove(struct afs_server *server, 757260a9803SDavid Howells struct key *key, 758260a9803SDavid Howells struct afs_vnode *vnode, 759260a9803SDavid Howells const char *name, 760260a9803SDavid Howells bool isdir, 761260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 762260a9803SDavid Howells { 763260a9803SDavid Howells struct afs_call *call; 764260a9803SDavid Howells size_t namesz, reqsz, padsz; 765260a9803SDavid Howells __be32 *bp; 766260a9803SDavid Howells 767260a9803SDavid Howells _enter(""); 768260a9803SDavid Howells 769260a9803SDavid Howells namesz = strlen(name); 770260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 771260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 772260a9803SDavid Howells 773260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); 774260a9803SDavid Howells if (!call) 775260a9803SDavid Howells return -ENOMEM; 776260a9803SDavid Howells 777260a9803SDavid Howells call->key = key; 778260a9803SDavid Howells call->reply = vnode; 779260a9803SDavid Howells call->service_id = FS_SERVICE; 780260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 781260a9803SDavid Howells 782260a9803SDavid Howells /* marshall the parameters */ 783260a9803SDavid Howells bp = call->request; 784260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 785260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 786260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 787260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 788260a9803SDavid Howells *bp++ = htonl(namesz); 789260a9803SDavid Howells memcpy(bp, name, namesz); 790260a9803SDavid Howells bp = (void *) bp + namesz; 791260a9803SDavid Howells if (padsz > 0) { 792260a9803SDavid Howells memset(bp, 0, padsz); 793260a9803SDavid Howells bp = (void *) bp + padsz; 794260a9803SDavid Howells } 795260a9803SDavid Howells 796260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 797260a9803SDavid Howells } 798260a9803SDavid Howells 799260a9803SDavid Howells /* 800260a9803SDavid Howells * deliver reply data to an FS.Link 801260a9803SDavid Howells */ 802260a9803SDavid Howells static int afs_deliver_fs_link(struct afs_call *call, 803260a9803SDavid Howells struct sk_buff *skb, bool last) 804260a9803SDavid Howells { 805260a9803SDavid Howells struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; 806260a9803SDavid Howells const __be32 *bp; 807260a9803SDavid Howells 808260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 809260a9803SDavid Howells 810260a9803SDavid Howells afs_transfer_reply(call, skb); 811260a9803SDavid Howells if (!last) 812260a9803SDavid Howells return 0; 813260a9803SDavid Howells 814260a9803SDavid Howells if (call->reply_size != call->reply_max) 815260a9803SDavid Howells return -EBADMSG; 816260a9803SDavid Howells 817260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 818260a9803SDavid Howells bp = call->buffer; 81931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 82031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); 821260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 822260a9803SDavid Howells 823260a9803SDavid Howells _leave(" = 0 [done]"); 824260a9803SDavid Howells return 0; 825260a9803SDavid Howells } 826260a9803SDavid Howells 827260a9803SDavid Howells /* 828260a9803SDavid Howells * FS.Link operation type 829260a9803SDavid Howells */ 830260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 831260a9803SDavid Howells .name = "FS.Link", 832260a9803SDavid Howells .deliver = afs_deliver_fs_link, 833260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 834260a9803SDavid Howells .destructor = afs_flat_call_destructor, 835260a9803SDavid Howells }; 836260a9803SDavid Howells 837260a9803SDavid Howells /* 838260a9803SDavid Howells * make a hard link 839260a9803SDavid Howells */ 840260a9803SDavid Howells int afs_fs_link(struct afs_server *server, 841260a9803SDavid Howells struct key *key, 842260a9803SDavid Howells struct afs_vnode *dvnode, 843260a9803SDavid Howells struct afs_vnode *vnode, 844260a9803SDavid Howells const char *name, 845260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 846260a9803SDavid Howells { 847260a9803SDavid Howells struct afs_call *call; 848260a9803SDavid Howells size_t namesz, reqsz, padsz; 849260a9803SDavid Howells __be32 *bp; 850260a9803SDavid Howells 851260a9803SDavid Howells _enter(""); 852260a9803SDavid Howells 853260a9803SDavid Howells namesz = strlen(name); 854260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 855260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 856260a9803SDavid Howells 857260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 858260a9803SDavid Howells if (!call) 859260a9803SDavid Howells return -ENOMEM; 860260a9803SDavid Howells 861260a9803SDavid Howells call->key = key; 862260a9803SDavid Howells call->reply = dvnode; 863260a9803SDavid Howells call->reply2 = vnode; 864260a9803SDavid Howells call->service_id = FS_SERVICE; 865260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 866260a9803SDavid Howells 867260a9803SDavid Howells /* marshall the parameters */ 868260a9803SDavid Howells bp = call->request; 869260a9803SDavid Howells *bp++ = htonl(FSLINK); 870260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 871260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 872260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 873260a9803SDavid Howells *bp++ = htonl(namesz); 874260a9803SDavid Howells memcpy(bp, name, namesz); 875260a9803SDavid Howells bp = (void *) bp + namesz; 876260a9803SDavid Howells if (padsz > 0) { 877260a9803SDavid Howells memset(bp, 0, padsz); 878260a9803SDavid Howells bp = (void *) bp + padsz; 879260a9803SDavid Howells } 880260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 881260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 882260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 883260a9803SDavid Howells 884260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 885260a9803SDavid Howells } 886260a9803SDavid Howells 887260a9803SDavid Howells /* 888260a9803SDavid Howells * deliver reply data to an FS.Symlink 889260a9803SDavid Howells */ 890260a9803SDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call, 891260a9803SDavid Howells struct sk_buff *skb, bool last) 892260a9803SDavid Howells { 893260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 894260a9803SDavid Howells const __be32 *bp; 895260a9803SDavid Howells 896260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 897260a9803SDavid Howells 898260a9803SDavid Howells afs_transfer_reply(call, skb); 899260a9803SDavid Howells if (!last) 900260a9803SDavid Howells return 0; 901260a9803SDavid Howells 902260a9803SDavid Howells if (call->reply_size != call->reply_max) 903260a9803SDavid Howells return -EBADMSG; 904260a9803SDavid Howells 905260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 906260a9803SDavid Howells bp = call->buffer; 907260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 90831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 90931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 910260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 911260a9803SDavid Howells 912260a9803SDavid Howells _leave(" = 0 [done]"); 913260a9803SDavid Howells return 0; 914260a9803SDavid Howells } 915260a9803SDavid Howells 916260a9803SDavid Howells /* 917260a9803SDavid Howells * FS.Symlink operation type 918260a9803SDavid Howells */ 919260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 920260a9803SDavid Howells .name = "FS.Symlink", 921260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 922260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 923260a9803SDavid Howells .destructor = afs_flat_call_destructor, 924260a9803SDavid Howells }; 925260a9803SDavid Howells 926260a9803SDavid Howells /* 927260a9803SDavid Howells * create a symbolic link 928260a9803SDavid Howells */ 929260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server, 930260a9803SDavid Howells struct key *key, 931260a9803SDavid Howells struct afs_vnode *vnode, 932260a9803SDavid Howells const char *name, 933260a9803SDavid Howells const char *contents, 934260a9803SDavid Howells struct afs_fid *newfid, 935260a9803SDavid Howells struct afs_file_status *newstatus, 936260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 937260a9803SDavid Howells { 938260a9803SDavid Howells struct afs_call *call; 939260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 940260a9803SDavid Howells __be32 *bp; 941260a9803SDavid Howells 942260a9803SDavid Howells _enter(""); 943260a9803SDavid Howells 944260a9803SDavid Howells namesz = strlen(name); 945260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 946260a9803SDavid Howells 947260a9803SDavid Howells c_namesz = strlen(contents); 948260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 949260a9803SDavid Howells 950260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 951260a9803SDavid Howells 952260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, 953260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 954260a9803SDavid Howells if (!call) 955260a9803SDavid Howells return -ENOMEM; 956260a9803SDavid Howells 957260a9803SDavid Howells call->key = key; 958260a9803SDavid Howells call->reply = vnode; 959260a9803SDavid Howells call->reply2 = newfid; 960260a9803SDavid Howells call->reply3 = newstatus; 961260a9803SDavid Howells call->service_id = FS_SERVICE; 962260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 963260a9803SDavid Howells 964260a9803SDavid Howells /* marshall the parameters */ 965260a9803SDavid Howells bp = call->request; 966260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 967260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 968260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 969260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 970260a9803SDavid Howells *bp++ = htonl(namesz); 971260a9803SDavid Howells memcpy(bp, name, namesz); 972260a9803SDavid Howells bp = (void *) bp + namesz; 973260a9803SDavid Howells if (padsz > 0) { 974260a9803SDavid Howells memset(bp, 0, padsz); 975260a9803SDavid Howells bp = (void *) bp + padsz; 976260a9803SDavid Howells } 977260a9803SDavid Howells *bp++ = htonl(c_namesz); 978260a9803SDavid Howells memcpy(bp, contents, c_namesz); 979260a9803SDavid Howells bp = (void *) bp + c_namesz; 980260a9803SDavid Howells if (c_padsz > 0) { 981260a9803SDavid Howells memset(bp, 0, c_padsz); 982260a9803SDavid Howells bp = (void *) bp + c_padsz; 983260a9803SDavid Howells } 984260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 985260a9803SDavid Howells *bp++ = 0; /* mtime */ 986260a9803SDavid Howells *bp++ = 0; /* owner */ 987260a9803SDavid Howells *bp++ = 0; /* group */ 988260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 989260a9803SDavid Howells *bp++ = 0; /* segment size */ 990260a9803SDavid Howells 991260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 992260a9803SDavid Howells } 993260a9803SDavid Howells 994260a9803SDavid Howells /* 995260a9803SDavid Howells * deliver reply data to an FS.Rename 996260a9803SDavid Howells */ 997260a9803SDavid Howells static int afs_deliver_fs_rename(struct afs_call *call, 998260a9803SDavid Howells struct sk_buff *skb, bool last) 999260a9803SDavid Howells { 1000260a9803SDavid Howells struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; 1001260a9803SDavid Howells const __be32 *bp; 1002260a9803SDavid Howells 1003260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 1004260a9803SDavid Howells 1005260a9803SDavid Howells afs_transfer_reply(call, skb); 1006260a9803SDavid Howells if (!last) 1007260a9803SDavid Howells return 0; 1008260a9803SDavid Howells 1009260a9803SDavid Howells if (call->reply_size != call->reply_max) 1010260a9803SDavid Howells return -EBADMSG; 1011260a9803SDavid Howells 1012260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 1013260a9803SDavid Howells bp = call->buffer; 101431143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); 1015260a9803SDavid Howells if (new_dvnode != orig_dvnode) 101631143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, 101731143d5dSDavid Howells NULL); 1018260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1019260a9803SDavid Howells 1020260a9803SDavid Howells _leave(" = 0 [done]"); 1021260a9803SDavid Howells return 0; 1022260a9803SDavid Howells } 1023260a9803SDavid Howells 1024260a9803SDavid Howells /* 1025260a9803SDavid Howells * FS.Rename operation type 1026260a9803SDavid Howells */ 1027260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 1028260a9803SDavid Howells .name = "FS.Rename", 1029260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 1030260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 1031260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1032260a9803SDavid Howells }; 1033260a9803SDavid Howells 1034260a9803SDavid Howells /* 1035260a9803SDavid Howells * create a symbolic link 1036260a9803SDavid Howells */ 1037260a9803SDavid Howells int afs_fs_rename(struct afs_server *server, 1038260a9803SDavid Howells struct key *key, 1039260a9803SDavid Howells struct afs_vnode *orig_dvnode, 1040260a9803SDavid Howells const char *orig_name, 1041260a9803SDavid Howells struct afs_vnode *new_dvnode, 1042260a9803SDavid Howells const char *new_name, 1043260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 1044260a9803SDavid Howells { 1045260a9803SDavid Howells struct afs_call *call; 1046260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 1047260a9803SDavid Howells __be32 *bp; 1048260a9803SDavid Howells 1049260a9803SDavid Howells _enter(""); 1050260a9803SDavid Howells 1051260a9803SDavid Howells o_namesz = strlen(orig_name); 1052260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 1053260a9803SDavid Howells 1054260a9803SDavid Howells n_namesz = strlen(new_name); 1055260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 1056260a9803SDavid Howells 1057260a9803SDavid Howells reqsz = (4 * 4) + 1058260a9803SDavid Howells 4 + o_namesz + o_padsz + 1059260a9803SDavid Howells (3 * 4) + 1060260a9803SDavid Howells 4 + n_namesz + n_padsz; 1061260a9803SDavid Howells 1062260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1063260a9803SDavid Howells if (!call) 1064260a9803SDavid Howells return -ENOMEM; 1065260a9803SDavid Howells 1066260a9803SDavid Howells call->key = key; 1067260a9803SDavid Howells call->reply = orig_dvnode; 1068260a9803SDavid Howells call->reply2 = new_dvnode; 1069260a9803SDavid Howells call->service_id = FS_SERVICE; 1070260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 1071260a9803SDavid Howells 1072260a9803SDavid Howells /* marshall the parameters */ 1073260a9803SDavid Howells bp = call->request; 1074260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1075260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 1076260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 1077260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 1078260a9803SDavid Howells *bp++ = htonl(o_namesz); 1079260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 1080260a9803SDavid Howells bp = (void *) bp + o_namesz; 1081260a9803SDavid Howells if (o_padsz > 0) { 1082260a9803SDavid Howells memset(bp, 0, o_padsz); 1083260a9803SDavid Howells bp = (void *) bp + o_padsz; 1084260a9803SDavid Howells } 1085260a9803SDavid Howells 1086260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 1087260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 1088260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 1089260a9803SDavid Howells *bp++ = htonl(n_namesz); 1090260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 1091260a9803SDavid Howells bp = (void *) bp + n_namesz; 1092260a9803SDavid Howells if (n_padsz > 0) { 1093260a9803SDavid Howells memset(bp, 0, n_padsz); 1094260a9803SDavid Howells bp = (void *) bp + n_padsz; 1095260a9803SDavid Howells } 1096260a9803SDavid Howells 1097260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1098260a9803SDavid Howells } 109931143d5dSDavid Howells 110031143d5dSDavid Howells /* 110131143d5dSDavid Howells * deliver reply data to an FS.StoreData 110231143d5dSDavid Howells */ 110331143d5dSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call, 110431143d5dSDavid Howells struct sk_buff *skb, bool last) 110531143d5dSDavid Howells { 110631143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 110731143d5dSDavid Howells const __be32 *bp; 110831143d5dSDavid Howells 110931143d5dSDavid Howells _enter(",,%u", last); 111031143d5dSDavid Howells 111131143d5dSDavid Howells afs_transfer_reply(call, skb); 111231143d5dSDavid Howells if (!last) { 111331143d5dSDavid Howells _leave(" = 0 [more]"); 111431143d5dSDavid Howells return 0; 111531143d5dSDavid Howells } 111631143d5dSDavid Howells 111731143d5dSDavid Howells if (call->reply_size != call->reply_max) { 111831143d5dSDavid Howells _leave(" = -EBADMSG [%u != %u]", 111931143d5dSDavid Howells call->reply_size, call->reply_max); 112031143d5dSDavid Howells return -EBADMSG; 112131143d5dSDavid Howells } 112231143d5dSDavid Howells 112331143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 112431143d5dSDavid Howells bp = call->buffer; 112531143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, 112631143d5dSDavid Howells &call->store_version); 112731143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 112831143d5dSDavid Howells 112931143d5dSDavid Howells afs_pages_written_back(vnode, call); 113031143d5dSDavid Howells 113131143d5dSDavid Howells _leave(" = 0 [done]"); 113231143d5dSDavid Howells return 0; 113331143d5dSDavid Howells } 113431143d5dSDavid Howells 113531143d5dSDavid Howells /* 113631143d5dSDavid Howells * FS.StoreData operation type 113731143d5dSDavid Howells */ 113831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 113931143d5dSDavid Howells .name = "FS.StoreData", 114031143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 114131143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 114231143d5dSDavid Howells .destructor = afs_flat_call_destructor, 114331143d5dSDavid Howells }; 114431143d5dSDavid Howells 1145b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1146b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1147b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1148b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1149b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1150b9b1f8d5SDavid Howells }; 1151b9b1f8d5SDavid Howells 1152b9b1f8d5SDavid Howells /* 1153b9b1f8d5SDavid Howells * store a set of pages to a very large file 1154b9b1f8d5SDavid Howells */ 1155b9b1f8d5SDavid Howells static int afs_fs_store_data64(struct afs_server *server, 1156b9b1f8d5SDavid Howells struct afs_writeback *wb, 1157b9b1f8d5SDavid Howells pgoff_t first, pgoff_t last, 1158b9b1f8d5SDavid Howells unsigned offset, unsigned to, 1159b9b1f8d5SDavid Howells loff_t size, loff_t pos, loff_t i_size, 1160b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 1161b9b1f8d5SDavid Howells { 1162b9b1f8d5SDavid Howells struct afs_vnode *vnode = wb->vnode; 1163b9b1f8d5SDavid Howells struct afs_call *call; 1164b9b1f8d5SDavid Howells __be32 *bp; 1165b9b1f8d5SDavid Howells 1166b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1167b9b1f8d5SDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 1168b9b1f8d5SDavid Howells 1169b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData64, 1170b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1171b9b1f8d5SDavid Howells (21 + 6) * 4); 1172b9b1f8d5SDavid Howells if (!call) 1173b9b1f8d5SDavid Howells return -ENOMEM; 1174b9b1f8d5SDavid Howells 1175b9b1f8d5SDavid Howells call->wb = wb; 1176b9b1f8d5SDavid Howells call->key = wb->key; 1177b9b1f8d5SDavid Howells call->reply = vnode; 1178b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1179b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1180b9b1f8d5SDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 1181b9b1f8d5SDavid Howells call->first = first; 1182b9b1f8d5SDavid Howells call->last = last; 1183b9b1f8d5SDavid Howells call->first_offset = offset; 1184b9b1f8d5SDavid Howells call->last_to = to; 1185b9b1f8d5SDavid Howells call->send_pages = true; 1186b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1187b9b1f8d5SDavid Howells 1188b9b1f8d5SDavid Howells /* marshall the parameters */ 1189b9b1f8d5SDavid Howells bp = call->request; 1190b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1191b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1192b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1193b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1194b9b1f8d5SDavid Howells 1195b9b1f8d5SDavid Howells *bp++ = 0; /* mask */ 1196b9b1f8d5SDavid Howells *bp++ = 0; /* mtime */ 1197b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1198b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1199b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1200b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1201b9b1f8d5SDavid Howells 1202b9b1f8d5SDavid Howells *bp++ = htonl(pos >> 32); 1203b9b1f8d5SDavid Howells *bp++ = htonl((u32) pos); 1204b9b1f8d5SDavid Howells *bp++ = htonl(size >> 32); 1205b9b1f8d5SDavid Howells *bp++ = htonl((u32) size); 1206b9b1f8d5SDavid Howells *bp++ = htonl(i_size >> 32); 1207b9b1f8d5SDavid Howells *bp++ = htonl((u32) i_size); 1208b9b1f8d5SDavid Howells 1209b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1210b9b1f8d5SDavid Howells } 1211b9b1f8d5SDavid Howells 121231143d5dSDavid Howells /* 121331143d5dSDavid Howells * store a set of pages 121431143d5dSDavid Howells */ 121531143d5dSDavid Howells int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, 121631143d5dSDavid Howells pgoff_t first, pgoff_t last, 121731143d5dSDavid Howells unsigned offset, unsigned to, 121831143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 121931143d5dSDavid Howells { 122031143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 122131143d5dSDavid Howells struct afs_call *call; 122231143d5dSDavid Howells loff_t size, pos, i_size; 122331143d5dSDavid Howells __be32 *bp; 122431143d5dSDavid Howells 122531143d5dSDavid Howells _enter(",%x,{%x:%u},,", 122631143d5dSDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 122731143d5dSDavid Howells 122831143d5dSDavid Howells size = to - offset; 122931143d5dSDavid Howells if (first != last) 123031143d5dSDavid Howells size += (loff_t)(last - first) << PAGE_SHIFT; 123131143d5dSDavid Howells pos = (loff_t)first << PAGE_SHIFT; 123231143d5dSDavid Howells pos += offset; 123331143d5dSDavid Howells 123431143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 123531143d5dSDavid Howells if (pos + size > i_size) 123631143d5dSDavid Howells i_size = size + pos; 123731143d5dSDavid Howells 123831143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 123931143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 124031143d5dSDavid Howells (unsigned long long) i_size); 124131143d5dSDavid Howells 1242b9b1f8d5SDavid Howells if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) 1243b9b1f8d5SDavid Howells return afs_fs_store_data64(server, wb, first, last, offset, to, 1244b9b1f8d5SDavid Howells size, pos, i_size, wait_mode); 124531143d5dSDavid Howells 124631143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData, 124731143d5dSDavid Howells (4 + 6 + 3) * 4, 124831143d5dSDavid Howells (21 + 6) * 4); 124931143d5dSDavid Howells if (!call) 125031143d5dSDavid Howells return -ENOMEM; 125131143d5dSDavid Howells 125231143d5dSDavid Howells call->wb = wb; 125331143d5dSDavid Howells call->key = wb->key; 125431143d5dSDavid Howells call->reply = vnode; 125531143d5dSDavid Howells call->service_id = FS_SERVICE; 125631143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 125731143d5dSDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 125831143d5dSDavid Howells call->first = first; 125931143d5dSDavid Howells call->last = last; 126031143d5dSDavid Howells call->first_offset = offset; 126131143d5dSDavid Howells call->last_to = to; 126231143d5dSDavid Howells call->send_pages = true; 126331143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 126431143d5dSDavid Howells 126531143d5dSDavid Howells /* marshall the parameters */ 126631143d5dSDavid Howells bp = call->request; 126731143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 126831143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 126931143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 127031143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 127131143d5dSDavid Howells 127231143d5dSDavid Howells *bp++ = 0; /* mask */ 127331143d5dSDavid Howells *bp++ = 0; /* mtime */ 127431143d5dSDavid Howells *bp++ = 0; /* owner */ 127531143d5dSDavid Howells *bp++ = 0; /* group */ 127631143d5dSDavid Howells *bp++ = 0; /* unix mode */ 127731143d5dSDavid Howells *bp++ = 0; /* segment size */ 127831143d5dSDavid Howells 127931143d5dSDavid Howells *bp++ = htonl(pos); 128031143d5dSDavid Howells *bp++ = htonl(size); 128131143d5dSDavid Howells *bp++ = htonl(i_size); 128231143d5dSDavid Howells 128331143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 128431143d5dSDavid Howells } 128531143d5dSDavid Howells 128631143d5dSDavid Howells /* 128731143d5dSDavid Howells * deliver reply data to an FS.StoreStatus 128831143d5dSDavid Howells */ 128931143d5dSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call, 129031143d5dSDavid Howells struct sk_buff *skb, bool last) 129131143d5dSDavid Howells { 129231143d5dSDavid Howells afs_dataversion_t *store_version; 129331143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 129431143d5dSDavid Howells const __be32 *bp; 129531143d5dSDavid Howells 129631143d5dSDavid Howells _enter(",,%u", last); 129731143d5dSDavid Howells 129831143d5dSDavid Howells afs_transfer_reply(call, skb); 129931143d5dSDavid Howells if (!last) { 130031143d5dSDavid Howells _leave(" = 0 [more]"); 130131143d5dSDavid Howells return 0; 130231143d5dSDavid Howells } 130331143d5dSDavid Howells 130431143d5dSDavid Howells if (call->reply_size != call->reply_max) { 130531143d5dSDavid Howells _leave(" = -EBADMSG [%u != %u]", 130631143d5dSDavid Howells call->reply_size, call->reply_max); 130731143d5dSDavid Howells return -EBADMSG; 130831143d5dSDavid Howells } 130931143d5dSDavid Howells 131031143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 131131143d5dSDavid Howells store_version = NULL; 131231143d5dSDavid Howells if (call->operation_ID == FSSTOREDATA) 131331143d5dSDavid Howells store_version = &call->store_version; 131431143d5dSDavid Howells 131531143d5dSDavid Howells bp = call->buffer; 131631143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); 131731143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 131831143d5dSDavid Howells 131931143d5dSDavid Howells _leave(" = 0 [done]"); 132031143d5dSDavid Howells return 0; 132131143d5dSDavid Howells } 132231143d5dSDavid Howells 132331143d5dSDavid Howells /* 132431143d5dSDavid Howells * FS.StoreStatus operation type 132531143d5dSDavid Howells */ 132631143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 132731143d5dSDavid Howells .name = "FS.StoreStatus", 132831143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 132931143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 133031143d5dSDavid Howells .destructor = afs_flat_call_destructor, 133131143d5dSDavid Howells }; 133231143d5dSDavid Howells 133331143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 133431143d5dSDavid Howells .name = "FS.StoreData", 133531143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 133631143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 133731143d5dSDavid Howells .destructor = afs_flat_call_destructor, 133831143d5dSDavid Howells }; 133931143d5dSDavid Howells 1340b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1341b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1342b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_status, 1343b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1344b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1345b9b1f8d5SDavid Howells }; 1346b9b1f8d5SDavid Howells 1347b9b1f8d5SDavid Howells /* 1348b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1349b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1350b9b1f8d5SDavid Howells */ 1351b9b1f8d5SDavid Howells static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, 1352b9b1f8d5SDavid Howells struct afs_vnode *vnode, struct iattr *attr, 1353b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 1354b9b1f8d5SDavid Howells { 1355b9b1f8d5SDavid Howells struct afs_call *call; 1356b9b1f8d5SDavid Howells __be32 *bp; 1357b9b1f8d5SDavid Howells 1358b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1359b9b1f8d5SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 1360b9b1f8d5SDavid Howells 1361b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1362b9b1f8d5SDavid Howells 1363b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status, 1364b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1365b9b1f8d5SDavid Howells (21 + 6) * 4); 1366b9b1f8d5SDavid Howells if (!call) 1367b9b1f8d5SDavid Howells return -ENOMEM; 1368b9b1f8d5SDavid Howells 1369b9b1f8d5SDavid Howells call->key = key; 1370b9b1f8d5SDavid Howells call->reply = vnode; 1371b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1372b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1373b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1374b9b1f8d5SDavid Howells call->operation_ID = FSSTOREDATA; 1375b9b1f8d5SDavid Howells 1376b9b1f8d5SDavid Howells /* marshall the parameters */ 1377b9b1f8d5SDavid Howells bp = call->request; 1378b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1379b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1380b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1381b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1382b9b1f8d5SDavid Howells 1383b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1384b9b1f8d5SDavid Howells 1385b9b1f8d5SDavid Howells *bp++ = 0; /* position of start of write */ 1386b9b1f8d5SDavid Howells *bp++ = 0; 1387b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1388b9b1f8d5SDavid Howells *bp++ = 0; 1389b9b1f8d5SDavid Howells *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1390b9b1f8d5SDavid Howells *bp++ = htonl((u32) attr->ia_size); 1391b9b1f8d5SDavid Howells 1392b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1393b9b1f8d5SDavid Howells } 1394b9b1f8d5SDavid Howells 139531143d5dSDavid Howells /* 139631143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 139731143d5dSDavid Howells * so as to alter the file size also 139831143d5dSDavid Howells */ 139931143d5dSDavid Howells static int afs_fs_setattr_size(struct afs_server *server, struct key *key, 140031143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 140131143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 140231143d5dSDavid Howells { 140331143d5dSDavid Howells struct afs_call *call; 140431143d5dSDavid Howells __be32 *bp; 140531143d5dSDavid Howells 140631143d5dSDavid Howells _enter(",%x,{%x:%u},,", 140731143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 140831143d5dSDavid Howells 140931143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1410b9b1f8d5SDavid Howells if (attr->ia_size >> 32) 1411b9b1f8d5SDavid Howells return afs_fs_setattr_size64(server, key, vnode, attr, 1412b9b1f8d5SDavid Howells wait_mode); 141331143d5dSDavid Howells 141431143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, 141531143d5dSDavid Howells (4 + 6 + 3) * 4, 141631143d5dSDavid Howells (21 + 6) * 4); 141731143d5dSDavid Howells if (!call) 141831143d5dSDavid Howells return -ENOMEM; 141931143d5dSDavid Howells 142031143d5dSDavid Howells call->key = key; 142131143d5dSDavid Howells call->reply = vnode; 142231143d5dSDavid Howells call->service_id = FS_SERVICE; 142331143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 142431143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 142531143d5dSDavid Howells call->operation_ID = FSSTOREDATA; 142631143d5dSDavid Howells 142731143d5dSDavid Howells /* marshall the parameters */ 142831143d5dSDavid Howells bp = call->request; 142931143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 143031143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 143131143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 143231143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 143331143d5dSDavid Howells 143431143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 143531143d5dSDavid Howells 143631143d5dSDavid Howells *bp++ = 0; /* position of start of write */ 143731143d5dSDavid Howells *bp++ = 0; /* size of write */ 143831143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 143931143d5dSDavid Howells 144031143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 144131143d5dSDavid Howells } 144231143d5dSDavid Howells 144331143d5dSDavid Howells /* 144431143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 144531143d5dSDavid Howells * size, and FS.StoreStatus otherwise 144631143d5dSDavid Howells */ 144731143d5dSDavid Howells int afs_fs_setattr(struct afs_server *server, struct key *key, 144831143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 144931143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 145031143d5dSDavid Howells { 145131143d5dSDavid Howells struct afs_call *call; 145231143d5dSDavid Howells __be32 *bp; 145331143d5dSDavid Howells 145431143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 145531143d5dSDavid Howells return afs_fs_setattr_size(server, key, vnode, attr, 145631143d5dSDavid Howells wait_mode); 145731143d5dSDavid Howells 145831143d5dSDavid Howells _enter(",%x,{%x:%u},,", 145931143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 146031143d5dSDavid Howells 146131143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreStatus, 146231143d5dSDavid Howells (4 + 6) * 4, 146331143d5dSDavid Howells (21 + 6) * 4); 146431143d5dSDavid Howells if (!call) 146531143d5dSDavid Howells return -ENOMEM; 146631143d5dSDavid Howells 146731143d5dSDavid Howells call->key = key; 146831143d5dSDavid Howells call->reply = vnode; 146931143d5dSDavid Howells call->service_id = FS_SERVICE; 147031143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 147131143d5dSDavid Howells call->operation_ID = FSSTORESTATUS; 147231143d5dSDavid Howells 147331143d5dSDavid Howells /* marshall the parameters */ 147431143d5dSDavid Howells bp = call->request; 147531143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 147631143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 147731143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 147831143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 147931143d5dSDavid Howells 148031143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 148131143d5dSDavid Howells 148231143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 148331143d5dSDavid Howells } 148445222b9eSDavid Howells 148545222b9eSDavid Howells /* 148645222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 148745222b9eSDavid Howells */ 148845222b9eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call, 148945222b9eSDavid Howells struct sk_buff *skb, bool last) 149045222b9eSDavid Howells { 149145222b9eSDavid Howells const __be32 *bp; 149245222b9eSDavid Howells char *p; 149345222b9eSDavid Howells int ret; 149445222b9eSDavid Howells 149545222b9eSDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 149645222b9eSDavid Howells 149745222b9eSDavid Howells switch (call->unmarshall) { 149845222b9eSDavid Howells case 0: 149945222b9eSDavid Howells call->offset = 0; 150045222b9eSDavid Howells call->unmarshall++; 150145222b9eSDavid Howells 150245222b9eSDavid Howells /* extract the returned status record */ 150345222b9eSDavid Howells case 1: 150445222b9eSDavid Howells _debug("extract status"); 150545222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 150645222b9eSDavid Howells 12 * 4); 150745222b9eSDavid Howells switch (ret) { 150845222b9eSDavid Howells case 0: break; 150945222b9eSDavid Howells case -EAGAIN: return 0; 151045222b9eSDavid Howells default: return ret; 151145222b9eSDavid Howells } 151245222b9eSDavid Howells 151345222b9eSDavid Howells bp = call->buffer; 151445222b9eSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); 151545222b9eSDavid Howells call->offset = 0; 151645222b9eSDavid Howells call->unmarshall++; 151745222b9eSDavid Howells 151845222b9eSDavid Howells /* extract the volume name length */ 151945222b9eSDavid Howells case 2: 152045222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 152145222b9eSDavid Howells switch (ret) { 152245222b9eSDavid Howells case 0: break; 152345222b9eSDavid Howells case -EAGAIN: return 0; 152445222b9eSDavid Howells default: return ret; 152545222b9eSDavid Howells } 152645222b9eSDavid Howells 152745222b9eSDavid Howells call->count = ntohl(call->tmp); 152845222b9eSDavid Howells _debug("volname length: %u", call->count); 152945222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 153045222b9eSDavid Howells return -EBADMSG; 153145222b9eSDavid Howells call->offset = 0; 153245222b9eSDavid Howells call->unmarshall++; 153345222b9eSDavid Howells 153445222b9eSDavid Howells /* extract the volume name */ 153545222b9eSDavid Howells case 3: 153645222b9eSDavid Howells _debug("extract volname"); 153745222b9eSDavid Howells if (call->count > 0) { 153845222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 153945222b9eSDavid Howells call->count); 154045222b9eSDavid Howells switch (ret) { 154145222b9eSDavid Howells case 0: break; 154245222b9eSDavid Howells case -EAGAIN: return 0; 154345222b9eSDavid Howells default: return ret; 154445222b9eSDavid Howells } 154545222b9eSDavid Howells } 154645222b9eSDavid Howells 154745222b9eSDavid Howells p = call->reply3; 154845222b9eSDavid Howells p[call->count] = 0; 154945222b9eSDavid Howells _debug("volname '%s'", p); 155045222b9eSDavid Howells 155145222b9eSDavid Howells call->offset = 0; 155245222b9eSDavid Howells call->unmarshall++; 155345222b9eSDavid Howells 155445222b9eSDavid Howells /* extract the volume name padding */ 155545222b9eSDavid Howells if ((call->count & 3) == 0) { 155645222b9eSDavid Howells call->unmarshall++; 155745222b9eSDavid Howells goto no_volname_padding; 155845222b9eSDavid Howells } 155945222b9eSDavid Howells call->count = 4 - (call->count & 3); 156045222b9eSDavid Howells 156145222b9eSDavid Howells case 4: 156245222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 156345222b9eSDavid Howells call->count); 156445222b9eSDavid Howells switch (ret) { 156545222b9eSDavid Howells case 0: break; 156645222b9eSDavid Howells case -EAGAIN: return 0; 156745222b9eSDavid Howells default: return ret; 156845222b9eSDavid Howells } 156945222b9eSDavid Howells 157045222b9eSDavid Howells call->offset = 0; 157145222b9eSDavid Howells call->unmarshall++; 157245222b9eSDavid Howells no_volname_padding: 157345222b9eSDavid Howells 157445222b9eSDavid Howells /* extract the offline message length */ 157545222b9eSDavid Howells case 5: 157645222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 157745222b9eSDavid Howells switch (ret) { 157845222b9eSDavid Howells case 0: break; 157945222b9eSDavid Howells case -EAGAIN: return 0; 158045222b9eSDavid Howells default: return ret; 158145222b9eSDavid Howells } 158245222b9eSDavid Howells 158345222b9eSDavid Howells call->count = ntohl(call->tmp); 158445222b9eSDavid Howells _debug("offline msg length: %u", call->count); 158545222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 158645222b9eSDavid Howells return -EBADMSG; 158745222b9eSDavid Howells call->offset = 0; 158845222b9eSDavid Howells call->unmarshall++; 158945222b9eSDavid Howells 159045222b9eSDavid Howells /* extract the offline message */ 159145222b9eSDavid Howells case 6: 159245222b9eSDavid Howells _debug("extract offline"); 159345222b9eSDavid Howells if (call->count > 0) { 159445222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 159545222b9eSDavid Howells call->count); 159645222b9eSDavid Howells switch (ret) { 159745222b9eSDavid Howells case 0: break; 159845222b9eSDavid Howells case -EAGAIN: return 0; 159945222b9eSDavid Howells default: return ret; 160045222b9eSDavid Howells } 160145222b9eSDavid Howells } 160245222b9eSDavid Howells 160345222b9eSDavid Howells p = call->reply3; 160445222b9eSDavid Howells p[call->count] = 0; 160545222b9eSDavid Howells _debug("offline '%s'", p); 160645222b9eSDavid Howells 160745222b9eSDavid Howells call->offset = 0; 160845222b9eSDavid Howells call->unmarshall++; 160945222b9eSDavid Howells 161045222b9eSDavid Howells /* extract the offline message padding */ 161145222b9eSDavid Howells if ((call->count & 3) == 0) { 161245222b9eSDavid Howells call->unmarshall++; 161345222b9eSDavid Howells goto no_offline_padding; 161445222b9eSDavid Howells } 161545222b9eSDavid Howells call->count = 4 - (call->count & 3); 161645222b9eSDavid Howells 161745222b9eSDavid Howells case 7: 161845222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 161945222b9eSDavid Howells call->count); 162045222b9eSDavid Howells switch (ret) { 162145222b9eSDavid Howells case 0: break; 162245222b9eSDavid Howells case -EAGAIN: return 0; 162345222b9eSDavid Howells default: return ret; 162445222b9eSDavid Howells } 162545222b9eSDavid Howells 162645222b9eSDavid Howells call->offset = 0; 162745222b9eSDavid Howells call->unmarshall++; 162845222b9eSDavid Howells no_offline_padding: 162945222b9eSDavid Howells 163045222b9eSDavid Howells /* extract the message of the day length */ 163145222b9eSDavid Howells case 8: 163245222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 163345222b9eSDavid Howells switch (ret) { 163445222b9eSDavid Howells case 0: break; 163545222b9eSDavid Howells case -EAGAIN: return 0; 163645222b9eSDavid Howells default: return ret; 163745222b9eSDavid Howells } 163845222b9eSDavid Howells 163945222b9eSDavid Howells call->count = ntohl(call->tmp); 164045222b9eSDavid Howells _debug("motd length: %u", call->count); 164145222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 164245222b9eSDavid Howells return -EBADMSG; 164345222b9eSDavid Howells call->offset = 0; 164445222b9eSDavid Howells call->unmarshall++; 164545222b9eSDavid Howells 164645222b9eSDavid Howells /* extract the message of the day */ 164745222b9eSDavid Howells case 9: 164845222b9eSDavid Howells _debug("extract motd"); 164945222b9eSDavid Howells if (call->count > 0) { 165045222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 165145222b9eSDavid Howells call->count); 165245222b9eSDavid Howells switch (ret) { 165345222b9eSDavid Howells case 0: break; 165445222b9eSDavid Howells case -EAGAIN: return 0; 165545222b9eSDavid Howells default: return ret; 165645222b9eSDavid Howells } 165745222b9eSDavid Howells } 165845222b9eSDavid Howells 165945222b9eSDavid Howells p = call->reply3; 166045222b9eSDavid Howells p[call->count] = 0; 166145222b9eSDavid Howells _debug("motd '%s'", p); 166245222b9eSDavid Howells 166345222b9eSDavid Howells call->offset = 0; 166445222b9eSDavid Howells call->unmarshall++; 166545222b9eSDavid Howells 166645222b9eSDavid Howells /* extract the message of the day padding */ 166745222b9eSDavid Howells if ((call->count & 3) == 0) { 166845222b9eSDavid Howells call->unmarshall++; 166945222b9eSDavid Howells goto no_motd_padding; 167045222b9eSDavid Howells } 167145222b9eSDavid Howells call->count = 4 - (call->count & 3); 167245222b9eSDavid Howells 167345222b9eSDavid Howells case 10: 167445222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 167545222b9eSDavid Howells call->count); 167645222b9eSDavid Howells switch (ret) { 167745222b9eSDavid Howells case 0: break; 167845222b9eSDavid Howells case -EAGAIN: return 0; 167945222b9eSDavid Howells default: return ret; 168045222b9eSDavid Howells } 168145222b9eSDavid Howells 168245222b9eSDavid Howells call->offset = 0; 168345222b9eSDavid Howells call->unmarshall++; 168445222b9eSDavid Howells no_motd_padding: 168545222b9eSDavid Howells 168645222b9eSDavid Howells case 11: 168745222b9eSDavid Howells _debug("trailer %d", skb->len); 168845222b9eSDavid Howells if (skb->len != 0) 168945222b9eSDavid Howells return -EBADMSG; 169045222b9eSDavid Howells break; 169145222b9eSDavid Howells } 169245222b9eSDavid Howells 169345222b9eSDavid Howells if (!last) 169445222b9eSDavid Howells return 0; 169545222b9eSDavid Howells 169645222b9eSDavid Howells _leave(" = 0 [done]"); 169745222b9eSDavid Howells return 0; 169845222b9eSDavid Howells } 169945222b9eSDavid Howells 170045222b9eSDavid Howells /* 170145222b9eSDavid Howells * destroy an FS.GetVolumeStatus call 170245222b9eSDavid Howells */ 170345222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call) 170445222b9eSDavid Howells { 170545222b9eSDavid Howells kfree(call->reply3); 170645222b9eSDavid Howells call->reply3 = NULL; 170745222b9eSDavid Howells afs_flat_call_destructor(call); 170845222b9eSDavid Howells } 170945222b9eSDavid Howells 171045222b9eSDavid Howells /* 171145222b9eSDavid Howells * FS.GetVolumeStatus operation type 171245222b9eSDavid Howells */ 171345222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 171445222b9eSDavid Howells .name = "FS.GetVolumeStatus", 171545222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 171645222b9eSDavid Howells .abort_to_error = afs_abort_to_error, 171745222b9eSDavid Howells .destructor = afs_get_volume_status_call_destructor, 171845222b9eSDavid Howells }; 171945222b9eSDavid Howells 172045222b9eSDavid Howells /* 172145222b9eSDavid Howells * fetch the status of a volume 172245222b9eSDavid Howells */ 172345222b9eSDavid Howells int afs_fs_get_volume_status(struct afs_server *server, 172445222b9eSDavid Howells struct key *key, 172545222b9eSDavid Howells struct afs_vnode *vnode, 172645222b9eSDavid Howells struct afs_volume_status *vs, 172745222b9eSDavid Howells const struct afs_wait_mode *wait_mode) 172845222b9eSDavid Howells { 172945222b9eSDavid Howells struct afs_call *call; 173045222b9eSDavid Howells __be32 *bp; 173145222b9eSDavid Howells void *tmpbuf; 173245222b9eSDavid Howells 173345222b9eSDavid Howells _enter(""); 173445222b9eSDavid Howells 173545222b9eSDavid Howells tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); 173645222b9eSDavid Howells if (!tmpbuf) 173745222b9eSDavid Howells return -ENOMEM; 173845222b9eSDavid Howells 173945222b9eSDavid Howells call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); 174045222b9eSDavid Howells if (!call) { 174145222b9eSDavid Howells kfree(tmpbuf); 174245222b9eSDavid Howells return -ENOMEM; 174345222b9eSDavid Howells } 174445222b9eSDavid Howells 174545222b9eSDavid Howells call->key = key; 174645222b9eSDavid Howells call->reply = vnode; 174745222b9eSDavid Howells call->reply2 = vs; 174845222b9eSDavid Howells call->reply3 = tmpbuf; 174945222b9eSDavid Howells call->service_id = FS_SERVICE; 175045222b9eSDavid Howells call->port = htons(AFS_FS_PORT); 175145222b9eSDavid Howells 175245222b9eSDavid Howells /* marshall the parameters */ 175345222b9eSDavid Howells bp = call->request; 175445222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 175545222b9eSDavid Howells bp[1] = htonl(vnode->fid.vid); 175645222b9eSDavid Howells 175745222b9eSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 175845222b9eSDavid Howells } 1759e8d6c554SDavid Howells 1760e8d6c554SDavid Howells /* 1761e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1762e8d6c554SDavid Howells */ 1763e8d6c554SDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call, 1764e8d6c554SDavid Howells struct sk_buff *skb, bool last) 1765e8d6c554SDavid Howells { 1766e8d6c554SDavid Howells const __be32 *bp; 1767e8d6c554SDavid Howells 1768e8d6c554SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 1769e8d6c554SDavid Howells 1770e8d6c554SDavid Howells afs_transfer_reply(call, skb); 1771e8d6c554SDavid Howells if (!last) 1772e8d6c554SDavid Howells return 0; 1773e8d6c554SDavid Howells 1774e8d6c554SDavid Howells if (call->reply_size != call->reply_max) 1775e8d6c554SDavid Howells return -EBADMSG; 1776e8d6c554SDavid Howells 1777e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1778e8d6c554SDavid Howells bp = call->buffer; 1779e8d6c554SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1780e8d6c554SDavid Howells 1781e8d6c554SDavid Howells _leave(" = 0 [done]"); 1782e8d6c554SDavid Howells return 0; 1783e8d6c554SDavid Howells } 1784e8d6c554SDavid Howells 1785e8d6c554SDavid Howells /* 1786e8d6c554SDavid Howells * FS.SetLock operation type 1787e8d6c554SDavid Howells */ 1788e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1789e8d6c554SDavid Howells .name = "FS.SetLock", 1790e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1791e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1792e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1793e8d6c554SDavid Howells }; 1794e8d6c554SDavid Howells 1795e8d6c554SDavid Howells /* 1796e8d6c554SDavid Howells * FS.ExtendLock operation type 1797e8d6c554SDavid Howells */ 1798e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1799e8d6c554SDavid Howells .name = "FS.ExtendLock", 1800e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1801e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1802e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1803e8d6c554SDavid Howells }; 1804e8d6c554SDavid Howells 1805e8d6c554SDavid Howells /* 1806e8d6c554SDavid Howells * FS.ReleaseLock operation type 1807e8d6c554SDavid Howells */ 1808e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1809e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1810e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1811e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1812e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1813e8d6c554SDavid Howells }; 1814e8d6c554SDavid Howells 1815e8d6c554SDavid Howells /* 1816e8d6c554SDavid Howells * get a lock on a file 1817e8d6c554SDavid Howells */ 1818e8d6c554SDavid Howells int afs_fs_set_lock(struct afs_server *server, 1819e8d6c554SDavid Howells struct key *key, 1820e8d6c554SDavid Howells struct afs_vnode *vnode, 1821e8d6c554SDavid Howells afs_lock_type_t type, 1822e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1823e8d6c554SDavid Howells { 1824e8d6c554SDavid Howells struct afs_call *call; 1825e8d6c554SDavid Howells __be32 *bp; 1826e8d6c554SDavid Howells 1827e8d6c554SDavid Howells _enter(""); 1828e8d6c554SDavid Howells 1829e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4); 1830e8d6c554SDavid Howells if (!call) 1831e8d6c554SDavid Howells return -ENOMEM; 1832e8d6c554SDavid Howells 1833e8d6c554SDavid Howells call->key = key; 1834e8d6c554SDavid Howells call->reply = vnode; 1835e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1836e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1837e8d6c554SDavid Howells 1838e8d6c554SDavid Howells /* marshall the parameters */ 1839e8d6c554SDavid Howells bp = call->request; 1840e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1841e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1842e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1843e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1844e8d6c554SDavid Howells *bp++ = htonl(type); 1845e8d6c554SDavid Howells 1846e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1847e8d6c554SDavid Howells } 1848e8d6c554SDavid Howells 1849e8d6c554SDavid Howells /* 1850e8d6c554SDavid Howells * extend a lock on a file 1851e8d6c554SDavid Howells */ 1852e8d6c554SDavid Howells int afs_fs_extend_lock(struct afs_server *server, 1853e8d6c554SDavid Howells struct key *key, 1854e8d6c554SDavid Howells struct afs_vnode *vnode, 1855e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1856e8d6c554SDavid Howells { 1857e8d6c554SDavid Howells struct afs_call *call; 1858e8d6c554SDavid Howells __be32 *bp; 1859e8d6c554SDavid Howells 1860e8d6c554SDavid Howells _enter(""); 1861e8d6c554SDavid Howells 1862e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4); 1863e8d6c554SDavid Howells if (!call) 1864e8d6c554SDavid Howells return -ENOMEM; 1865e8d6c554SDavid Howells 1866e8d6c554SDavid Howells call->key = key; 1867e8d6c554SDavid Howells call->reply = vnode; 1868e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1869e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1870e8d6c554SDavid Howells 1871e8d6c554SDavid Howells /* marshall the parameters */ 1872e8d6c554SDavid Howells bp = call->request; 1873e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1874e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1875e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1876e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1877e8d6c554SDavid Howells 1878e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1879e8d6c554SDavid Howells } 1880e8d6c554SDavid Howells 1881e8d6c554SDavid Howells /* 1882e8d6c554SDavid Howells * release a lock on a file 1883e8d6c554SDavid Howells */ 1884e8d6c554SDavid Howells int afs_fs_release_lock(struct afs_server *server, 1885e8d6c554SDavid Howells struct key *key, 1886e8d6c554SDavid Howells struct afs_vnode *vnode, 1887e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1888e8d6c554SDavid Howells { 1889e8d6c554SDavid Howells struct afs_call *call; 1890e8d6c554SDavid Howells __be32 *bp; 1891e8d6c554SDavid Howells 1892e8d6c554SDavid Howells _enter(""); 1893e8d6c554SDavid Howells 1894e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1895e8d6c554SDavid Howells if (!call) 1896e8d6c554SDavid Howells return -ENOMEM; 1897e8d6c554SDavid Howells 1898e8d6c554SDavid Howells call->key = key; 1899e8d6c554SDavid Howells call->reply = vnode; 1900e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1901e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1902e8d6c554SDavid Howells 1903e8d6c554SDavid Howells /* marshall the parameters */ 1904e8d6c554SDavid Howells bp = call->request; 1905e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1906e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1907e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1908e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1909e8d6c554SDavid Howells 1910e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1911e8d6c554SDavid Howells } 1912