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 */ 4508e0e7c8SDavid Howells 4608e0e7c8SDavid Howells #define EXTRACT(DST) \ 4708e0e7c8SDavid Howells do { \ 4808e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 4908e0e7c8SDavid Howells changed |= DST - x; \ 5008e0e7c8SDavid Howells DST = x; \ 5108e0e7c8SDavid Howells } while (0) 5208e0e7c8SDavid Howells 53260a9803SDavid Howells status->if_version = ntohl(*bp++); 54260a9803SDavid Howells EXTRACT(status->type); 55260a9803SDavid Howells EXTRACT(status->nlink); 56260a9803SDavid Howells size = ntohl(*bp++); 5708e0e7c8SDavid Howells data_version = ntohl(*bp++); 58260a9803SDavid Howells EXTRACT(status->author); 59260a9803SDavid Howells EXTRACT(status->owner); 60260a9803SDavid Howells EXTRACT(status->caller_access); /* call ticket dependent */ 61260a9803SDavid Howells EXTRACT(status->anon_access); 62260a9803SDavid Howells EXTRACT(status->mode); 63260a9803SDavid Howells EXTRACT(status->parent.vnode); 64260a9803SDavid Howells EXTRACT(status->parent.unique); 6508e0e7c8SDavid Howells bp++; /* seg size */ 66260a9803SDavid Howells status->mtime_client = ntohl(*bp++); 67260a9803SDavid Howells status->mtime_server = ntohl(*bp++); 68260a9803SDavid Howells EXTRACT(status->group); 6908e0e7c8SDavid Howells bp++; /* sync counter */ 7008e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 71e8d6c554SDavid Howells EXTRACT(status->lock_count); 72260a9803SDavid Howells size |= (u64) ntohl(*bp++) << 32; 7308e0e7c8SDavid Howells bp++; /* spare 4 */ 7408e0e7c8SDavid Howells *_bp = bp; 7508e0e7c8SDavid Howells 76260a9803SDavid Howells if (size != status->size) { 77260a9803SDavid Howells status->size = size; 78260a9803SDavid Howells changed |= true; 79260a9803SDavid Howells } 80260a9803SDavid Howells status->mode &= S_IALLUGO; 8108e0e7c8SDavid Howells 82260a9803SDavid Howells _debug("vnode time %lx, %lx", 83260a9803SDavid Howells status->mtime_client, status->mtime_server); 84260a9803SDavid Howells 85260a9803SDavid Howells if (vnode) { 86260a9803SDavid Howells status->parent.vid = vnode->fid.vid; 87260a9803SDavid Howells if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 88260a9803SDavid Howells _debug("vnode changed"); 89260a9803SDavid Howells i_size_write(&vnode->vfs_inode, size); 90260a9803SDavid Howells vnode->vfs_inode.i_uid = status->owner; 91260a9803SDavid Howells vnode->vfs_inode.i_gid = status->group; 92d6e43f75SDavid Howells vnode->vfs_inode.i_generation = vnode->fid.unique; 93bfe86848SMiklos Szeredi set_nlink(&vnode->vfs_inode, status->nlink); 94260a9803SDavid Howells 9508e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 9608e0e7c8SDavid Howells mode &= ~S_IALLUGO; 97260a9803SDavid Howells mode |= status->mode; 98260a9803SDavid Howells barrier(); 9908e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 10008e0e7c8SDavid Howells } 10108e0e7c8SDavid Howells 102260a9803SDavid Howells vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; 10308e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 10408e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 105d6e43f75SDavid Howells vnode->vfs_inode.i_version = data_version; 106260a9803SDavid Howells } 10708e0e7c8SDavid Howells 10831143d5dSDavid Howells expected_version = status->data_version; 10931143d5dSDavid Howells if (store_version) 11031143d5dSDavid Howells expected_version = *store_version; 11131143d5dSDavid Howells 11231143d5dSDavid Howells if (expected_version != data_version) { 113260a9803SDavid Howells status->data_version = data_version; 114260a9803SDavid Howells if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 115260a9803SDavid Howells _debug("vnode modified %llx on {%x:%u}", 116ba3e0e1aSDavid S. Miller (unsigned long long) data_version, 117ba3e0e1aSDavid S. Miller vnode->fid.vid, vnode->fid.vnode); 11808e0e7c8SDavid Howells set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 11908e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1201da177e4SLinus Torvalds } 12131143d5dSDavid Howells } else if (store_version) { 12231143d5dSDavid Howells status->data_version = data_version; 123ec26815aSDavid Howells } 124260a9803SDavid Howells } 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* 12708e0e7c8SDavid Howells * decode an AFSCallBack block 1281da177e4SLinus Torvalds */ 12908e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) 1301da177e4SLinus Torvalds { 13108e0e7c8SDavid Howells const __be32 *bp = *_bp; 1321da177e4SLinus Torvalds 13308e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 13408e0e7c8SDavid Howells vnode->cb_expiry = ntohl(*bp++); 13508e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 13608e0e7c8SDavid Howells vnode->cb_expires = vnode->cb_expiry + get_seconds(); 13708e0e7c8SDavid Howells *_bp = bp; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 140260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 141260a9803SDavid Howells struct afs_callback *cb) 142260a9803SDavid Howells { 143260a9803SDavid Howells const __be32 *bp = *_bp; 144260a9803SDavid Howells 145260a9803SDavid Howells cb->version = ntohl(*bp++); 146260a9803SDavid Howells cb->expiry = ntohl(*bp++); 147260a9803SDavid Howells cb->type = ntohl(*bp++); 148260a9803SDavid Howells *_bp = bp; 149260a9803SDavid Howells } 150260a9803SDavid Howells 1511da177e4SLinus Torvalds /* 15208e0e7c8SDavid Howells * decode an AFSVolSync block 1531da177e4SLinus Torvalds */ 15408e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 15508e0e7c8SDavid Howells struct afs_volsync *volsync) 1561da177e4SLinus Torvalds { 15708e0e7c8SDavid Howells const __be32 *bp = *_bp; 1581da177e4SLinus Torvalds 15908e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 16008e0e7c8SDavid Howells bp++; /* spare2 */ 16108e0e7c8SDavid Howells bp++; /* spare3 */ 16208e0e7c8SDavid Howells bp++; /* spare4 */ 16308e0e7c8SDavid Howells bp++; /* spare5 */ 16408e0e7c8SDavid Howells bp++; /* spare6 */ 16508e0e7c8SDavid Howells *_bp = bp; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 16808e0e7c8SDavid Howells /* 16931143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 17031143d5dSDavid Howells */ 17131143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 17231143d5dSDavid Howells { 17331143d5dSDavid Howells __be32 *bp = *_bp; 17431143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 17531143d5dSDavid Howells 17631143d5dSDavid Howells mask = 0; 17731143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 17831143d5dSDavid Howells mask |= AFS_SET_MTIME; 17931143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 18031143d5dSDavid Howells } 18131143d5dSDavid Howells 18231143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 18331143d5dSDavid Howells mask |= AFS_SET_OWNER; 18431143d5dSDavid Howells owner = attr->ia_uid; 18531143d5dSDavid Howells } 18631143d5dSDavid Howells 18731143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 18831143d5dSDavid Howells mask |= AFS_SET_GROUP; 18931143d5dSDavid Howells group = attr->ia_gid; 19031143d5dSDavid Howells } 19131143d5dSDavid Howells 19231143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 19331143d5dSDavid Howells mask |= AFS_SET_MODE; 19431143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 19531143d5dSDavid Howells } 19631143d5dSDavid Howells 19731143d5dSDavid Howells *bp++ = htonl(mask); 19831143d5dSDavid Howells *bp++ = htonl(mtime); 19931143d5dSDavid Howells *bp++ = htonl(owner); 20031143d5dSDavid Howells *bp++ = htonl(group); 20131143d5dSDavid Howells *bp++ = htonl(mode); 20231143d5dSDavid Howells *bp++ = 0; /* segment size */ 20331143d5dSDavid Howells *_bp = bp; 20431143d5dSDavid Howells } 20531143d5dSDavid Howells 20631143d5dSDavid Howells /* 20745222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 20845222b9eSDavid Howells */ 20945222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 21045222b9eSDavid Howells struct afs_volume_status *vs) 21145222b9eSDavid Howells { 21245222b9eSDavid Howells const __be32 *bp = *_bp; 21345222b9eSDavid Howells 21445222b9eSDavid Howells vs->vid = ntohl(*bp++); 21545222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 21645222b9eSDavid Howells vs->online = ntohl(*bp++); 21745222b9eSDavid Howells vs->in_service = ntohl(*bp++); 21845222b9eSDavid Howells vs->blessed = ntohl(*bp++); 21945222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 22045222b9eSDavid Howells vs->type = ntohl(*bp++); 22145222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 22245222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 22345222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 22445222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 22545222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 22645222b9eSDavid Howells *_bp = bp; 22745222b9eSDavid Howells } 22845222b9eSDavid Howells 22945222b9eSDavid Howells /* 23008e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 23108e0e7c8SDavid Howells */ 23208e0e7c8SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call, 23308e0e7c8SDavid Howells struct sk_buff *skb, bool last) 23408e0e7c8SDavid Howells { 235260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 23608e0e7c8SDavid Howells const __be32 *bp; 2371da177e4SLinus Torvalds 23808e0e7c8SDavid Howells _enter(",,%u", last); 2391da177e4SLinus Torvalds 24008e0e7c8SDavid Howells afs_transfer_reply(call, skb); 24108e0e7c8SDavid Howells if (!last) 24208e0e7c8SDavid Howells return 0; 2431da177e4SLinus Torvalds 24408e0e7c8SDavid Howells if (call->reply_size != call->reply_max) 24508e0e7c8SDavid Howells return -EBADMSG; 2461da177e4SLinus Torvalds 24708e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 24808e0e7c8SDavid Howells bp = call->buffer; 24931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 250260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 25108e0e7c8SDavid Howells if (call->reply2) 25208e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 2531da177e4SLinus Torvalds 25408e0e7c8SDavid Howells _leave(" = 0 [done]"); 25508e0e7c8SDavid Howells return 0; 256ec26815aSDavid Howells } 25708e0e7c8SDavid Howells 25808e0e7c8SDavid Howells /* 25908e0e7c8SDavid Howells * FS.FetchStatus operation type 26008e0e7c8SDavid Howells */ 26108e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 26200d3b7a4SDavid Howells .name = "FS.FetchStatus", 26308e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 26408e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 26508e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 26608e0e7c8SDavid Howells }; 2671da177e4SLinus Torvalds 2681da177e4SLinus Torvalds /* 2691da177e4SLinus Torvalds * fetch the status information for a file 2701da177e4SLinus Torvalds */ 27108e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server, 27200d3b7a4SDavid Howells struct key *key, 2731da177e4SLinus Torvalds struct afs_vnode *vnode, 27408e0e7c8SDavid Howells struct afs_volsync *volsync, 27508e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 2761da177e4SLinus Torvalds { 27708e0e7c8SDavid Howells struct afs_call *call; 2781da177e4SLinus Torvalds __be32 *bp; 2791da177e4SLinus Torvalds 280416351f2SDavid Howells _enter(",%x,{%x:%u},,", 281260a9803SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 2821da177e4SLinus Torvalds 283260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 28408e0e7c8SDavid Howells if (!call) 28508e0e7c8SDavid Howells return -ENOMEM; 2861da177e4SLinus Torvalds 28700d3b7a4SDavid Howells call->key = key; 28808e0e7c8SDavid Howells call->reply = vnode; 28908e0e7c8SDavid Howells call->reply2 = volsync; 29008e0e7c8SDavid Howells call->service_id = FS_SERVICE; 29108e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds /* marshall the parameters */ 29408e0e7c8SDavid Howells bp = call->request; 2951da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 2961da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 2971da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 2981da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 2991da177e4SLinus Torvalds 30008e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 301ec26815aSDavid Howells } 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* 30408e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 3051da177e4SLinus Torvalds */ 30608e0e7c8SDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call, 30708e0e7c8SDavid Howells struct sk_buff *skb, bool last) 3081da177e4SLinus Torvalds { 309260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 31008e0e7c8SDavid Howells const __be32 *bp; 31108e0e7c8SDavid Howells struct page *page; 31208e0e7c8SDavid Howells void *buffer; 3131da177e4SLinus Torvalds int ret; 3141da177e4SLinus Torvalds 31508e0e7c8SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 3161da177e4SLinus Torvalds 31708e0e7c8SDavid Howells switch (call->unmarshall) { 31808e0e7c8SDavid Howells case 0: 31908e0e7c8SDavid Howells call->offset = 0; 32008e0e7c8SDavid Howells call->unmarshall++; 321b9b1f8d5SDavid Howells if (call->operation_ID != FSFETCHDATA64) { 322b9b1f8d5SDavid Howells call->unmarshall++; 323b9b1f8d5SDavid Howells goto no_msw; 324b9b1f8d5SDavid Howells } 3251da177e4SLinus Torvalds 326b9b1f8d5SDavid Howells /* extract the upper part of the returned data length of an 327b9b1f8d5SDavid Howells * FSFETCHDATA64 op (which should always be 0 using this 328b9b1f8d5SDavid Howells * client) */ 32908e0e7c8SDavid Howells case 1: 330b9b1f8d5SDavid Howells _debug("extract data length (MSW)"); 331b9b1f8d5SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 332b9b1f8d5SDavid Howells switch (ret) { 333b9b1f8d5SDavid Howells case 0: break; 334b9b1f8d5SDavid Howells case -EAGAIN: return 0; 335b9b1f8d5SDavid Howells default: return ret; 336b9b1f8d5SDavid Howells } 337b9b1f8d5SDavid Howells 338b9b1f8d5SDavid Howells call->count = ntohl(call->tmp); 339b9b1f8d5SDavid Howells _debug("DATA length MSW: %u", call->count); 340b9b1f8d5SDavid Howells if (call->count > 0) 341b9b1f8d5SDavid Howells return -EBADMSG; 342b9b1f8d5SDavid Howells call->offset = 0; 343b9b1f8d5SDavid Howells call->unmarshall++; 344b9b1f8d5SDavid Howells 345b9b1f8d5SDavid Howells no_msw: 346b9b1f8d5SDavid Howells /* extract the returned data length */ 347b9b1f8d5SDavid Howells case 2: 34808e0e7c8SDavid Howells _debug("extract data length"); 34908e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 35008e0e7c8SDavid Howells switch (ret) { 35108e0e7c8SDavid Howells case 0: break; 35208e0e7c8SDavid Howells case -EAGAIN: return 0; 35308e0e7c8SDavid Howells default: return ret; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 35608e0e7c8SDavid Howells call->count = ntohl(call->tmp); 35708e0e7c8SDavid Howells _debug("DATA length: %u", call->count); 35808e0e7c8SDavid Howells if (call->count > PAGE_SIZE) 35908e0e7c8SDavid Howells return -EBADMSG; 36008e0e7c8SDavid Howells call->offset = 0; 36108e0e7c8SDavid Howells call->unmarshall++; 3621da177e4SLinus Torvalds 36308e0e7c8SDavid Howells /* extract the returned data */ 364b9b1f8d5SDavid Howells case 3: 36508e0e7c8SDavid Howells _debug("extract data"); 366416351f2SDavid Howells if (call->count > 0) { 36708e0e7c8SDavid Howells page = call->reply3; 368da4aa36dSCong Wang buffer = kmap_atomic(page); 369416351f2SDavid Howells ret = afs_extract_data(call, skb, last, buffer, 370416351f2SDavid Howells call->count); 371da4aa36dSCong Wang kunmap_atomic(buffer); 37208e0e7c8SDavid Howells switch (ret) { 37308e0e7c8SDavid Howells case 0: break; 37408e0e7c8SDavid Howells case -EAGAIN: return 0; 37508e0e7c8SDavid Howells default: return ret; 3761da177e4SLinus Torvalds } 377416351f2SDavid Howells } 3781da177e4SLinus Torvalds 37908e0e7c8SDavid Howells call->offset = 0; 38008e0e7c8SDavid Howells call->unmarshall++; 38108e0e7c8SDavid Howells 38208e0e7c8SDavid Howells /* extract the metadata */ 383b9b1f8d5SDavid Howells case 4: 384260a9803SDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 385260a9803SDavid Howells (21 + 3 + 6) * 4); 38608e0e7c8SDavid Howells switch (ret) { 38708e0e7c8SDavid Howells case 0: break; 38808e0e7c8SDavid Howells case -EAGAIN: return 0; 38908e0e7c8SDavid Howells default: return ret; 390ec26815aSDavid Howells } 3911da177e4SLinus Torvalds 39208e0e7c8SDavid Howells bp = call->buffer; 39331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 394260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 39508e0e7c8SDavid Howells if (call->reply2) 39608e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 3971da177e4SLinus Torvalds 39808e0e7c8SDavid Howells call->offset = 0; 39908e0e7c8SDavid Howells call->unmarshall++; 4001da177e4SLinus Torvalds 401b9b1f8d5SDavid Howells case 5: 40208e0e7c8SDavid Howells _debug("trailer"); 40308e0e7c8SDavid Howells if (skb->len != 0) 40408e0e7c8SDavid Howells return -EBADMSG; 4051da177e4SLinus Torvalds break; 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds 40808e0e7c8SDavid Howells if (!last) 40908e0e7c8SDavid Howells return 0; 4101da177e4SLinus Torvalds 411416351f2SDavid Howells if (call->count < PAGE_SIZE) { 412416351f2SDavid Howells _debug("clear"); 413416351f2SDavid Howells page = call->reply3; 414da4aa36dSCong Wang buffer = kmap_atomic(page); 415416351f2SDavid Howells memset(buffer + call->count, 0, PAGE_SIZE - call->count); 416da4aa36dSCong Wang kunmap_atomic(buffer); 417416351f2SDavid Howells } 418416351f2SDavid Howells 41908e0e7c8SDavid Howells _leave(" = 0 [done]"); 42008e0e7c8SDavid Howells return 0; 421ec26815aSDavid Howells } 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /* 42408e0e7c8SDavid Howells * FS.FetchData operation type 4251da177e4SLinus Torvalds */ 42608e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 42700d3b7a4SDavid Howells .name = "FS.FetchData", 42808e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 42908e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 43008e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 43108e0e7c8SDavid Howells }; 43208e0e7c8SDavid Howells 433b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 434b9b1f8d5SDavid Howells .name = "FS.FetchData64", 435b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 436b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 437b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 438b9b1f8d5SDavid Howells }; 439b9b1f8d5SDavid Howells 440b9b1f8d5SDavid Howells /* 441b9b1f8d5SDavid Howells * fetch data from a very large file 442b9b1f8d5SDavid Howells */ 443b9b1f8d5SDavid Howells static int afs_fs_fetch_data64(struct afs_server *server, 444b9b1f8d5SDavid Howells struct key *key, 445b9b1f8d5SDavid Howells struct afs_vnode *vnode, 446b9b1f8d5SDavid Howells off_t offset, size_t length, 447b9b1f8d5SDavid Howells struct page *buffer, 448b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 449b9b1f8d5SDavid Howells { 450b9b1f8d5SDavid Howells struct afs_call *call; 451b9b1f8d5SDavid Howells __be32 *bp; 452b9b1f8d5SDavid Howells 453b9b1f8d5SDavid Howells _enter(""); 454b9b1f8d5SDavid Howells 455b9b1f8d5SDavid Howells ASSERTCMP(length, <, ULONG_MAX); 456b9b1f8d5SDavid Howells 457b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 458b9b1f8d5SDavid Howells if (!call) 459b9b1f8d5SDavid Howells return -ENOMEM; 460b9b1f8d5SDavid Howells 461b9b1f8d5SDavid Howells call->key = key; 462b9b1f8d5SDavid Howells call->reply = vnode; 463b9b1f8d5SDavid Howells call->reply2 = NULL; /* volsync */ 464b9b1f8d5SDavid Howells call->reply3 = buffer; 465b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 466b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 467b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA64; 468b9b1f8d5SDavid Howells 469b9b1f8d5SDavid Howells /* marshall the parameters */ 470b9b1f8d5SDavid Howells bp = call->request; 471b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 472b9b1f8d5SDavid Howells bp[1] = htonl(vnode->fid.vid); 473b9b1f8d5SDavid Howells bp[2] = htonl(vnode->fid.vnode); 474b9b1f8d5SDavid Howells bp[3] = htonl(vnode->fid.unique); 475b9b1f8d5SDavid Howells bp[4] = htonl(upper_32_bits(offset)); 476b9b1f8d5SDavid Howells bp[5] = htonl((u32) offset); 477b9b1f8d5SDavid Howells bp[6] = 0; 478b9b1f8d5SDavid Howells bp[7] = htonl((u32) length); 479b9b1f8d5SDavid Howells 480b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 481b9b1f8d5SDavid Howells } 482b9b1f8d5SDavid Howells 48308e0e7c8SDavid Howells /* 48408e0e7c8SDavid Howells * fetch data from a file 48508e0e7c8SDavid Howells */ 48608e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 48700d3b7a4SDavid Howells struct key *key, 4881da177e4SLinus Torvalds struct afs_vnode *vnode, 48908e0e7c8SDavid Howells off_t offset, size_t length, 49008e0e7c8SDavid Howells struct page *buffer, 49108e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 4921da177e4SLinus Torvalds { 49308e0e7c8SDavid Howells struct afs_call *call; 49408e0e7c8SDavid Howells __be32 *bp; 4951da177e4SLinus Torvalds 496b9b1f8d5SDavid Howells if (upper_32_bits(offset) || upper_32_bits(offset + length)) 497b9b1f8d5SDavid Howells return afs_fs_fetch_data64(server, key, vnode, offset, length, 498b9b1f8d5SDavid Howells buffer, wait_mode); 499b9b1f8d5SDavid Howells 50008e0e7c8SDavid Howells _enter(""); 5011da177e4SLinus Torvalds 502260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 50308e0e7c8SDavid Howells if (!call) 50408e0e7c8SDavid Howells return -ENOMEM; 5051da177e4SLinus Torvalds 50600d3b7a4SDavid Howells call->key = key; 50708e0e7c8SDavid Howells call->reply = vnode; 508260a9803SDavid Howells call->reply2 = NULL; /* volsync */ 50908e0e7c8SDavid Howells call->reply3 = buffer; 51008e0e7c8SDavid Howells call->service_id = FS_SERVICE; 51108e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 512b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds /* marshall the parameters */ 51508e0e7c8SDavid Howells bp = call->request; 51608e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 51708e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 51808e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 51908e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 52008e0e7c8SDavid Howells bp[4] = htonl(offset); 52108e0e7c8SDavid Howells bp[5] = htonl(length); 5221da177e4SLinus Torvalds 52308e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 52608e0e7c8SDavid Howells /* 52708e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 52808e0e7c8SDavid Howells */ 52908e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, 53008e0e7c8SDavid Howells struct sk_buff *skb, bool last) 53108e0e7c8SDavid Howells { 53208e0e7c8SDavid Howells _enter(",{%u},%d", skb->len, last); 5331da177e4SLinus Torvalds 53408e0e7c8SDavid Howells if (skb->len > 0) 53508e0e7c8SDavid Howells return -EBADMSG; /* shouldn't be any reply data */ 53608e0e7c8SDavid Howells return 0; 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 53908e0e7c8SDavid Howells /* 54008e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 54108e0e7c8SDavid Howells */ 54208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 54300d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 54408e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 54508e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 54608e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 54708e0e7c8SDavid Howells }; 5481da177e4SLinus Torvalds 54908e0e7c8SDavid Howells /* 55008e0e7c8SDavid Howells * give up a set of callbacks 55108e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 55208e0e7c8SDavid Howells */ 55308e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server, 55408e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 55508e0e7c8SDavid Howells { 55608e0e7c8SDavid Howells struct afs_call *call; 55708e0e7c8SDavid Howells size_t ncallbacks; 55808e0e7c8SDavid Howells __be32 *bp, *tp; 55908e0e7c8SDavid Howells int loop; 5601da177e4SLinus Torvalds 56108e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 56208e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 56308e0e7c8SDavid Howells 56408e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 56508e0e7c8SDavid Howells 56608e0e7c8SDavid Howells if (ncallbacks == 0) 56708e0e7c8SDavid Howells return 0; 56808e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 56908e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 57008e0e7c8SDavid Howells 57108e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 57208e0e7c8SDavid Howells 57308e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, 57408e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 57508e0e7c8SDavid Howells if (!call) 57608e0e7c8SDavid Howells return -ENOMEM; 57708e0e7c8SDavid Howells 57808e0e7c8SDavid Howells call->service_id = FS_SERVICE; 57908e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 58008e0e7c8SDavid Howells 58108e0e7c8SDavid Howells /* marshall the parameters */ 58208e0e7c8SDavid Howells bp = call->request; 58308e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 58408e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 58508e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 58608e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 58708e0e7c8SDavid Howells 58808e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 58908e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 59008e0e7c8SDavid Howells struct afs_callback *cb = 59108e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 59208e0e7c8SDavid Howells 59308e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 59408e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 59508e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 59608e0e7c8SDavid Howells *tp++ = htonl(cb->version); 59708e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 59808e0e7c8SDavid Howells *tp++ = htonl(cb->type); 59908e0e7c8SDavid Howells smp_mb(); 60008e0e7c8SDavid Howells server->cb_break_tail = 60108e0e7c8SDavid Howells (server->cb_break_tail + 1) & 60208e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 603ec26815aSDavid Howells } 60408e0e7c8SDavid Howells 60508e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 60608e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 60708e0e7c8SDavid Howells 60808e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 60908e0e7c8SDavid Howells } 610260a9803SDavid Howells 611260a9803SDavid Howells /* 612260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 613260a9803SDavid Howells */ 614260a9803SDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call, 615260a9803SDavid Howells struct sk_buff *skb, bool last) 616260a9803SDavid Howells { 617260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 618260a9803SDavid Howells const __be32 *bp; 619260a9803SDavid Howells 620260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 621260a9803SDavid Howells 622260a9803SDavid Howells afs_transfer_reply(call, skb); 623260a9803SDavid Howells if (!last) 624260a9803SDavid Howells return 0; 625260a9803SDavid Howells 626260a9803SDavid Howells if (call->reply_size != call->reply_max) 627260a9803SDavid Howells return -EBADMSG; 628260a9803SDavid Howells 629260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 630260a9803SDavid Howells bp = call->buffer; 631260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 63231143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 63331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 634260a9803SDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply4); 635260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 636260a9803SDavid Howells 637260a9803SDavid Howells _leave(" = 0 [done]"); 638260a9803SDavid Howells return 0; 639260a9803SDavid Howells } 640260a9803SDavid Howells 641260a9803SDavid Howells /* 642260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 643260a9803SDavid Howells */ 644260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = { 645260a9803SDavid Howells .name = "FS.CreateXXXX", 646260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 647260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 648260a9803SDavid Howells .destructor = afs_flat_call_destructor, 649260a9803SDavid Howells }; 650260a9803SDavid Howells 651260a9803SDavid Howells /* 652260a9803SDavid Howells * create a file or make a directory 653260a9803SDavid Howells */ 654260a9803SDavid Howells int afs_fs_create(struct afs_server *server, 655260a9803SDavid Howells struct key *key, 656260a9803SDavid Howells struct afs_vnode *vnode, 657260a9803SDavid Howells const char *name, 658260a9803SDavid Howells umode_t mode, 659260a9803SDavid Howells struct afs_fid *newfid, 660260a9803SDavid Howells struct afs_file_status *newstatus, 661260a9803SDavid Howells struct afs_callback *newcb, 662260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 663260a9803SDavid Howells { 664260a9803SDavid Howells struct afs_call *call; 665260a9803SDavid Howells size_t namesz, reqsz, padsz; 666260a9803SDavid Howells __be32 *bp; 667260a9803SDavid Howells 668260a9803SDavid Howells _enter(""); 669260a9803SDavid Howells 670260a9803SDavid Howells namesz = strlen(name); 671260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 672260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 673260a9803SDavid Howells 674260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, 675260a9803SDavid Howells (3 + 21 + 21 + 3 + 6) * 4); 676260a9803SDavid Howells if (!call) 677260a9803SDavid Howells return -ENOMEM; 678260a9803SDavid Howells 679260a9803SDavid Howells call->key = key; 680260a9803SDavid Howells call->reply = vnode; 681260a9803SDavid Howells call->reply2 = newfid; 682260a9803SDavid Howells call->reply3 = newstatus; 683260a9803SDavid Howells call->reply4 = newcb; 684260a9803SDavid Howells call->service_id = FS_SERVICE; 685260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 686260a9803SDavid Howells 687260a9803SDavid Howells /* marshall the parameters */ 688260a9803SDavid Howells bp = call->request; 689260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 690260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 691260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 692260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 693260a9803SDavid Howells *bp++ = htonl(namesz); 694260a9803SDavid Howells memcpy(bp, name, namesz); 695260a9803SDavid Howells bp = (void *) bp + namesz; 696260a9803SDavid Howells if (padsz > 0) { 697260a9803SDavid Howells memset(bp, 0, padsz); 698260a9803SDavid Howells bp = (void *) bp + padsz; 699260a9803SDavid Howells } 700260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 701260a9803SDavid Howells *bp++ = 0; /* mtime */ 702260a9803SDavid Howells *bp++ = 0; /* owner */ 703260a9803SDavid Howells *bp++ = 0; /* group */ 704260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 705260a9803SDavid Howells *bp++ = 0; /* segment size */ 706260a9803SDavid Howells 707260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 708260a9803SDavid Howells } 709260a9803SDavid Howells 710260a9803SDavid Howells /* 711260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 712260a9803SDavid Howells */ 713260a9803SDavid Howells static int afs_deliver_fs_remove(struct afs_call *call, 714260a9803SDavid Howells struct sk_buff *skb, bool last) 715260a9803SDavid Howells { 716260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 717260a9803SDavid Howells const __be32 *bp; 718260a9803SDavid Howells 719260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 720260a9803SDavid Howells 721260a9803SDavid Howells afs_transfer_reply(call, skb); 722260a9803SDavid Howells if (!last) 723260a9803SDavid Howells return 0; 724260a9803SDavid Howells 725260a9803SDavid Howells if (call->reply_size != call->reply_max) 726260a9803SDavid Howells return -EBADMSG; 727260a9803SDavid Howells 728260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 729260a9803SDavid Howells bp = call->buffer; 73031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 731260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 732260a9803SDavid Howells 733260a9803SDavid Howells _leave(" = 0 [done]"); 734260a9803SDavid Howells return 0; 735260a9803SDavid Howells } 736260a9803SDavid Howells 737260a9803SDavid Howells /* 738260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 739260a9803SDavid Howells */ 740260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = { 741260a9803SDavid Howells .name = "FS.RemoveXXXX", 742260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 743260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 744260a9803SDavid Howells .destructor = afs_flat_call_destructor, 745260a9803SDavid Howells }; 746260a9803SDavid Howells 747260a9803SDavid Howells /* 748260a9803SDavid Howells * remove a file or directory 749260a9803SDavid Howells */ 750260a9803SDavid Howells int afs_fs_remove(struct afs_server *server, 751260a9803SDavid Howells struct key *key, 752260a9803SDavid Howells struct afs_vnode *vnode, 753260a9803SDavid Howells const char *name, 754260a9803SDavid Howells bool isdir, 755260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 756260a9803SDavid Howells { 757260a9803SDavid Howells struct afs_call *call; 758260a9803SDavid Howells size_t namesz, reqsz, padsz; 759260a9803SDavid Howells __be32 *bp; 760260a9803SDavid Howells 761260a9803SDavid Howells _enter(""); 762260a9803SDavid Howells 763260a9803SDavid Howells namesz = strlen(name); 764260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 765260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 766260a9803SDavid Howells 767260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); 768260a9803SDavid Howells if (!call) 769260a9803SDavid Howells return -ENOMEM; 770260a9803SDavid Howells 771260a9803SDavid Howells call->key = key; 772260a9803SDavid Howells call->reply = vnode; 773260a9803SDavid Howells call->service_id = FS_SERVICE; 774260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 775260a9803SDavid Howells 776260a9803SDavid Howells /* marshall the parameters */ 777260a9803SDavid Howells bp = call->request; 778260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 779260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 780260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 781260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 782260a9803SDavid Howells *bp++ = htonl(namesz); 783260a9803SDavid Howells memcpy(bp, name, namesz); 784260a9803SDavid Howells bp = (void *) bp + namesz; 785260a9803SDavid Howells if (padsz > 0) { 786260a9803SDavid Howells memset(bp, 0, padsz); 787260a9803SDavid Howells bp = (void *) bp + padsz; 788260a9803SDavid Howells } 789260a9803SDavid Howells 790260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 791260a9803SDavid Howells } 792260a9803SDavid Howells 793260a9803SDavid Howells /* 794260a9803SDavid Howells * deliver reply data to an FS.Link 795260a9803SDavid Howells */ 796260a9803SDavid Howells static int afs_deliver_fs_link(struct afs_call *call, 797260a9803SDavid Howells struct sk_buff *skb, bool last) 798260a9803SDavid Howells { 799260a9803SDavid Howells struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; 800260a9803SDavid Howells const __be32 *bp; 801260a9803SDavid Howells 802260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 803260a9803SDavid Howells 804260a9803SDavid Howells afs_transfer_reply(call, skb); 805260a9803SDavid Howells if (!last) 806260a9803SDavid Howells return 0; 807260a9803SDavid Howells 808260a9803SDavid Howells if (call->reply_size != call->reply_max) 809260a9803SDavid Howells return -EBADMSG; 810260a9803SDavid Howells 811260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 812260a9803SDavid Howells bp = call->buffer; 81331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 81431143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); 815260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 816260a9803SDavid Howells 817260a9803SDavid Howells _leave(" = 0 [done]"); 818260a9803SDavid Howells return 0; 819260a9803SDavid Howells } 820260a9803SDavid Howells 821260a9803SDavid Howells /* 822260a9803SDavid Howells * FS.Link operation type 823260a9803SDavid Howells */ 824260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 825260a9803SDavid Howells .name = "FS.Link", 826260a9803SDavid Howells .deliver = afs_deliver_fs_link, 827260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 828260a9803SDavid Howells .destructor = afs_flat_call_destructor, 829260a9803SDavid Howells }; 830260a9803SDavid Howells 831260a9803SDavid Howells /* 832260a9803SDavid Howells * make a hard link 833260a9803SDavid Howells */ 834260a9803SDavid Howells int afs_fs_link(struct afs_server *server, 835260a9803SDavid Howells struct key *key, 836260a9803SDavid Howells struct afs_vnode *dvnode, 837260a9803SDavid Howells struct afs_vnode *vnode, 838260a9803SDavid Howells const char *name, 839260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 840260a9803SDavid Howells { 841260a9803SDavid Howells struct afs_call *call; 842260a9803SDavid Howells size_t namesz, reqsz, padsz; 843260a9803SDavid Howells __be32 *bp; 844260a9803SDavid Howells 845260a9803SDavid Howells _enter(""); 846260a9803SDavid Howells 847260a9803SDavid Howells namesz = strlen(name); 848260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 849260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 850260a9803SDavid Howells 851260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 852260a9803SDavid Howells if (!call) 853260a9803SDavid Howells return -ENOMEM; 854260a9803SDavid Howells 855260a9803SDavid Howells call->key = key; 856260a9803SDavid Howells call->reply = dvnode; 857260a9803SDavid Howells call->reply2 = vnode; 858260a9803SDavid Howells call->service_id = FS_SERVICE; 859260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 860260a9803SDavid Howells 861260a9803SDavid Howells /* marshall the parameters */ 862260a9803SDavid Howells bp = call->request; 863260a9803SDavid Howells *bp++ = htonl(FSLINK); 864260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 865260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 866260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 867260a9803SDavid Howells *bp++ = htonl(namesz); 868260a9803SDavid Howells memcpy(bp, name, namesz); 869260a9803SDavid Howells bp = (void *) bp + namesz; 870260a9803SDavid Howells if (padsz > 0) { 871260a9803SDavid Howells memset(bp, 0, padsz); 872260a9803SDavid Howells bp = (void *) bp + padsz; 873260a9803SDavid Howells } 874260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 875260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 876260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 877260a9803SDavid Howells 878260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 879260a9803SDavid Howells } 880260a9803SDavid Howells 881260a9803SDavid Howells /* 882260a9803SDavid Howells * deliver reply data to an FS.Symlink 883260a9803SDavid Howells */ 884260a9803SDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call, 885260a9803SDavid Howells struct sk_buff *skb, bool last) 886260a9803SDavid Howells { 887260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 888260a9803SDavid Howells const __be32 *bp; 889260a9803SDavid Howells 890260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 891260a9803SDavid Howells 892260a9803SDavid Howells afs_transfer_reply(call, skb); 893260a9803SDavid Howells if (!last) 894260a9803SDavid Howells return 0; 895260a9803SDavid Howells 896260a9803SDavid Howells if (call->reply_size != call->reply_max) 897260a9803SDavid Howells return -EBADMSG; 898260a9803SDavid Howells 899260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 900260a9803SDavid Howells bp = call->buffer; 901260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 90231143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 90331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 904260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 905260a9803SDavid Howells 906260a9803SDavid Howells _leave(" = 0 [done]"); 907260a9803SDavid Howells return 0; 908260a9803SDavid Howells } 909260a9803SDavid Howells 910260a9803SDavid Howells /* 911260a9803SDavid Howells * FS.Symlink operation type 912260a9803SDavid Howells */ 913260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 914260a9803SDavid Howells .name = "FS.Symlink", 915260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 916260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 917260a9803SDavid Howells .destructor = afs_flat_call_destructor, 918260a9803SDavid Howells }; 919260a9803SDavid Howells 920260a9803SDavid Howells /* 921260a9803SDavid Howells * create a symbolic link 922260a9803SDavid Howells */ 923260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server, 924260a9803SDavid Howells struct key *key, 925260a9803SDavid Howells struct afs_vnode *vnode, 926260a9803SDavid Howells const char *name, 927260a9803SDavid Howells const char *contents, 928260a9803SDavid Howells struct afs_fid *newfid, 929260a9803SDavid Howells struct afs_file_status *newstatus, 930260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 931260a9803SDavid Howells { 932260a9803SDavid Howells struct afs_call *call; 933260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 934260a9803SDavid Howells __be32 *bp; 935260a9803SDavid Howells 936260a9803SDavid Howells _enter(""); 937260a9803SDavid Howells 938260a9803SDavid Howells namesz = strlen(name); 939260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 940260a9803SDavid Howells 941260a9803SDavid Howells c_namesz = strlen(contents); 942260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 943260a9803SDavid Howells 944260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 945260a9803SDavid Howells 946260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, 947260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 948260a9803SDavid Howells if (!call) 949260a9803SDavid Howells return -ENOMEM; 950260a9803SDavid Howells 951260a9803SDavid Howells call->key = key; 952260a9803SDavid Howells call->reply = vnode; 953260a9803SDavid Howells call->reply2 = newfid; 954260a9803SDavid Howells call->reply3 = newstatus; 955260a9803SDavid Howells call->service_id = FS_SERVICE; 956260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 957260a9803SDavid Howells 958260a9803SDavid Howells /* marshall the parameters */ 959260a9803SDavid Howells bp = call->request; 960260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 961260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 962260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 963260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 964260a9803SDavid Howells *bp++ = htonl(namesz); 965260a9803SDavid Howells memcpy(bp, name, namesz); 966260a9803SDavid Howells bp = (void *) bp + namesz; 967260a9803SDavid Howells if (padsz > 0) { 968260a9803SDavid Howells memset(bp, 0, padsz); 969260a9803SDavid Howells bp = (void *) bp + padsz; 970260a9803SDavid Howells } 971260a9803SDavid Howells *bp++ = htonl(c_namesz); 972260a9803SDavid Howells memcpy(bp, contents, c_namesz); 973260a9803SDavid Howells bp = (void *) bp + c_namesz; 974260a9803SDavid Howells if (c_padsz > 0) { 975260a9803SDavid Howells memset(bp, 0, c_padsz); 976260a9803SDavid Howells bp = (void *) bp + c_padsz; 977260a9803SDavid Howells } 978260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 979260a9803SDavid Howells *bp++ = 0; /* mtime */ 980260a9803SDavid Howells *bp++ = 0; /* owner */ 981260a9803SDavid Howells *bp++ = 0; /* group */ 982260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 983260a9803SDavid Howells *bp++ = 0; /* segment size */ 984260a9803SDavid Howells 985260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 986260a9803SDavid Howells } 987260a9803SDavid Howells 988260a9803SDavid Howells /* 989260a9803SDavid Howells * deliver reply data to an FS.Rename 990260a9803SDavid Howells */ 991260a9803SDavid Howells static int afs_deliver_fs_rename(struct afs_call *call, 992260a9803SDavid Howells struct sk_buff *skb, bool last) 993260a9803SDavid Howells { 994260a9803SDavid Howells struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; 995260a9803SDavid Howells const __be32 *bp; 996260a9803SDavid Howells 997260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 998260a9803SDavid Howells 999260a9803SDavid Howells afs_transfer_reply(call, skb); 1000260a9803SDavid Howells if (!last) 1001260a9803SDavid Howells return 0; 1002260a9803SDavid Howells 1003260a9803SDavid Howells if (call->reply_size != call->reply_max) 1004260a9803SDavid Howells return -EBADMSG; 1005260a9803SDavid Howells 1006260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 1007260a9803SDavid Howells bp = call->buffer; 100831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); 1009260a9803SDavid Howells if (new_dvnode != orig_dvnode) 101031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, 101131143d5dSDavid Howells NULL); 1012260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1013260a9803SDavid Howells 1014260a9803SDavid Howells _leave(" = 0 [done]"); 1015260a9803SDavid Howells return 0; 1016260a9803SDavid Howells } 1017260a9803SDavid Howells 1018260a9803SDavid Howells /* 1019260a9803SDavid Howells * FS.Rename operation type 1020260a9803SDavid Howells */ 1021260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 1022260a9803SDavid Howells .name = "FS.Rename", 1023260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 1024260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 1025260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1026260a9803SDavid Howells }; 1027260a9803SDavid Howells 1028260a9803SDavid Howells /* 1029260a9803SDavid Howells * create a symbolic link 1030260a9803SDavid Howells */ 1031260a9803SDavid Howells int afs_fs_rename(struct afs_server *server, 1032260a9803SDavid Howells struct key *key, 1033260a9803SDavid Howells struct afs_vnode *orig_dvnode, 1034260a9803SDavid Howells const char *orig_name, 1035260a9803SDavid Howells struct afs_vnode *new_dvnode, 1036260a9803SDavid Howells const char *new_name, 1037260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 1038260a9803SDavid Howells { 1039260a9803SDavid Howells struct afs_call *call; 1040260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 1041260a9803SDavid Howells __be32 *bp; 1042260a9803SDavid Howells 1043260a9803SDavid Howells _enter(""); 1044260a9803SDavid Howells 1045260a9803SDavid Howells o_namesz = strlen(orig_name); 1046260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 1047260a9803SDavid Howells 1048260a9803SDavid Howells n_namesz = strlen(new_name); 1049260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 1050260a9803SDavid Howells 1051260a9803SDavid Howells reqsz = (4 * 4) + 1052260a9803SDavid Howells 4 + o_namesz + o_padsz + 1053260a9803SDavid Howells (3 * 4) + 1054260a9803SDavid Howells 4 + n_namesz + n_padsz; 1055260a9803SDavid Howells 1056260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1057260a9803SDavid Howells if (!call) 1058260a9803SDavid Howells return -ENOMEM; 1059260a9803SDavid Howells 1060260a9803SDavid Howells call->key = key; 1061260a9803SDavid Howells call->reply = orig_dvnode; 1062260a9803SDavid Howells call->reply2 = new_dvnode; 1063260a9803SDavid Howells call->service_id = FS_SERVICE; 1064260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 1065260a9803SDavid Howells 1066260a9803SDavid Howells /* marshall the parameters */ 1067260a9803SDavid Howells bp = call->request; 1068260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1069260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 1070260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 1071260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 1072260a9803SDavid Howells *bp++ = htonl(o_namesz); 1073260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 1074260a9803SDavid Howells bp = (void *) bp + o_namesz; 1075260a9803SDavid Howells if (o_padsz > 0) { 1076260a9803SDavid Howells memset(bp, 0, o_padsz); 1077260a9803SDavid Howells bp = (void *) bp + o_padsz; 1078260a9803SDavid Howells } 1079260a9803SDavid Howells 1080260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 1081260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 1082260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 1083260a9803SDavid Howells *bp++ = htonl(n_namesz); 1084260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 1085260a9803SDavid Howells bp = (void *) bp + n_namesz; 1086260a9803SDavid Howells if (n_padsz > 0) { 1087260a9803SDavid Howells memset(bp, 0, n_padsz); 1088260a9803SDavid Howells bp = (void *) bp + n_padsz; 1089260a9803SDavid Howells } 1090260a9803SDavid Howells 1091260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1092260a9803SDavid Howells } 109331143d5dSDavid Howells 109431143d5dSDavid Howells /* 109531143d5dSDavid Howells * deliver reply data to an FS.StoreData 109631143d5dSDavid Howells */ 109731143d5dSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call, 109831143d5dSDavid Howells struct sk_buff *skb, bool last) 109931143d5dSDavid Howells { 110031143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 110131143d5dSDavid Howells const __be32 *bp; 110231143d5dSDavid Howells 110331143d5dSDavid Howells _enter(",,%u", last); 110431143d5dSDavid Howells 110531143d5dSDavid Howells afs_transfer_reply(call, skb); 110631143d5dSDavid Howells if (!last) { 110731143d5dSDavid Howells _leave(" = 0 [more]"); 110831143d5dSDavid Howells return 0; 110931143d5dSDavid Howells } 111031143d5dSDavid Howells 111131143d5dSDavid Howells if (call->reply_size != call->reply_max) { 111231143d5dSDavid Howells _leave(" = -EBADMSG [%u != %u]", 111331143d5dSDavid Howells call->reply_size, call->reply_max); 111431143d5dSDavid Howells return -EBADMSG; 111531143d5dSDavid Howells } 111631143d5dSDavid Howells 111731143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 111831143d5dSDavid Howells bp = call->buffer; 111931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, 112031143d5dSDavid Howells &call->store_version); 112131143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 112231143d5dSDavid Howells 112331143d5dSDavid Howells afs_pages_written_back(vnode, call); 112431143d5dSDavid Howells 112531143d5dSDavid Howells _leave(" = 0 [done]"); 112631143d5dSDavid Howells return 0; 112731143d5dSDavid Howells } 112831143d5dSDavid Howells 112931143d5dSDavid Howells /* 113031143d5dSDavid Howells * FS.StoreData operation type 113131143d5dSDavid Howells */ 113231143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 113331143d5dSDavid Howells .name = "FS.StoreData", 113431143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 113531143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 113631143d5dSDavid Howells .destructor = afs_flat_call_destructor, 113731143d5dSDavid Howells }; 113831143d5dSDavid Howells 1139b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1140b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1141b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1142b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1143b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1144b9b1f8d5SDavid Howells }; 1145b9b1f8d5SDavid Howells 1146b9b1f8d5SDavid Howells /* 1147b9b1f8d5SDavid Howells * store a set of pages to a very large file 1148b9b1f8d5SDavid Howells */ 1149b9b1f8d5SDavid Howells static int afs_fs_store_data64(struct afs_server *server, 1150b9b1f8d5SDavid Howells struct afs_writeback *wb, 1151b9b1f8d5SDavid Howells pgoff_t first, pgoff_t last, 1152b9b1f8d5SDavid Howells unsigned offset, unsigned to, 1153b9b1f8d5SDavid Howells loff_t size, loff_t pos, loff_t i_size, 1154b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 1155b9b1f8d5SDavid Howells { 1156b9b1f8d5SDavid Howells struct afs_vnode *vnode = wb->vnode; 1157b9b1f8d5SDavid Howells struct afs_call *call; 1158b9b1f8d5SDavid Howells __be32 *bp; 1159b9b1f8d5SDavid Howells 1160b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1161b9b1f8d5SDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 1162b9b1f8d5SDavid Howells 1163b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData64, 1164b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1165b9b1f8d5SDavid Howells (21 + 6) * 4); 1166b9b1f8d5SDavid Howells if (!call) 1167b9b1f8d5SDavid Howells return -ENOMEM; 1168b9b1f8d5SDavid Howells 1169b9b1f8d5SDavid Howells call->wb = wb; 1170b9b1f8d5SDavid Howells call->key = wb->key; 1171b9b1f8d5SDavid Howells call->reply = vnode; 1172b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1173b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1174b9b1f8d5SDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 1175b9b1f8d5SDavid Howells call->first = first; 1176b9b1f8d5SDavid Howells call->last = last; 1177b9b1f8d5SDavid Howells call->first_offset = offset; 1178b9b1f8d5SDavid Howells call->last_to = to; 1179b9b1f8d5SDavid Howells call->send_pages = true; 1180b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1181b9b1f8d5SDavid Howells 1182b9b1f8d5SDavid Howells /* marshall the parameters */ 1183b9b1f8d5SDavid Howells bp = call->request; 1184b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1185b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1186b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1187b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1188b9b1f8d5SDavid Howells 1189b9b1f8d5SDavid Howells *bp++ = 0; /* mask */ 1190b9b1f8d5SDavid Howells *bp++ = 0; /* mtime */ 1191b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1192b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1193b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1194b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1195b9b1f8d5SDavid Howells 1196b9b1f8d5SDavid Howells *bp++ = htonl(pos >> 32); 1197b9b1f8d5SDavid Howells *bp++ = htonl((u32) pos); 1198b9b1f8d5SDavid Howells *bp++ = htonl(size >> 32); 1199b9b1f8d5SDavid Howells *bp++ = htonl((u32) size); 1200b9b1f8d5SDavid Howells *bp++ = htonl(i_size >> 32); 1201b9b1f8d5SDavid Howells *bp++ = htonl((u32) i_size); 1202b9b1f8d5SDavid Howells 1203b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1204b9b1f8d5SDavid Howells } 1205b9b1f8d5SDavid Howells 120631143d5dSDavid Howells /* 120731143d5dSDavid Howells * store a set of pages 120831143d5dSDavid Howells */ 120931143d5dSDavid Howells int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, 121031143d5dSDavid Howells pgoff_t first, pgoff_t last, 121131143d5dSDavid Howells unsigned offset, unsigned to, 121231143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 121331143d5dSDavid Howells { 121431143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 121531143d5dSDavid Howells struct afs_call *call; 121631143d5dSDavid Howells loff_t size, pos, i_size; 121731143d5dSDavid Howells __be32 *bp; 121831143d5dSDavid Howells 121931143d5dSDavid Howells _enter(",%x,{%x:%u},,", 122031143d5dSDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 122131143d5dSDavid Howells 122231143d5dSDavid Howells size = to - offset; 122331143d5dSDavid Howells if (first != last) 122431143d5dSDavid Howells size += (loff_t)(last - first) << PAGE_SHIFT; 122531143d5dSDavid Howells pos = (loff_t)first << PAGE_SHIFT; 122631143d5dSDavid Howells pos += offset; 122731143d5dSDavid Howells 122831143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 122931143d5dSDavid Howells if (pos + size > i_size) 123031143d5dSDavid Howells i_size = size + pos; 123131143d5dSDavid Howells 123231143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 123331143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 123431143d5dSDavid Howells (unsigned long long) i_size); 123531143d5dSDavid Howells 1236b9b1f8d5SDavid Howells if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) 1237b9b1f8d5SDavid Howells return afs_fs_store_data64(server, wb, first, last, offset, to, 1238b9b1f8d5SDavid Howells size, pos, i_size, wait_mode); 123931143d5dSDavid Howells 124031143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData, 124131143d5dSDavid Howells (4 + 6 + 3) * 4, 124231143d5dSDavid Howells (21 + 6) * 4); 124331143d5dSDavid Howells if (!call) 124431143d5dSDavid Howells return -ENOMEM; 124531143d5dSDavid Howells 124631143d5dSDavid Howells call->wb = wb; 124731143d5dSDavid Howells call->key = wb->key; 124831143d5dSDavid Howells call->reply = vnode; 124931143d5dSDavid Howells call->service_id = FS_SERVICE; 125031143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 125131143d5dSDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 125231143d5dSDavid Howells call->first = first; 125331143d5dSDavid Howells call->last = last; 125431143d5dSDavid Howells call->first_offset = offset; 125531143d5dSDavid Howells call->last_to = to; 125631143d5dSDavid Howells call->send_pages = true; 125731143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 125831143d5dSDavid Howells 125931143d5dSDavid Howells /* marshall the parameters */ 126031143d5dSDavid Howells bp = call->request; 126131143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 126231143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 126331143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 126431143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 126531143d5dSDavid Howells 126631143d5dSDavid Howells *bp++ = 0; /* mask */ 126731143d5dSDavid Howells *bp++ = 0; /* mtime */ 126831143d5dSDavid Howells *bp++ = 0; /* owner */ 126931143d5dSDavid Howells *bp++ = 0; /* group */ 127031143d5dSDavid Howells *bp++ = 0; /* unix mode */ 127131143d5dSDavid Howells *bp++ = 0; /* segment size */ 127231143d5dSDavid Howells 127331143d5dSDavid Howells *bp++ = htonl(pos); 127431143d5dSDavid Howells *bp++ = htonl(size); 127531143d5dSDavid Howells *bp++ = htonl(i_size); 127631143d5dSDavid Howells 127731143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 127831143d5dSDavid Howells } 127931143d5dSDavid Howells 128031143d5dSDavid Howells /* 128131143d5dSDavid Howells * deliver reply data to an FS.StoreStatus 128231143d5dSDavid Howells */ 128331143d5dSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call, 128431143d5dSDavid Howells struct sk_buff *skb, bool last) 128531143d5dSDavid Howells { 128631143d5dSDavid Howells afs_dataversion_t *store_version; 128731143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 128831143d5dSDavid Howells const __be32 *bp; 128931143d5dSDavid Howells 129031143d5dSDavid Howells _enter(",,%u", last); 129131143d5dSDavid Howells 129231143d5dSDavid Howells afs_transfer_reply(call, skb); 129331143d5dSDavid Howells if (!last) { 129431143d5dSDavid Howells _leave(" = 0 [more]"); 129531143d5dSDavid Howells return 0; 129631143d5dSDavid Howells } 129731143d5dSDavid Howells 129831143d5dSDavid Howells if (call->reply_size != call->reply_max) { 129931143d5dSDavid Howells _leave(" = -EBADMSG [%u != %u]", 130031143d5dSDavid Howells call->reply_size, call->reply_max); 130131143d5dSDavid Howells return -EBADMSG; 130231143d5dSDavid Howells } 130331143d5dSDavid Howells 130431143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 130531143d5dSDavid Howells store_version = NULL; 130631143d5dSDavid Howells if (call->operation_ID == FSSTOREDATA) 130731143d5dSDavid Howells store_version = &call->store_version; 130831143d5dSDavid Howells 130931143d5dSDavid Howells bp = call->buffer; 131031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); 131131143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 131231143d5dSDavid Howells 131331143d5dSDavid Howells _leave(" = 0 [done]"); 131431143d5dSDavid Howells return 0; 131531143d5dSDavid Howells } 131631143d5dSDavid Howells 131731143d5dSDavid Howells /* 131831143d5dSDavid Howells * FS.StoreStatus operation type 131931143d5dSDavid Howells */ 132031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 132131143d5dSDavid Howells .name = "FS.StoreStatus", 132231143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 132331143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 132431143d5dSDavid Howells .destructor = afs_flat_call_destructor, 132531143d5dSDavid Howells }; 132631143d5dSDavid Howells 132731143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 132831143d5dSDavid Howells .name = "FS.StoreData", 132931143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 133031143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 133131143d5dSDavid Howells .destructor = afs_flat_call_destructor, 133231143d5dSDavid Howells }; 133331143d5dSDavid Howells 1334b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1335b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1336b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_status, 1337b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1338b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1339b9b1f8d5SDavid Howells }; 1340b9b1f8d5SDavid Howells 1341b9b1f8d5SDavid Howells /* 1342b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1343b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1344b9b1f8d5SDavid Howells */ 1345b9b1f8d5SDavid Howells static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, 1346b9b1f8d5SDavid Howells struct afs_vnode *vnode, struct iattr *attr, 1347b9b1f8d5SDavid Howells const struct afs_wait_mode *wait_mode) 1348b9b1f8d5SDavid Howells { 1349b9b1f8d5SDavid Howells struct afs_call *call; 1350b9b1f8d5SDavid Howells __be32 *bp; 1351b9b1f8d5SDavid Howells 1352b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1353b9b1f8d5SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 1354b9b1f8d5SDavid Howells 1355b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1356b9b1f8d5SDavid Howells 1357b9b1f8d5SDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status, 1358b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1359b9b1f8d5SDavid Howells (21 + 6) * 4); 1360b9b1f8d5SDavid Howells if (!call) 1361b9b1f8d5SDavid Howells return -ENOMEM; 1362b9b1f8d5SDavid Howells 1363b9b1f8d5SDavid Howells call->key = key; 1364b9b1f8d5SDavid Howells call->reply = vnode; 1365b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1366b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1367b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1368b9b1f8d5SDavid Howells call->operation_ID = FSSTOREDATA; 1369b9b1f8d5SDavid Howells 1370b9b1f8d5SDavid Howells /* marshall the parameters */ 1371b9b1f8d5SDavid Howells bp = call->request; 1372b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1373b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1374b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1375b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1376b9b1f8d5SDavid Howells 1377b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1378b9b1f8d5SDavid Howells 1379b9b1f8d5SDavid Howells *bp++ = 0; /* position of start of write */ 1380b9b1f8d5SDavid Howells *bp++ = 0; 1381b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1382b9b1f8d5SDavid Howells *bp++ = 0; 1383b9b1f8d5SDavid Howells *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1384b9b1f8d5SDavid Howells *bp++ = htonl((u32) attr->ia_size); 1385b9b1f8d5SDavid Howells 1386b9b1f8d5SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1387b9b1f8d5SDavid Howells } 1388b9b1f8d5SDavid Howells 138931143d5dSDavid Howells /* 139031143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 139131143d5dSDavid Howells * so as to alter the file size also 139231143d5dSDavid Howells */ 139331143d5dSDavid Howells static int afs_fs_setattr_size(struct afs_server *server, struct key *key, 139431143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 139531143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 139631143d5dSDavid Howells { 139731143d5dSDavid Howells struct afs_call *call; 139831143d5dSDavid Howells __be32 *bp; 139931143d5dSDavid Howells 140031143d5dSDavid Howells _enter(",%x,{%x:%u},,", 140131143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 140231143d5dSDavid Howells 140331143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1404b9b1f8d5SDavid Howells if (attr->ia_size >> 32) 1405b9b1f8d5SDavid Howells return afs_fs_setattr_size64(server, key, vnode, attr, 1406b9b1f8d5SDavid Howells wait_mode); 140731143d5dSDavid Howells 140831143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, 140931143d5dSDavid Howells (4 + 6 + 3) * 4, 141031143d5dSDavid Howells (21 + 6) * 4); 141131143d5dSDavid Howells if (!call) 141231143d5dSDavid Howells return -ENOMEM; 141331143d5dSDavid Howells 141431143d5dSDavid Howells call->key = key; 141531143d5dSDavid Howells call->reply = vnode; 141631143d5dSDavid Howells call->service_id = FS_SERVICE; 141731143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 141831143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 141931143d5dSDavid Howells call->operation_ID = FSSTOREDATA; 142031143d5dSDavid Howells 142131143d5dSDavid Howells /* marshall the parameters */ 142231143d5dSDavid Howells bp = call->request; 142331143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 142431143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 142531143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 142631143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 142731143d5dSDavid Howells 142831143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 142931143d5dSDavid Howells 143031143d5dSDavid Howells *bp++ = 0; /* position of start of write */ 143131143d5dSDavid Howells *bp++ = 0; /* size of write */ 143231143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 143331143d5dSDavid Howells 143431143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 143531143d5dSDavid Howells } 143631143d5dSDavid Howells 143731143d5dSDavid Howells /* 143831143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 143931143d5dSDavid Howells * size, and FS.StoreStatus otherwise 144031143d5dSDavid Howells */ 144131143d5dSDavid Howells int afs_fs_setattr(struct afs_server *server, struct key *key, 144231143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 144331143d5dSDavid Howells const struct afs_wait_mode *wait_mode) 144431143d5dSDavid Howells { 144531143d5dSDavid Howells struct afs_call *call; 144631143d5dSDavid Howells __be32 *bp; 144731143d5dSDavid Howells 144831143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 144931143d5dSDavid Howells return afs_fs_setattr_size(server, key, vnode, attr, 145031143d5dSDavid Howells wait_mode); 145131143d5dSDavid Howells 145231143d5dSDavid Howells _enter(",%x,{%x:%u},,", 145331143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 145431143d5dSDavid Howells 145531143d5dSDavid Howells call = afs_alloc_flat_call(&afs_RXFSStoreStatus, 145631143d5dSDavid Howells (4 + 6) * 4, 145731143d5dSDavid Howells (21 + 6) * 4); 145831143d5dSDavid Howells if (!call) 145931143d5dSDavid Howells return -ENOMEM; 146031143d5dSDavid Howells 146131143d5dSDavid Howells call->key = key; 146231143d5dSDavid Howells call->reply = vnode; 146331143d5dSDavid Howells call->service_id = FS_SERVICE; 146431143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 146531143d5dSDavid Howells call->operation_ID = FSSTORESTATUS; 146631143d5dSDavid Howells 146731143d5dSDavid Howells /* marshall the parameters */ 146831143d5dSDavid Howells bp = call->request; 146931143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 147031143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 147131143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 147231143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 147331143d5dSDavid Howells 147431143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 147531143d5dSDavid Howells 147631143d5dSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 147731143d5dSDavid Howells } 147845222b9eSDavid Howells 147945222b9eSDavid Howells /* 148045222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 148145222b9eSDavid Howells */ 148245222b9eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call, 148345222b9eSDavid Howells struct sk_buff *skb, bool last) 148445222b9eSDavid Howells { 148545222b9eSDavid Howells const __be32 *bp; 148645222b9eSDavid Howells char *p; 148745222b9eSDavid Howells int ret; 148845222b9eSDavid Howells 148945222b9eSDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 149045222b9eSDavid Howells 149145222b9eSDavid Howells switch (call->unmarshall) { 149245222b9eSDavid Howells case 0: 149345222b9eSDavid Howells call->offset = 0; 149445222b9eSDavid Howells call->unmarshall++; 149545222b9eSDavid Howells 149645222b9eSDavid Howells /* extract the returned status record */ 149745222b9eSDavid Howells case 1: 149845222b9eSDavid Howells _debug("extract status"); 149945222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 150045222b9eSDavid Howells 12 * 4); 150145222b9eSDavid Howells switch (ret) { 150245222b9eSDavid Howells case 0: break; 150345222b9eSDavid Howells case -EAGAIN: return 0; 150445222b9eSDavid Howells default: return ret; 150545222b9eSDavid Howells } 150645222b9eSDavid Howells 150745222b9eSDavid Howells bp = call->buffer; 150845222b9eSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); 150945222b9eSDavid Howells call->offset = 0; 151045222b9eSDavid Howells call->unmarshall++; 151145222b9eSDavid Howells 151245222b9eSDavid Howells /* extract the volume name length */ 151345222b9eSDavid Howells case 2: 151445222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 151545222b9eSDavid Howells switch (ret) { 151645222b9eSDavid Howells case 0: break; 151745222b9eSDavid Howells case -EAGAIN: return 0; 151845222b9eSDavid Howells default: return ret; 151945222b9eSDavid Howells } 152045222b9eSDavid Howells 152145222b9eSDavid Howells call->count = ntohl(call->tmp); 152245222b9eSDavid Howells _debug("volname length: %u", call->count); 152345222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 152445222b9eSDavid Howells return -EBADMSG; 152545222b9eSDavid Howells call->offset = 0; 152645222b9eSDavid Howells call->unmarshall++; 152745222b9eSDavid Howells 152845222b9eSDavid Howells /* extract the volume name */ 152945222b9eSDavid Howells case 3: 153045222b9eSDavid Howells _debug("extract volname"); 153145222b9eSDavid Howells if (call->count > 0) { 153245222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 153345222b9eSDavid Howells call->count); 153445222b9eSDavid Howells switch (ret) { 153545222b9eSDavid Howells case 0: break; 153645222b9eSDavid Howells case -EAGAIN: return 0; 153745222b9eSDavid Howells default: return ret; 153845222b9eSDavid Howells } 153945222b9eSDavid Howells } 154045222b9eSDavid Howells 154145222b9eSDavid Howells p = call->reply3; 154245222b9eSDavid Howells p[call->count] = 0; 154345222b9eSDavid Howells _debug("volname '%s'", p); 154445222b9eSDavid Howells 154545222b9eSDavid Howells call->offset = 0; 154645222b9eSDavid Howells call->unmarshall++; 154745222b9eSDavid Howells 154845222b9eSDavid Howells /* extract the volume name padding */ 154945222b9eSDavid Howells if ((call->count & 3) == 0) { 155045222b9eSDavid Howells call->unmarshall++; 155145222b9eSDavid Howells goto no_volname_padding; 155245222b9eSDavid Howells } 155345222b9eSDavid Howells call->count = 4 - (call->count & 3); 155445222b9eSDavid Howells 155545222b9eSDavid Howells case 4: 155645222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 155745222b9eSDavid Howells call->count); 155845222b9eSDavid Howells switch (ret) { 155945222b9eSDavid Howells case 0: break; 156045222b9eSDavid Howells case -EAGAIN: return 0; 156145222b9eSDavid Howells default: return ret; 156245222b9eSDavid Howells } 156345222b9eSDavid Howells 156445222b9eSDavid Howells call->offset = 0; 156545222b9eSDavid Howells call->unmarshall++; 156645222b9eSDavid Howells no_volname_padding: 156745222b9eSDavid Howells 156845222b9eSDavid Howells /* extract the offline message length */ 156945222b9eSDavid Howells case 5: 157045222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 157145222b9eSDavid Howells switch (ret) { 157245222b9eSDavid Howells case 0: break; 157345222b9eSDavid Howells case -EAGAIN: return 0; 157445222b9eSDavid Howells default: return ret; 157545222b9eSDavid Howells } 157645222b9eSDavid Howells 157745222b9eSDavid Howells call->count = ntohl(call->tmp); 157845222b9eSDavid Howells _debug("offline msg length: %u", call->count); 157945222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 158045222b9eSDavid Howells return -EBADMSG; 158145222b9eSDavid Howells call->offset = 0; 158245222b9eSDavid Howells call->unmarshall++; 158345222b9eSDavid Howells 158445222b9eSDavid Howells /* extract the offline message */ 158545222b9eSDavid Howells case 6: 158645222b9eSDavid Howells _debug("extract offline"); 158745222b9eSDavid Howells if (call->count > 0) { 158845222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 158945222b9eSDavid Howells call->count); 159045222b9eSDavid Howells switch (ret) { 159145222b9eSDavid Howells case 0: break; 159245222b9eSDavid Howells case -EAGAIN: return 0; 159345222b9eSDavid Howells default: return ret; 159445222b9eSDavid Howells } 159545222b9eSDavid Howells } 159645222b9eSDavid Howells 159745222b9eSDavid Howells p = call->reply3; 159845222b9eSDavid Howells p[call->count] = 0; 159945222b9eSDavid Howells _debug("offline '%s'", p); 160045222b9eSDavid Howells 160145222b9eSDavid Howells call->offset = 0; 160245222b9eSDavid Howells call->unmarshall++; 160345222b9eSDavid Howells 160445222b9eSDavid Howells /* extract the offline message padding */ 160545222b9eSDavid Howells if ((call->count & 3) == 0) { 160645222b9eSDavid Howells call->unmarshall++; 160745222b9eSDavid Howells goto no_offline_padding; 160845222b9eSDavid Howells } 160945222b9eSDavid Howells call->count = 4 - (call->count & 3); 161045222b9eSDavid Howells 161145222b9eSDavid Howells case 7: 161245222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 161345222b9eSDavid Howells call->count); 161445222b9eSDavid Howells switch (ret) { 161545222b9eSDavid Howells case 0: break; 161645222b9eSDavid Howells case -EAGAIN: return 0; 161745222b9eSDavid Howells default: return ret; 161845222b9eSDavid Howells } 161945222b9eSDavid Howells 162045222b9eSDavid Howells call->offset = 0; 162145222b9eSDavid Howells call->unmarshall++; 162245222b9eSDavid Howells no_offline_padding: 162345222b9eSDavid Howells 162445222b9eSDavid Howells /* extract the message of the day length */ 162545222b9eSDavid Howells case 8: 162645222b9eSDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 162745222b9eSDavid Howells switch (ret) { 162845222b9eSDavid Howells case 0: break; 162945222b9eSDavid Howells case -EAGAIN: return 0; 163045222b9eSDavid Howells default: return ret; 163145222b9eSDavid Howells } 163245222b9eSDavid Howells 163345222b9eSDavid Howells call->count = ntohl(call->tmp); 163445222b9eSDavid Howells _debug("motd length: %u", call->count); 163545222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 163645222b9eSDavid Howells return -EBADMSG; 163745222b9eSDavid Howells call->offset = 0; 163845222b9eSDavid Howells call->unmarshall++; 163945222b9eSDavid Howells 164045222b9eSDavid Howells /* extract the message of the day */ 164145222b9eSDavid Howells case 9: 164245222b9eSDavid Howells _debug("extract motd"); 164345222b9eSDavid Howells if (call->count > 0) { 164445222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->reply3, 164545222b9eSDavid Howells call->count); 164645222b9eSDavid Howells switch (ret) { 164745222b9eSDavid Howells case 0: break; 164845222b9eSDavid Howells case -EAGAIN: return 0; 164945222b9eSDavid Howells default: return ret; 165045222b9eSDavid Howells } 165145222b9eSDavid Howells } 165245222b9eSDavid Howells 165345222b9eSDavid Howells p = call->reply3; 165445222b9eSDavid Howells p[call->count] = 0; 165545222b9eSDavid Howells _debug("motd '%s'", p); 165645222b9eSDavid Howells 165745222b9eSDavid Howells call->offset = 0; 165845222b9eSDavid Howells call->unmarshall++; 165945222b9eSDavid Howells 166045222b9eSDavid Howells /* extract the message of the day padding */ 166145222b9eSDavid Howells if ((call->count & 3) == 0) { 166245222b9eSDavid Howells call->unmarshall++; 166345222b9eSDavid Howells goto no_motd_padding; 166445222b9eSDavid Howells } 166545222b9eSDavid Howells call->count = 4 - (call->count & 3); 166645222b9eSDavid Howells 166745222b9eSDavid Howells case 10: 166845222b9eSDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 166945222b9eSDavid Howells call->count); 167045222b9eSDavid Howells switch (ret) { 167145222b9eSDavid Howells case 0: break; 167245222b9eSDavid Howells case -EAGAIN: return 0; 167345222b9eSDavid Howells default: return ret; 167445222b9eSDavid Howells } 167545222b9eSDavid Howells 167645222b9eSDavid Howells call->offset = 0; 167745222b9eSDavid Howells call->unmarshall++; 167845222b9eSDavid Howells no_motd_padding: 167945222b9eSDavid Howells 168045222b9eSDavid Howells case 11: 168145222b9eSDavid Howells _debug("trailer %d", skb->len); 168245222b9eSDavid Howells if (skb->len != 0) 168345222b9eSDavid Howells return -EBADMSG; 168445222b9eSDavid Howells break; 168545222b9eSDavid Howells } 168645222b9eSDavid Howells 168745222b9eSDavid Howells if (!last) 168845222b9eSDavid Howells return 0; 168945222b9eSDavid Howells 169045222b9eSDavid Howells _leave(" = 0 [done]"); 169145222b9eSDavid Howells return 0; 169245222b9eSDavid Howells } 169345222b9eSDavid Howells 169445222b9eSDavid Howells /* 169545222b9eSDavid Howells * destroy an FS.GetVolumeStatus call 169645222b9eSDavid Howells */ 169745222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call) 169845222b9eSDavid Howells { 169945222b9eSDavid Howells kfree(call->reply3); 170045222b9eSDavid Howells call->reply3 = NULL; 170145222b9eSDavid Howells afs_flat_call_destructor(call); 170245222b9eSDavid Howells } 170345222b9eSDavid Howells 170445222b9eSDavid Howells /* 170545222b9eSDavid Howells * FS.GetVolumeStatus operation type 170645222b9eSDavid Howells */ 170745222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 170845222b9eSDavid Howells .name = "FS.GetVolumeStatus", 170945222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 171045222b9eSDavid Howells .abort_to_error = afs_abort_to_error, 171145222b9eSDavid Howells .destructor = afs_get_volume_status_call_destructor, 171245222b9eSDavid Howells }; 171345222b9eSDavid Howells 171445222b9eSDavid Howells /* 171545222b9eSDavid Howells * fetch the status of a volume 171645222b9eSDavid Howells */ 171745222b9eSDavid Howells int afs_fs_get_volume_status(struct afs_server *server, 171845222b9eSDavid Howells struct key *key, 171945222b9eSDavid Howells struct afs_vnode *vnode, 172045222b9eSDavid Howells struct afs_volume_status *vs, 172145222b9eSDavid Howells const struct afs_wait_mode *wait_mode) 172245222b9eSDavid Howells { 172345222b9eSDavid Howells struct afs_call *call; 172445222b9eSDavid Howells __be32 *bp; 172545222b9eSDavid Howells void *tmpbuf; 172645222b9eSDavid Howells 172745222b9eSDavid Howells _enter(""); 172845222b9eSDavid Howells 172945222b9eSDavid Howells tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); 173045222b9eSDavid Howells if (!tmpbuf) 173145222b9eSDavid Howells return -ENOMEM; 173245222b9eSDavid Howells 173345222b9eSDavid Howells call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); 173445222b9eSDavid Howells if (!call) { 173545222b9eSDavid Howells kfree(tmpbuf); 173645222b9eSDavid Howells return -ENOMEM; 173745222b9eSDavid Howells } 173845222b9eSDavid Howells 173945222b9eSDavid Howells call->key = key; 174045222b9eSDavid Howells call->reply = vnode; 174145222b9eSDavid Howells call->reply2 = vs; 174245222b9eSDavid Howells call->reply3 = tmpbuf; 174345222b9eSDavid Howells call->service_id = FS_SERVICE; 174445222b9eSDavid Howells call->port = htons(AFS_FS_PORT); 174545222b9eSDavid Howells 174645222b9eSDavid Howells /* marshall the parameters */ 174745222b9eSDavid Howells bp = call->request; 174845222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 174945222b9eSDavid Howells bp[1] = htonl(vnode->fid.vid); 175045222b9eSDavid Howells 175145222b9eSDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 175245222b9eSDavid Howells } 1753e8d6c554SDavid Howells 1754e8d6c554SDavid Howells /* 1755e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1756e8d6c554SDavid Howells */ 1757e8d6c554SDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call, 1758e8d6c554SDavid Howells struct sk_buff *skb, bool last) 1759e8d6c554SDavid Howells { 1760e8d6c554SDavid Howells const __be32 *bp; 1761e8d6c554SDavid Howells 1762e8d6c554SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 1763e8d6c554SDavid Howells 1764e8d6c554SDavid Howells afs_transfer_reply(call, skb); 1765e8d6c554SDavid Howells if (!last) 1766e8d6c554SDavid Howells return 0; 1767e8d6c554SDavid Howells 1768e8d6c554SDavid Howells if (call->reply_size != call->reply_max) 1769e8d6c554SDavid Howells return -EBADMSG; 1770e8d6c554SDavid Howells 1771e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1772e8d6c554SDavid Howells bp = call->buffer; 1773e8d6c554SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1774e8d6c554SDavid Howells 1775e8d6c554SDavid Howells _leave(" = 0 [done]"); 1776e8d6c554SDavid Howells return 0; 1777e8d6c554SDavid Howells } 1778e8d6c554SDavid Howells 1779e8d6c554SDavid Howells /* 1780e8d6c554SDavid Howells * FS.SetLock operation type 1781e8d6c554SDavid Howells */ 1782e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1783e8d6c554SDavid Howells .name = "FS.SetLock", 1784e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1785e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1786e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1787e8d6c554SDavid Howells }; 1788e8d6c554SDavid Howells 1789e8d6c554SDavid Howells /* 1790e8d6c554SDavid Howells * FS.ExtendLock operation type 1791e8d6c554SDavid Howells */ 1792e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1793e8d6c554SDavid Howells .name = "FS.ExtendLock", 1794e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1795e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1796e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1797e8d6c554SDavid Howells }; 1798e8d6c554SDavid Howells 1799e8d6c554SDavid Howells /* 1800e8d6c554SDavid Howells * FS.ReleaseLock operation type 1801e8d6c554SDavid Howells */ 1802e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1803e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1804e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1805e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1806e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1807e8d6c554SDavid Howells }; 1808e8d6c554SDavid Howells 1809e8d6c554SDavid Howells /* 1810e8d6c554SDavid Howells * get a lock on a file 1811e8d6c554SDavid Howells */ 1812e8d6c554SDavid Howells int afs_fs_set_lock(struct afs_server *server, 1813e8d6c554SDavid Howells struct key *key, 1814e8d6c554SDavid Howells struct afs_vnode *vnode, 1815e8d6c554SDavid Howells afs_lock_type_t type, 1816e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1817e8d6c554SDavid Howells { 1818e8d6c554SDavid Howells struct afs_call *call; 1819e8d6c554SDavid Howells __be32 *bp; 1820e8d6c554SDavid Howells 1821e8d6c554SDavid Howells _enter(""); 1822e8d6c554SDavid Howells 1823e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4); 1824e8d6c554SDavid Howells if (!call) 1825e8d6c554SDavid Howells return -ENOMEM; 1826e8d6c554SDavid Howells 1827e8d6c554SDavid Howells call->key = key; 1828e8d6c554SDavid Howells call->reply = vnode; 1829e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1830e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1831e8d6c554SDavid Howells 1832e8d6c554SDavid Howells /* marshall the parameters */ 1833e8d6c554SDavid Howells bp = call->request; 1834e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1835e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1836e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1837e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1838e8d6c554SDavid Howells *bp++ = htonl(type); 1839e8d6c554SDavid Howells 1840e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1841e8d6c554SDavid Howells } 1842e8d6c554SDavid Howells 1843e8d6c554SDavid Howells /* 1844e8d6c554SDavid Howells * extend a lock on a file 1845e8d6c554SDavid Howells */ 1846e8d6c554SDavid Howells int afs_fs_extend_lock(struct afs_server *server, 1847e8d6c554SDavid Howells struct key *key, 1848e8d6c554SDavid Howells struct afs_vnode *vnode, 1849e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1850e8d6c554SDavid Howells { 1851e8d6c554SDavid Howells struct afs_call *call; 1852e8d6c554SDavid Howells __be32 *bp; 1853e8d6c554SDavid Howells 1854e8d6c554SDavid Howells _enter(""); 1855e8d6c554SDavid Howells 1856e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4); 1857e8d6c554SDavid Howells if (!call) 1858e8d6c554SDavid Howells return -ENOMEM; 1859e8d6c554SDavid Howells 1860e8d6c554SDavid Howells call->key = key; 1861e8d6c554SDavid Howells call->reply = vnode; 1862e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1863e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1864e8d6c554SDavid Howells 1865e8d6c554SDavid Howells /* marshall the parameters */ 1866e8d6c554SDavid Howells bp = call->request; 1867e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1868e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1869e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1870e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1871e8d6c554SDavid Howells 1872e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1873e8d6c554SDavid Howells } 1874e8d6c554SDavid Howells 1875e8d6c554SDavid Howells /* 1876e8d6c554SDavid Howells * release a lock on a file 1877e8d6c554SDavid Howells */ 1878e8d6c554SDavid Howells int afs_fs_release_lock(struct afs_server *server, 1879e8d6c554SDavid Howells struct key *key, 1880e8d6c554SDavid Howells struct afs_vnode *vnode, 1881e8d6c554SDavid Howells const struct afs_wait_mode *wait_mode) 1882e8d6c554SDavid Howells { 1883e8d6c554SDavid Howells struct afs_call *call; 1884e8d6c554SDavid Howells __be32 *bp; 1885e8d6c554SDavid Howells 1886e8d6c554SDavid Howells _enter(""); 1887e8d6c554SDavid Howells 1888e8d6c554SDavid Howells call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1889e8d6c554SDavid Howells if (!call) 1890e8d6c554SDavid Howells return -ENOMEM; 1891e8d6c554SDavid Howells 1892e8d6c554SDavid Howells call->key = key; 1893e8d6c554SDavid Howells call->reply = vnode; 1894e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1895e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1896e8d6c554SDavid Howells 1897e8d6c554SDavid Howells /* marshall the parameters */ 1898e8d6c554SDavid Howells bp = call->request; 1899e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1900e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1901e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1902e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1903e8d6c554SDavid Howells 1904e8d6c554SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 1905e8d6c554SDavid Howells } 1906