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 /* 206db3ac3cSDavid Howells * We need somewhere to discard into in case the server helpfully returns more 216db3ac3cSDavid Howells * than we asked for in FS.FetchData{,64}. 226db3ac3cSDavid Howells */ 236db3ac3cSDavid Howells static u8 afs_discard_buffer[64]; 246db3ac3cSDavid Howells 256db3ac3cSDavid Howells /* 26260a9803SDavid Howells * decode an AFSFid block 27260a9803SDavid Howells */ 28260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 29260a9803SDavid Howells { 30260a9803SDavid Howells const __be32 *bp = *_bp; 31260a9803SDavid Howells 32260a9803SDavid Howells fid->vid = ntohl(*bp++); 33260a9803SDavid Howells fid->vnode = ntohl(*bp++); 34260a9803SDavid Howells fid->unique = ntohl(*bp++); 35260a9803SDavid Howells *_bp = bp; 36260a9803SDavid Howells } 37260a9803SDavid Howells 38260a9803SDavid Howells /* 3908e0e7c8SDavid Howells * decode an AFSFetchStatus block 401da177e4SLinus Torvalds */ 4108e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 42260a9803SDavid Howells struct afs_file_status *status, 4331143d5dSDavid Howells struct afs_vnode *vnode, 4431143d5dSDavid Howells afs_dataversion_t *store_version) 451da177e4SLinus Torvalds { 4631143d5dSDavid Howells afs_dataversion_t expected_version; 4708e0e7c8SDavid Howells const __be32 *bp = *_bp; 4808e0e7c8SDavid Howells umode_t mode; 49260a9803SDavid Howells u64 data_version, size; 5008e0e7c8SDavid Howells u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ 51a0a5386aSEric W. Biederman kuid_t owner; 52a0a5386aSEric W. Biederman kgid_t group; 5308e0e7c8SDavid Howells 5408e0e7c8SDavid Howells #define EXTRACT(DST) \ 5508e0e7c8SDavid Howells do { \ 5608e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 5708e0e7c8SDavid Howells changed |= DST - x; \ 5808e0e7c8SDavid Howells DST = x; \ 5908e0e7c8SDavid Howells } while (0) 6008e0e7c8SDavid Howells 61260a9803SDavid Howells status->if_version = ntohl(*bp++); 62260a9803SDavid Howells EXTRACT(status->type); 63260a9803SDavid Howells EXTRACT(status->nlink); 64260a9803SDavid Howells size = ntohl(*bp++); 6508e0e7c8SDavid Howells data_version = ntohl(*bp++); 66260a9803SDavid Howells EXTRACT(status->author); 67a0a5386aSEric W. Biederman owner = make_kuid(&init_user_ns, ntohl(*bp++)); 68a0a5386aSEric W. Biederman changed |= !uid_eq(owner, status->owner); 69a0a5386aSEric W. Biederman status->owner = owner; 70260a9803SDavid Howells EXTRACT(status->caller_access); /* call ticket dependent */ 71260a9803SDavid Howells EXTRACT(status->anon_access); 72260a9803SDavid Howells EXTRACT(status->mode); 73260a9803SDavid Howells EXTRACT(status->parent.vnode); 74260a9803SDavid Howells EXTRACT(status->parent.unique); 7508e0e7c8SDavid Howells bp++; /* seg size */ 76260a9803SDavid Howells status->mtime_client = ntohl(*bp++); 77260a9803SDavid Howells status->mtime_server = ntohl(*bp++); 78a0a5386aSEric W. Biederman group = make_kgid(&init_user_ns, ntohl(*bp++)); 79a0a5386aSEric W. Biederman changed |= !gid_eq(group, status->group); 80a0a5386aSEric W. Biederman status->group = group; 8108e0e7c8SDavid Howells bp++; /* sync counter */ 8208e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 83e8d6c554SDavid Howells EXTRACT(status->lock_count); 84260a9803SDavid Howells size |= (u64) ntohl(*bp++) << 32; 8508e0e7c8SDavid Howells bp++; /* spare 4 */ 8608e0e7c8SDavid Howells *_bp = bp; 8708e0e7c8SDavid Howells 88260a9803SDavid Howells if (size != status->size) { 89260a9803SDavid Howells status->size = size; 90260a9803SDavid Howells changed |= true; 91260a9803SDavid Howells } 92260a9803SDavid Howells status->mode &= S_IALLUGO; 9308e0e7c8SDavid Howells 94260a9803SDavid Howells _debug("vnode time %lx, %lx", 95260a9803SDavid Howells status->mtime_client, status->mtime_server); 96260a9803SDavid Howells 97260a9803SDavid Howells if (vnode) { 98260a9803SDavid Howells status->parent.vid = vnode->fid.vid; 99260a9803SDavid Howells if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 100260a9803SDavid Howells _debug("vnode changed"); 101260a9803SDavid Howells i_size_write(&vnode->vfs_inode, size); 102260a9803SDavid Howells vnode->vfs_inode.i_uid = status->owner; 103260a9803SDavid Howells vnode->vfs_inode.i_gid = status->group; 104d6e43f75SDavid Howells vnode->vfs_inode.i_generation = vnode->fid.unique; 105bfe86848SMiklos Szeredi set_nlink(&vnode->vfs_inode, status->nlink); 106260a9803SDavid Howells 10708e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 10808e0e7c8SDavid Howells mode &= ~S_IALLUGO; 109260a9803SDavid Howells mode |= status->mode; 110260a9803SDavid Howells barrier(); 11108e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 11208e0e7c8SDavid Howells } 11308e0e7c8SDavid Howells 114ab94f5d0SMarc Dionne vnode->vfs_inode.i_ctime.tv_sec = status->mtime_client; 11508e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 11608e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 117d6e43f75SDavid Howells vnode->vfs_inode.i_version = data_version; 118260a9803SDavid Howells } 11908e0e7c8SDavid Howells 12031143d5dSDavid Howells expected_version = status->data_version; 12131143d5dSDavid Howells if (store_version) 12231143d5dSDavid Howells expected_version = *store_version; 12331143d5dSDavid Howells 12431143d5dSDavid Howells if (expected_version != data_version) { 125260a9803SDavid Howells status->data_version = data_version; 126260a9803SDavid Howells if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 127260a9803SDavid Howells _debug("vnode modified %llx on {%x:%u}", 128ba3e0e1aSDavid S. Miller (unsigned long long) data_version, 129ba3e0e1aSDavid S. Miller vnode->fid.vid, vnode->fid.vnode); 13008e0e7c8SDavid Howells set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 13108e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1321da177e4SLinus Torvalds } 13331143d5dSDavid Howells } else if (store_version) { 13431143d5dSDavid Howells status->data_version = data_version; 135ec26815aSDavid Howells } 136260a9803SDavid Howells } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* 13908e0e7c8SDavid Howells * decode an AFSCallBack block 1401da177e4SLinus Torvalds */ 14108e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) 1421da177e4SLinus Torvalds { 14308e0e7c8SDavid Howells const __be32 *bp = *_bp; 1441da177e4SLinus Torvalds 14508e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 14608e0e7c8SDavid Howells vnode->cb_expiry = ntohl(*bp++); 14708e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 14856e71431STina Ruchandani vnode->cb_expires = vnode->cb_expiry + ktime_get_real_seconds(); 14908e0e7c8SDavid Howells *_bp = bp; 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 152260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 153260a9803SDavid Howells struct afs_callback *cb) 154260a9803SDavid Howells { 155260a9803SDavid Howells const __be32 *bp = *_bp; 156260a9803SDavid Howells 157260a9803SDavid Howells cb->version = ntohl(*bp++); 158260a9803SDavid Howells cb->expiry = ntohl(*bp++); 159260a9803SDavid Howells cb->type = ntohl(*bp++); 160260a9803SDavid Howells *_bp = bp; 161260a9803SDavid Howells } 162260a9803SDavid Howells 1631da177e4SLinus Torvalds /* 16408e0e7c8SDavid Howells * decode an AFSVolSync block 1651da177e4SLinus Torvalds */ 16608e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 16708e0e7c8SDavid Howells struct afs_volsync *volsync) 1681da177e4SLinus Torvalds { 16908e0e7c8SDavid Howells const __be32 *bp = *_bp; 1701da177e4SLinus Torvalds 17108e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 17208e0e7c8SDavid Howells bp++; /* spare2 */ 17308e0e7c8SDavid Howells bp++; /* spare3 */ 17408e0e7c8SDavid Howells bp++; /* spare4 */ 17508e0e7c8SDavid Howells bp++; /* spare5 */ 17608e0e7c8SDavid Howells bp++; /* spare6 */ 17708e0e7c8SDavid Howells *_bp = bp; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 18008e0e7c8SDavid Howells /* 18131143d5dSDavid Howells * encode the requested attributes into an AFSStoreStatus block 18231143d5dSDavid Howells */ 18331143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) 18431143d5dSDavid Howells { 18531143d5dSDavid Howells __be32 *bp = *_bp; 18631143d5dSDavid Howells u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; 18731143d5dSDavid Howells 18831143d5dSDavid Howells mask = 0; 18931143d5dSDavid Howells if (attr->ia_valid & ATTR_MTIME) { 19031143d5dSDavid Howells mask |= AFS_SET_MTIME; 19131143d5dSDavid Howells mtime = attr->ia_mtime.tv_sec; 19231143d5dSDavid Howells } 19331143d5dSDavid Howells 19431143d5dSDavid Howells if (attr->ia_valid & ATTR_UID) { 19531143d5dSDavid Howells mask |= AFS_SET_OWNER; 196a0a5386aSEric W. Biederman owner = from_kuid(&init_user_ns, attr->ia_uid); 19731143d5dSDavid Howells } 19831143d5dSDavid Howells 19931143d5dSDavid Howells if (attr->ia_valid & ATTR_GID) { 20031143d5dSDavid Howells mask |= AFS_SET_GROUP; 201a0a5386aSEric W. Biederman group = from_kgid(&init_user_ns, attr->ia_gid); 20231143d5dSDavid Howells } 20331143d5dSDavid Howells 20431143d5dSDavid Howells if (attr->ia_valid & ATTR_MODE) { 20531143d5dSDavid Howells mask |= AFS_SET_MODE; 20631143d5dSDavid Howells mode = attr->ia_mode & S_IALLUGO; 20731143d5dSDavid Howells } 20831143d5dSDavid Howells 20931143d5dSDavid Howells *bp++ = htonl(mask); 21031143d5dSDavid Howells *bp++ = htonl(mtime); 21131143d5dSDavid Howells *bp++ = htonl(owner); 21231143d5dSDavid Howells *bp++ = htonl(group); 21331143d5dSDavid Howells *bp++ = htonl(mode); 21431143d5dSDavid Howells *bp++ = 0; /* segment size */ 21531143d5dSDavid Howells *_bp = bp; 21631143d5dSDavid Howells } 21731143d5dSDavid Howells 21831143d5dSDavid Howells /* 21945222b9eSDavid Howells * decode an AFSFetchVolumeStatus block 22045222b9eSDavid Howells */ 22145222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, 22245222b9eSDavid Howells struct afs_volume_status *vs) 22345222b9eSDavid Howells { 22445222b9eSDavid Howells const __be32 *bp = *_bp; 22545222b9eSDavid Howells 22645222b9eSDavid Howells vs->vid = ntohl(*bp++); 22745222b9eSDavid Howells vs->parent_id = ntohl(*bp++); 22845222b9eSDavid Howells vs->online = ntohl(*bp++); 22945222b9eSDavid Howells vs->in_service = ntohl(*bp++); 23045222b9eSDavid Howells vs->blessed = ntohl(*bp++); 23145222b9eSDavid Howells vs->needs_salvage = ntohl(*bp++); 23245222b9eSDavid Howells vs->type = ntohl(*bp++); 23345222b9eSDavid Howells vs->min_quota = ntohl(*bp++); 23445222b9eSDavid Howells vs->max_quota = ntohl(*bp++); 23545222b9eSDavid Howells vs->blocks_in_use = ntohl(*bp++); 23645222b9eSDavid Howells vs->part_blocks_avail = ntohl(*bp++); 23745222b9eSDavid Howells vs->part_max_blocks = ntohl(*bp++); 23845222b9eSDavid Howells *_bp = bp; 23945222b9eSDavid Howells } 24045222b9eSDavid Howells 24145222b9eSDavid Howells /* 24208e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 24308e0e7c8SDavid Howells */ 244d001648eSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call) 24508e0e7c8SDavid Howells { 246260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 24708e0e7c8SDavid Howells const __be32 *bp; 248372ee163SDavid Howells int ret; 2491da177e4SLinus Torvalds 250d001648eSDavid Howells _enter(""); 2511da177e4SLinus Torvalds 252d001648eSDavid Howells ret = afs_transfer_reply(call); 253372ee163SDavid Howells if (ret < 0) 254372ee163SDavid Howells return ret; 2551da177e4SLinus Torvalds 25608e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 25708e0e7c8SDavid Howells bp = call->buffer; 25831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 259260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 26008e0e7c8SDavid Howells if (call->reply2) 26108e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 2621da177e4SLinus Torvalds 26308e0e7c8SDavid Howells _leave(" = 0 [done]"); 26408e0e7c8SDavid Howells return 0; 265ec26815aSDavid Howells } 26608e0e7c8SDavid Howells 26708e0e7c8SDavid Howells /* 26808e0e7c8SDavid Howells * FS.FetchStatus operation type 26908e0e7c8SDavid Howells */ 27008e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 27100d3b7a4SDavid Howells .name = "FS.FetchStatus", 27208e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 27308e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 27408e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 27508e0e7c8SDavid Howells }; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* 2781da177e4SLinus Torvalds * fetch the status information for a file 2791da177e4SLinus Torvalds */ 28008e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server, 28100d3b7a4SDavid Howells struct key *key, 2821da177e4SLinus Torvalds struct afs_vnode *vnode, 28308e0e7c8SDavid Howells struct afs_volsync *volsync, 28456ff9c83SDavid Howells bool async) 2851da177e4SLinus Torvalds { 28608e0e7c8SDavid Howells struct afs_call *call; 287f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 2881da177e4SLinus Torvalds __be32 *bp; 2891da177e4SLinus Torvalds 290416351f2SDavid Howells _enter(",%x,{%x:%u},,", 291260a9803SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 2921da177e4SLinus Torvalds 293f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 29408e0e7c8SDavid Howells if (!call) 29508e0e7c8SDavid Howells return -ENOMEM; 2961da177e4SLinus Torvalds 29700d3b7a4SDavid Howells call->key = key; 29808e0e7c8SDavid Howells call->reply = vnode; 29908e0e7c8SDavid Howells call->reply2 = volsync; 30008e0e7c8SDavid Howells call->service_id = FS_SERVICE; 30108e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds /* marshall the parameters */ 30408e0e7c8SDavid Howells bp = call->request; 3051da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 3061da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 3071da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 3081da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 3091da177e4SLinus Torvalds 31056ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 311ec26815aSDavid Howells } 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds /* 31408e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 3151da177e4SLinus Torvalds */ 316d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call) 3171da177e4SLinus Torvalds { 318260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 319196ee9cdSDavid Howells struct afs_read *req = call->reply3; 32008e0e7c8SDavid Howells const __be32 *bp; 321196ee9cdSDavid Howells unsigned int size; 32208e0e7c8SDavid Howells void *buffer; 3231da177e4SLinus Torvalds int ret; 3241da177e4SLinus Torvalds 3256a0e3999SDavid Howells _enter("{%u,%zu/%u;%llu/%llu}", 326196ee9cdSDavid Howells call->unmarshall, call->offset, call->count, 327196ee9cdSDavid Howells req->remain, req->actual_len); 3281da177e4SLinus Torvalds 32908e0e7c8SDavid Howells switch (call->unmarshall) { 33008e0e7c8SDavid Howells case 0: 331196ee9cdSDavid Howells req->actual_len = 0; 33208e0e7c8SDavid Howells call->offset = 0; 33308e0e7c8SDavid Howells call->unmarshall++; 334b9b1f8d5SDavid Howells if (call->operation_ID != FSFETCHDATA64) { 335b9b1f8d5SDavid Howells call->unmarshall++; 336b9b1f8d5SDavid Howells goto no_msw; 337b9b1f8d5SDavid Howells } 3381da177e4SLinus Torvalds 339b9b1f8d5SDavid Howells /* extract the upper part of the returned data length of an 340b9b1f8d5SDavid Howells * FSFETCHDATA64 op (which should always be 0 using this 341b9b1f8d5SDavid Howells * client) */ 34208e0e7c8SDavid Howells case 1: 343b9b1f8d5SDavid Howells _debug("extract data length (MSW)"); 344d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 345372ee163SDavid Howells if (ret < 0) 346372ee163SDavid Howells return ret; 347b9b1f8d5SDavid Howells 348196ee9cdSDavid Howells req->actual_len = ntohl(call->tmp); 349196ee9cdSDavid Howells req->actual_len <<= 32; 350b9b1f8d5SDavid Howells call->offset = 0; 351b9b1f8d5SDavid Howells call->unmarshall++; 352b9b1f8d5SDavid Howells 353b9b1f8d5SDavid Howells no_msw: 354b9b1f8d5SDavid Howells /* extract the returned data length */ 355b9b1f8d5SDavid Howells case 2: 35608e0e7c8SDavid Howells _debug("extract data length"); 357d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 358372ee163SDavid Howells if (ret < 0) 359372ee163SDavid Howells return ret; 3601da177e4SLinus Torvalds 361196ee9cdSDavid Howells req->actual_len |= ntohl(call->tmp); 362196ee9cdSDavid Howells _debug("DATA length: %llu", req->actual_len); 363196ee9cdSDavid Howells 364196ee9cdSDavid Howells req->remain = req->actual_len; 365196ee9cdSDavid Howells call->offset = req->pos & (PAGE_SIZE - 1); 366196ee9cdSDavid Howells req->index = 0; 367196ee9cdSDavid Howells if (req->actual_len == 0) 368196ee9cdSDavid Howells goto no_more_data; 36908e0e7c8SDavid Howells call->unmarshall++; 3701da177e4SLinus Torvalds 371196ee9cdSDavid Howells begin_page: 3726db3ac3cSDavid Howells ASSERTCMP(req->index, <, req->nr_pages); 373196ee9cdSDavid Howells if (req->remain > PAGE_SIZE - call->offset) 374196ee9cdSDavid Howells size = PAGE_SIZE - call->offset; 375196ee9cdSDavid Howells else 376196ee9cdSDavid Howells size = req->remain; 377196ee9cdSDavid Howells call->count = call->offset + size; 378196ee9cdSDavid Howells ASSERTCMP(call->count, <=, PAGE_SIZE); 379196ee9cdSDavid Howells req->remain -= size; 380196ee9cdSDavid Howells 38108e0e7c8SDavid Howells /* extract the returned data */ 382b9b1f8d5SDavid Howells case 3: 3836a0e3999SDavid Howells _debug("extract data %llu/%llu %zu/%u", 384196ee9cdSDavid Howells req->remain, req->actual_len, call->offset, call->count); 385196ee9cdSDavid Howells 386196ee9cdSDavid Howells buffer = kmap(req->pages[req->index]); 387196ee9cdSDavid Howells ret = afs_extract_data(call, buffer, call->count, true); 388196ee9cdSDavid Howells kunmap(req->pages[req->index]); 389372ee163SDavid Howells if (ret < 0) 390372ee163SDavid Howells return ret; 391196ee9cdSDavid Howells if (call->offset == PAGE_SIZE) { 392196ee9cdSDavid Howells if (req->page_done) 393196ee9cdSDavid Howells req->page_done(call, req); 39429f06985SDavid Howells req->index++; 395196ee9cdSDavid Howells if (req->remain > 0) { 396196ee9cdSDavid Howells call->offset = 0; 397e8e581a8SDavid Howells if (req->index >= req->nr_pages) { 398e8e581a8SDavid Howells call->unmarshall = 4; 3996db3ac3cSDavid Howells goto begin_discard; 400e8e581a8SDavid Howells } 401196ee9cdSDavid Howells goto begin_page; 402196ee9cdSDavid Howells } 403416351f2SDavid Howells } 4046db3ac3cSDavid Howells goto no_more_data; 4056db3ac3cSDavid Howells 4066db3ac3cSDavid Howells /* Discard any excess data the server gave us */ 4076db3ac3cSDavid Howells begin_discard: 4086db3ac3cSDavid Howells case 4: 4096a0e3999SDavid Howells size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain); 4106db3ac3cSDavid Howells call->count = size; 4116a0e3999SDavid Howells _debug("extract discard %llu/%llu %zu/%u", 4126db3ac3cSDavid Howells req->remain, req->actual_len, call->offset, call->count); 4136db3ac3cSDavid Howells 4146db3ac3cSDavid Howells call->offset = 0; 4156db3ac3cSDavid Howells ret = afs_extract_data(call, afs_discard_buffer, call->count, true); 4166db3ac3cSDavid Howells req->remain -= call->offset; 4176db3ac3cSDavid Howells if (ret < 0) 4186db3ac3cSDavid Howells return ret; 4196db3ac3cSDavid Howells if (req->remain > 0) 4206db3ac3cSDavid Howells goto begin_discard; 4211da177e4SLinus Torvalds 422196ee9cdSDavid Howells no_more_data: 42308e0e7c8SDavid Howells call->offset = 0; 4246db3ac3cSDavid Howells call->unmarshall = 5; 42508e0e7c8SDavid Howells 42608e0e7c8SDavid Howells /* extract the metadata */ 4276db3ac3cSDavid Howells case 5: 428d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 429d001648eSDavid Howells (21 + 3 + 6) * 4, false); 430372ee163SDavid Howells if (ret < 0) 431372ee163SDavid Howells return ret; 4321da177e4SLinus Torvalds 43308e0e7c8SDavid Howells bp = call->buffer; 43431143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 435260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 43608e0e7c8SDavid Howells if (call->reply2) 43708e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 4381da177e4SLinus Torvalds 43908e0e7c8SDavid Howells call->offset = 0; 44008e0e7c8SDavid Howells call->unmarshall++; 4411da177e4SLinus Torvalds 4426db3ac3cSDavid Howells case 6: 4431da177e4SLinus Torvalds break; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4466db3ac3cSDavid Howells for (; req->index < req->nr_pages; req->index++) { 4476db3ac3cSDavid Howells if (call->count < PAGE_SIZE) 4486db3ac3cSDavid Howells zero_user_segment(req->pages[req->index], 4496db3ac3cSDavid Howells call->count, PAGE_SIZE); 450196ee9cdSDavid Howells if (req->page_done) 451196ee9cdSDavid Howells req->page_done(call, req); 4526db3ac3cSDavid Howells call->count = 0; 453416351f2SDavid Howells } 454416351f2SDavid Howells 45508e0e7c8SDavid Howells _leave(" = 0 [done]"); 45608e0e7c8SDavid Howells return 0; 457ec26815aSDavid Howells } 4581da177e4SLinus Torvalds 459196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call) 460196ee9cdSDavid Howells { 461196ee9cdSDavid Howells struct afs_read *req = call->reply3; 462196ee9cdSDavid Howells 463196ee9cdSDavid Howells afs_put_read(req); 464196ee9cdSDavid Howells afs_flat_call_destructor(call); 465196ee9cdSDavid Howells } 466196ee9cdSDavid Howells 4671da177e4SLinus Torvalds /* 46808e0e7c8SDavid Howells * FS.FetchData operation type 4691da177e4SLinus Torvalds */ 47008e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 47100d3b7a4SDavid Howells .name = "FS.FetchData", 47208e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 47308e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 474196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 47508e0e7c8SDavid Howells }; 47608e0e7c8SDavid Howells 477b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = { 478b9b1f8d5SDavid Howells .name = "FS.FetchData64", 479b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_fetch_data, 480b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 481196ee9cdSDavid Howells .destructor = afs_fetch_data_destructor, 482b9b1f8d5SDavid Howells }; 483b9b1f8d5SDavid Howells 484b9b1f8d5SDavid Howells /* 485b9b1f8d5SDavid Howells * fetch data from a very large file 486b9b1f8d5SDavid Howells */ 487b9b1f8d5SDavid Howells static int afs_fs_fetch_data64(struct afs_server *server, 488b9b1f8d5SDavid Howells struct key *key, 489b9b1f8d5SDavid Howells struct afs_vnode *vnode, 490196ee9cdSDavid Howells struct afs_read *req, 49156ff9c83SDavid Howells bool async) 492b9b1f8d5SDavid Howells { 493b9b1f8d5SDavid Howells struct afs_call *call; 494f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 495b9b1f8d5SDavid Howells __be32 *bp; 496b9b1f8d5SDavid Howells 497b9b1f8d5SDavid Howells _enter(""); 498b9b1f8d5SDavid Howells 499f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4); 500b9b1f8d5SDavid Howells if (!call) 501b9b1f8d5SDavid Howells return -ENOMEM; 502b9b1f8d5SDavid Howells 503b9b1f8d5SDavid Howells call->key = key; 504b9b1f8d5SDavid Howells call->reply = vnode; 505b9b1f8d5SDavid Howells call->reply2 = NULL; /* volsync */ 506196ee9cdSDavid Howells call->reply3 = req; 507b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 508b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 509b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA64; 510b9b1f8d5SDavid Howells 511b9b1f8d5SDavid Howells /* marshall the parameters */ 512b9b1f8d5SDavid Howells bp = call->request; 513b9b1f8d5SDavid Howells bp[0] = htonl(FSFETCHDATA64); 514b9b1f8d5SDavid Howells bp[1] = htonl(vnode->fid.vid); 515b9b1f8d5SDavid Howells bp[2] = htonl(vnode->fid.vnode); 516b9b1f8d5SDavid Howells bp[3] = htonl(vnode->fid.unique); 517196ee9cdSDavid Howells bp[4] = htonl(upper_32_bits(req->pos)); 518196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->pos)); 519b9b1f8d5SDavid Howells bp[6] = 0; 520196ee9cdSDavid Howells bp[7] = htonl(lower_32_bits(req->len)); 521b9b1f8d5SDavid Howells 522196ee9cdSDavid Howells atomic_inc(&req->usage); 52356ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 524b9b1f8d5SDavid Howells } 525b9b1f8d5SDavid Howells 52608e0e7c8SDavid Howells /* 52708e0e7c8SDavid Howells * fetch data from a file 52808e0e7c8SDavid Howells */ 52908e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 53000d3b7a4SDavid Howells struct key *key, 5311da177e4SLinus Torvalds struct afs_vnode *vnode, 532196ee9cdSDavid Howells struct afs_read *req, 53356ff9c83SDavid Howells bool async) 5341da177e4SLinus Torvalds { 53508e0e7c8SDavid Howells struct afs_call *call; 536f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 53708e0e7c8SDavid Howells __be32 *bp; 5381da177e4SLinus Torvalds 539196ee9cdSDavid Howells if (upper_32_bits(req->pos) || 540196ee9cdSDavid Howells upper_32_bits(req->len) || 541196ee9cdSDavid Howells upper_32_bits(req->pos + req->len)) 54256ff9c83SDavid Howells return afs_fs_fetch_data64(server, key, vnode, req, async); 543b9b1f8d5SDavid Howells 54408e0e7c8SDavid Howells _enter(""); 5451da177e4SLinus Torvalds 546f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 54708e0e7c8SDavid Howells if (!call) 54808e0e7c8SDavid Howells return -ENOMEM; 5491da177e4SLinus Torvalds 55000d3b7a4SDavid Howells call->key = key; 55108e0e7c8SDavid Howells call->reply = vnode; 552260a9803SDavid Howells call->reply2 = NULL; /* volsync */ 553196ee9cdSDavid Howells call->reply3 = req; 55408e0e7c8SDavid Howells call->service_id = FS_SERVICE; 55508e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 556b9b1f8d5SDavid Howells call->operation_ID = FSFETCHDATA; 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* marshall the parameters */ 55908e0e7c8SDavid Howells bp = call->request; 56008e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 56108e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 56208e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 56308e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 564196ee9cdSDavid Howells bp[4] = htonl(lower_32_bits(req->pos)); 565196ee9cdSDavid Howells bp[5] = htonl(lower_32_bits(req->len)); 5661da177e4SLinus Torvalds 567196ee9cdSDavid Howells atomic_inc(&req->usage); 56856ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 57108e0e7c8SDavid Howells /* 57208e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 57308e0e7c8SDavid Howells */ 574d001648eSDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call) 57508e0e7c8SDavid Howells { 576d001648eSDavid Howells _enter(""); 5771da177e4SLinus Torvalds 578372ee163SDavid Howells /* shouldn't be any reply data */ 579d001648eSDavid Howells return afs_extract_data(call, NULL, 0, false); 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds 58208e0e7c8SDavid Howells /* 58308e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 58408e0e7c8SDavid Howells */ 58508e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 58600d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 58708e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 58808e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 58908e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 59008e0e7c8SDavid Howells }; 5911da177e4SLinus Torvalds 59208e0e7c8SDavid Howells /* 59308e0e7c8SDavid Howells * give up a set of callbacks 59408e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 59508e0e7c8SDavid Howells */ 596f044c884SDavid Howells int afs_fs_give_up_callbacks(struct afs_net *net, 597f044c884SDavid Howells struct afs_server *server, 59856ff9c83SDavid Howells bool async) 59908e0e7c8SDavid Howells { 60008e0e7c8SDavid Howells struct afs_call *call; 60108e0e7c8SDavid Howells size_t ncallbacks; 60208e0e7c8SDavid Howells __be32 *bp, *tp; 60308e0e7c8SDavid Howells int loop; 6041da177e4SLinus Torvalds 60508e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 60608e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 60708e0e7c8SDavid Howells 60808e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 60908e0e7c8SDavid Howells 61008e0e7c8SDavid Howells if (ncallbacks == 0) 61108e0e7c8SDavid Howells return 0; 61208e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 61308e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 61408e0e7c8SDavid Howells 61508e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 61608e0e7c8SDavid Howells 617f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGiveUpCallBacks, 61808e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 61908e0e7c8SDavid Howells if (!call) 62008e0e7c8SDavid Howells return -ENOMEM; 62108e0e7c8SDavid Howells 62208e0e7c8SDavid Howells call->service_id = FS_SERVICE; 62308e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 62408e0e7c8SDavid Howells 62508e0e7c8SDavid Howells /* marshall the parameters */ 62608e0e7c8SDavid Howells bp = call->request; 62708e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 62808e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 62908e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 63008e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 63108e0e7c8SDavid Howells 63208e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 63308e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 63408e0e7c8SDavid Howells struct afs_callback *cb = 63508e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 63608e0e7c8SDavid Howells 63708e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 63808e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 63908e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 64008e0e7c8SDavid Howells *tp++ = htonl(cb->version); 64108e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 64208e0e7c8SDavid Howells *tp++ = htonl(cb->type); 64308e0e7c8SDavid Howells smp_mb(); 64408e0e7c8SDavid Howells server->cb_break_tail = 64508e0e7c8SDavid Howells (server->cb_break_tail + 1) & 64608e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 647ec26815aSDavid Howells } 64808e0e7c8SDavid Howells 64908e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 65008e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 65108e0e7c8SDavid Howells 65256ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 65308e0e7c8SDavid Howells } 654260a9803SDavid Howells 655260a9803SDavid Howells /* 656260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 657260a9803SDavid Howells */ 658d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call) 659260a9803SDavid Howells { 660260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 661260a9803SDavid Howells const __be32 *bp; 662372ee163SDavid Howells int ret; 663260a9803SDavid Howells 664d001648eSDavid Howells _enter("{%u}", call->unmarshall); 665260a9803SDavid Howells 666d001648eSDavid Howells ret = afs_transfer_reply(call); 667372ee163SDavid Howells if (ret < 0) 668372ee163SDavid Howells return ret; 669260a9803SDavid Howells 670260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 671260a9803SDavid Howells bp = call->buffer; 672260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 67331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 67431143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 675260a9803SDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply4); 676260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 677260a9803SDavid Howells 678260a9803SDavid Howells _leave(" = 0 [done]"); 679260a9803SDavid Howells return 0; 680260a9803SDavid Howells } 681260a9803SDavid Howells 682260a9803SDavid Howells /* 683260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 684260a9803SDavid Howells */ 685260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = { 686260a9803SDavid Howells .name = "FS.CreateXXXX", 687260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 688260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 689260a9803SDavid Howells .destructor = afs_flat_call_destructor, 690260a9803SDavid Howells }; 691260a9803SDavid Howells 692260a9803SDavid Howells /* 693260a9803SDavid Howells * create a file or make a directory 694260a9803SDavid Howells */ 695260a9803SDavid Howells int afs_fs_create(struct afs_server *server, 696260a9803SDavid Howells struct key *key, 697260a9803SDavid Howells struct afs_vnode *vnode, 698260a9803SDavid Howells const char *name, 699260a9803SDavid Howells umode_t mode, 700260a9803SDavid Howells struct afs_fid *newfid, 701260a9803SDavid Howells struct afs_file_status *newstatus, 702260a9803SDavid Howells struct afs_callback *newcb, 70356ff9c83SDavid Howells bool async) 704260a9803SDavid Howells { 705260a9803SDavid Howells struct afs_call *call; 706f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 707260a9803SDavid Howells size_t namesz, reqsz, padsz; 708260a9803SDavid Howells __be32 *bp; 709260a9803SDavid Howells 710260a9803SDavid Howells _enter(""); 711260a9803SDavid Howells 712260a9803SDavid Howells namesz = strlen(name); 713260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 714260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 715260a9803SDavid Howells 716f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSCreateXXXX, reqsz, 717260a9803SDavid Howells (3 + 21 + 21 + 3 + 6) * 4); 718260a9803SDavid Howells if (!call) 719260a9803SDavid Howells return -ENOMEM; 720260a9803SDavid Howells 721260a9803SDavid Howells call->key = key; 722260a9803SDavid Howells call->reply = vnode; 723260a9803SDavid Howells call->reply2 = newfid; 724260a9803SDavid Howells call->reply3 = newstatus; 725260a9803SDavid Howells call->reply4 = newcb; 726260a9803SDavid Howells call->service_id = FS_SERVICE; 727260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 728260a9803SDavid Howells 729260a9803SDavid Howells /* marshall the parameters */ 730260a9803SDavid Howells bp = call->request; 731260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 732260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 733260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 734260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 735260a9803SDavid Howells *bp++ = htonl(namesz); 736260a9803SDavid Howells memcpy(bp, name, namesz); 737260a9803SDavid Howells bp = (void *) bp + namesz; 738260a9803SDavid Howells if (padsz > 0) { 739260a9803SDavid Howells memset(bp, 0, padsz); 740260a9803SDavid Howells bp = (void *) bp + padsz; 741260a9803SDavid Howells } 742ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 743ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 744260a9803SDavid Howells *bp++ = 0; /* owner */ 745260a9803SDavid Howells *bp++ = 0; /* group */ 746260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 747260a9803SDavid Howells *bp++ = 0; /* segment size */ 748260a9803SDavid Howells 74956ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 750260a9803SDavid Howells } 751260a9803SDavid Howells 752260a9803SDavid Howells /* 753260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 754260a9803SDavid Howells */ 755d001648eSDavid Howells static int afs_deliver_fs_remove(struct afs_call *call) 756260a9803SDavid Howells { 757260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 758260a9803SDavid Howells const __be32 *bp; 759372ee163SDavid Howells int ret; 760260a9803SDavid Howells 761d001648eSDavid Howells _enter("{%u}", call->unmarshall); 762260a9803SDavid Howells 763d001648eSDavid Howells ret = afs_transfer_reply(call); 764372ee163SDavid Howells if (ret < 0) 765372ee163SDavid Howells return ret; 766260a9803SDavid Howells 767260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 768260a9803SDavid Howells bp = call->buffer; 76931143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 770260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 771260a9803SDavid Howells 772260a9803SDavid Howells _leave(" = 0 [done]"); 773260a9803SDavid Howells return 0; 774260a9803SDavid Howells } 775260a9803SDavid Howells 776260a9803SDavid Howells /* 777260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 778260a9803SDavid Howells */ 779260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = { 780260a9803SDavid Howells .name = "FS.RemoveXXXX", 781260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 782260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 783260a9803SDavid Howells .destructor = afs_flat_call_destructor, 784260a9803SDavid Howells }; 785260a9803SDavid Howells 786260a9803SDavid Howells /* 787260a9803SDavid Howells * remove a file or directory 788260a9803SDavid Howells */ 789260a9803SDavid Howells int afs_fs_remove(struct afs_server *server, 790260a9803SDavid Howells struct key *key, 791260a9803SDavid Howells struct afs_vnode *vnode, 792260a9803SDavid Howells const char *name, 793260a9803SDavid Howells bool isdir, 79456ff9c83SDavid Howells bool async) 795260a9803SDavid Howells { 796260a9803SDavid Howells struct afs_call *call; 797f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 798260a9803SDavid Howells size_t namesz, reqsz, padsz; 799260a9803SDavid Howells __be32 *bp; 800260a9803SDavid Howells 801260a9803SDavid Howells _enter(""); 802260a9803SDavid Howells 803260a9803SDavid Howells namesz = strlen(name); 804260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 805260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 806260a9803SDavid Howells 807f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); 808260a9803SDavid Howells if (!call) 809260a9803SDavid Howells return -ENOMEM; 810260a9803SDavid Howells 811260a9803SDavid Howells call->key = key; 812260a9803SDavid Howells call->reply = vnode; 813260a9803SDavid Howells call->service_id = FS_SERVICE; 814260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 815260a9803SDavid Howells 816260a9803SDavid Howells /* marshall the parameters */ 817260a9803SDavid Howells bp = call->request; 818260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 819260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 820260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 821260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 822260a9803SDavid Howells *bp++ = htonl(namesz); 823260a9803SDavid Howells memcpy(bp, name, namesz); 824260a9803SDavid Howells bp = (void *) bp + namesz; 825260a9803SDavid Howells if (padsz > 0) { 826260a9803SDavid Howells memset(bp, 0, padsz); 827260a9803SDavid Howells bp = (void *) bp + padsz; 828260a9803SDavid Howells } 829260a9803SDavid Howells 83056ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 831260a9803SDavid Howells } 832260a9803SDavid Howells 833260a9803SDavid Howells /* 834260a9803SDavid Howells * deliver reply data to an FS.Link 835260a9803SDavid Howells */ 836d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call) 837260a9803SDavid Howells { 838260a9803SDavid Howells struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; 839260a9803SDavid Howells const __be32 *bp; 840372ee163SDavid Howells int ret; 841260a9803SDavid Howells 842d001648eSDavid Howells _enter("{%u}", call->unmarshall); 843260a9803SDavid Howells 844d001648eSDavid Howells ret = afs_transfer_reply(call); 845372ee163SDavid Howells if (ret < 0) 846372ee163SDavid Howells return ret; 847260a9803SDavid Howells 848260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 849260a9803SDavid Howells bp = call->buffer; 85031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 85131143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); 852260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 853260a9803SDavid Howells 854260a9803SDavid Howells _leave(" = 0 [done]"); 855260a9803SDavid Howells return 0; 856260a9803SDavid Howells } 857260a9803SDavid Howells 858260a9803SDavid Howells /* 859260a9803SDavid Howells * FS.Link operation type 860260a9803SDavid Howells */ 861260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 862260a9803SDavid Howells .name = "FS.Link", 863260a9803SDavid Howells .deliver = afs_deliver_fs_link, 864260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 865260a9803SDavid Howells .destructor = afs_flat_call_destructor, 866260a9803SDavid Howells }; 867260a9803SDavid Howells 868260a9803SDavid Howells /* 869260a9803SDavid Howells * make a hard link 870260a9803SDavid Howells */ 871260a9803SDavid Howells int afs_fs_link(struct afs_server *server, 872260a9803SDavid Howells struct key *key, 873260a9803SDavid Howells struct afs_vnode *dvnode, 874260a9803SDavid Howells struct afs_vnode *vnode, 875260a9803SDavid Howells const char *name, 87656ff9c83SDavid Howells bool async) 877260a9803SDavid Howells { 878260a9803SDavid Howells struct afs_call *call; 879f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 880260a9803SDavid Howells size_t namesz, reqsz, padsz; 881260a9803SDavid Howells __be32 *bp; 882260a9803SDavid Howells 883260a9803SDavid Howells _enter(""); 884260a9803SDavid Howells 885260a9803SDavid Howells namesz = strlen(name); 886260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 887260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 888260a9803SDavid Howells 889f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 890260a9803SDavid Howells if (!call) 891260a9803SDavid Howells return -ENOMEM; 892260a9803SDavid Howells 893260a9803SDavid Howells call->key = key; 894260a9803SDavid Howells call->reply = dvnode; 895260a9803SDavid Howells call->reply2 = vnode; 896260a9803SDavid Howells call->service_id = FS_SERVICE; 897260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 898260a9803SDavid Howells 899260a9803SDavid Howells /* marshall the parameters */ 900260a9803SDavid Howells bp = call->request; 901260a9803SDavid Howells *bp++ = htonl(FSLINK); 902260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 903260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 904260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 905260a9803SDavid Howells *bp++ = htonl(namesz); 906260a9803SDavid Howells memcpy(bp, name, namesz); 907260a9803SDavid Howells bp = (void *) bp + namesz; 908260a9803SDavid Howells if (padsz > 0) { 909260a9803SDavid Howells memset(bp, 0, padsz); 910260a9803SDavid Howells bp = (void *) bp + padsz; 911260a9803SDavid Howells } 912260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 913260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 914260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 915260a9803SDavid Howells 91656ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 917260a9803SDavid Howells } 918260a9803SDavid Howells 919260a9803SDavid Howells /* 920260a9803SDavid Howells * deliver reply data to an FS.Symlink 921260a9803SDavid Howells */ 922d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call) 923260a9803SDavid Howells { 924260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 925260a9803SDavid Howells const __be32 *bp; 926372ee163SDavid Howells int ret; 927260a9803SDavid Howells 928d001648eSDavid Howells _enter("{%u}", call->unmarshall); 929260a9803SDavid Howells 930d001648eSDavid Howells ret = afs_transfer_reply(call); 931372ee163SDavid Howells if (ret < 0) 932372ee163SDavid Howells return ret; 933260a9803SDavid Howells 934260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 935260a9803SDavid Howells bp = call->buffer; 936260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 93731143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); 93831143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); 939260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 940260a9803SDavid Howells 941260a9803SDavid Howells _leave(" = 0 [done]"); 942260a9803SDavid Howells return 0; 943260a9803SDavid Howells } 944260a9803SDavid Howells 945260a9803SDavid Howells /* 946260a9803SDavid Howells * FS.Symlink operation type 947260a9803SDavid Howells */ 948260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 949260a9803SDavid Howells .name = "FS.Symlink", 950260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 951260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 952260a9803SDavid Howells .destructor = afs_flat_call_destructor, 953260a9803SDavid Howells }; 954260a9803SDavid Howells 955260a9803SDavid Howells /* 956260a9803SDavid Howells * create a symbolic link 957260a9803SDavid Howells */ 958260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server, 959260a9803SDavid Howells struct key *key, 960260a9803SDavid Howells struct afs_vnode *vnode, 961260a9803SDavid Howells const char *name, 962260a9803SDavid Howells const char *contents, 963260a9803SDavid Howells struct afs_fid *newfid, 964260a9803SDavid Howells struct afs_file_status *newstatus, 96556ff9c83SDavid Howells bool async) 966260a9803SDavid Howells { 967260a9803SDavid Howells struct afs_call *call; 968f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 969260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 970260a9803SDavid Howells __be32 *bp; 971260a9803SDavid Howells 972260a9803SDavid Howells _enter(""); 973260a9803SDavid Howells 974260a9803SDavid Howells namesz = strlen(name); 975260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 976260a9803SDavid Howells 977260a9803SDavid Howells c_namesz = strlen(contents); 978260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 979260a9803SDavid Howells 980260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 981260a9803SDavid Howells 982f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz, 983260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 984260a9803SDavid Howells if (!call) 985260a9803SDavid Howells return -ENOMEM; 986260a9803SDavid Howells 987260a9803SDavid Howells call->key = key; 988260a9803SDavid Howells call->reply = vnode; 989260a9803SDavid Howells call->reply2 = newfid; 990260a9803SDavid Howells call->reply3 = newstatus; 991260a9803SDavid Howells call->service_id = FS_SERVICE; 992260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 993260a9803SDavid Howells 994260a9803SDavid Howells /* marshall the parameters */ 995260a9803SDavid Howells bp = call->request; 996260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 997260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 998260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 999260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 1000260a9803SDavid Howells *bp++ = htonl(namesz); 1001260a9803SDavid Howells memcpy(bp, name, namesz); 1002260a9803SDavid Howells bp = (void *) bp + namesz; 1003260a9803SDavid Howells if (padsz > 0) { 1004260a9803SDavid Howells memset(bp, 0, padsz); 1005260a9803SDavid Howells bp = (void *) bp + padsz; 1006260a9803SDavid Howells } 1007260a9803SDavid Howells *bp++ = htonl(c_namesz); 1008260a9803SDavid Howells memcpy(bp, contents, c_namesz); 1009260a9803SDavid Howells bp = (void *) bp + c_namesz; 1010260a9803SDavid Howells if (c_padsz > 0) { 1011260a9803SDavid Howells memset(bp, 0, c_padsz); 1012260a9803SDavid Howells bp = (void *) bp + c_padsz; 1013260a9803SDavid Howells } 1014ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME); 1015ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 1016260a9803SDavid Howells *bp++ = 0; /* owner */ 1017260a9803SDavid Howells *bp++ = 0; /* group */ 1018260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 1019260a9803SDavid Howells *bp++ = 0; /* segment size */ 1020260a9803SDavid Howells 102156ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1022260a9803SDavid Howells } 1023260a9803SDavid Howells 1024260a9803SDavid Howells /* 1025260a9803SDavid Howells * deliver reply data to an FS.Rename 1026260a9803SDavid Howells */ 1027d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call) 1028260a9803SDavid Howells { 1029260a9803SDavid Howells struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; 1030260a9803SDavid Howells const __be32 *bp; 1031372ee163SDavid Howells int ret; 1032260a9803SDavid Howells 1033d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1034260a9803SDavid Howells 1035d001648eSDavid Howells ret = afs_transfer_reply(call); 1036372ee163SDavid Howells if (ret < 0) 1037372ee163SDavid Howells return ret; 1038260a9803SDavid Howells 1039260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 1040260a9803SDavid Howells bp = call->buffer; 104131143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); 1042260a9803SDavid Howells if (new_dvnode != orig_dvnode) 104331143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, 104431143d5dSDavid Howells NULL); 1045260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1046260a9803SDavid Howells 1047260a9803SDavid Howells _leave(" = 0 [done]"); 1048260a9803SDavid Howells return 0; 1049260a9803SDavid Howells } 1050260a9803SDavid Howells 1051260a9803SDavid Howells /* 1052260a9803SDavid Howells * FS.Rename operation type 1053260a9803SDavid Howells */ 1054260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 1055260a9803SDavid Howells .name = "FS.Rename", 1056260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 1057260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 1058260a9803SDavid Howells .destructor = afs_flat_call_destructor, 1059260a9803SDavid Howells }; 1060260a9803SDavid Howells 1061260a9803SDavid Howells /* 1062260a9803SDavid Howells * create a symbolic link 1063260a9803SDavid Howells */ 1064260a9803SDavid Howells int afs_fs_rename(struct afs_server *server, 1065260a9803SDavid Howells struct key *key, 1066260a9803SDavid Howells struct afs_vnode *orig_dvnode, 1067260a9803SDavid Howells const char *orig_name, 1068260a9803SDavid Howells struct afs_vnode *new_dvnode, 1069260a9803SDavid Howells const char *new_name, 107056ff9c83SDavid Howells bool async) 1071260a9803SDavid Howells { 1072260a9803SDavid Howells struct afs_call *call; 1073f044c884SDavid Howells struct afs_net *net = afs_v2net(orig_dvnode); 1074260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 1075260a9803SDavid Howells __be32 *bp; 1076260a9803SDavid Howells 1077260a9803SDavid Howells _enter(""); 1078260a9803SDavid Howells 1079260a9803SDavid Howells o_namesz = strlen(orig_name); 1080260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 1081260a9803SDavid Howells 1082260a9803SDavid Howells n_namesz = strlen(new_name); 1083260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 1084260a9803SDavid Howells 1085260a9803SDavid Howells reqsz = (4 * 4) + 1086260a9803SDavid Howells 4 + o_namesz + o_padsz + 1087260a9803SDavid Howells (3 * 4) + 1088260a9803SDavid Howells 4 + n_namesz + n_padsz; 1089260a9803SDavid Howells 1090f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 1091260a9803SDavid Howells if (!call) 1092260a9803SDavid Howells return -ENOMEM; 1093260a9803SDavid Howells 1094260a9803SDavid Howells call->key = key; 1095260a9803SDavid Howells call->reply = orig_dvnode; 1096260a9803SDavid Howells call->reply2 = new_dvnode; 1097260a9803SDavid Howells call->service_id = FS_SERVICE; 1098260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 1099260a9803SDavid Howells 1100260a9803SDavid Howells /* marshall the parameters */ 1101260a9803SDavid Howells bp = call->request; 1102260a9803SDavid Howells *bp++ = htonl(FSRENAME); 1103260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 1104260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 1105260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 1106260a9803SDavid Howells *bp++ = htonl(o_namesz); 1107260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 1108260a9803SDavid Howells bp = (void *) bp + o_namesz; 1109260a9803SDavid Howells if (o_padsz > 0) { 1110260a9803SDavid Howells memset(bp, 0, o_padsz); 1111260a9803SDavid Howells bp = (void *) bp + o_padsz; 1112260a9803SDavid Howells } 1113260a9803SDavid Howells 1114260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 1115260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 1116260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 1117260a9803SDavid Howells *bp++ = htonl(n_namesz); 1118260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 1119260a9803SDavid Howells bp = (void *) bp + n_namesz; 1120260a9803SDavid Howells if (n_padsz > 0) { 1121260a9803SDavid Howells memset(bp, 0, n_padsz); 1122260a9803SDavid Howells bp = (void *) bp + n_padsz; 1123260a9803SDavid Howells } 1124260a9803SDavid Howells 112556ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1126260a9803SDavid Howells } 112731143d5dSDavid Howells 112831143d5dSDavid Howells /* 112931143d5dSDavid Howells * deliver reply data to an FS.StoreData 113031143d5dSDavid Howells */ 1131d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call) 113231143d5dSDavid Howells { 113331143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 113431143d5dSDavid Howells const __be32 *bp; 1135372ee163SDavid Howells int ret; 113631143d5dSDavid Howells 1137d001648eSDavid Howells _enter(""); 113831143d5dSDavid Howells 1139d001648eSDavid Howells ret = afs_transfer_reply(call); 1140372ee163SDavid Howells if (ret < 0) 1141372ee163SDavid Howells return ret; 114231143d5dSDavid Howells 114331143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 114431143d5dSDavid Howells bp = call->buffer; 114531143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, 114631143d5dSDavid Howells &call->store_version); 114731143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 114831143d5dSDavid Howells 114931143d5dSDavid Howells afs_pages_written_back(vnode, call); 115031143d5dSDavid Howells 115131143d5dSDavid Howells _leave(" = 0 [done]"); 115231143d5dSDavid Howells return 0; 115331143d5dSDavid Howells } 115431143d5dSDavid Howells 115531143d5dSDavid Howells /* 115631143d5dSDavid Howells * FS.StoreData operation type 115731143d5dSDavid Howells */ 115831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = { 115931143d5dSDavid Howells .name = "FS.StoreData", 116031143d5dSDavid Howells .deliver = afs_deliver_fs_store_data, 116131143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 116231143d5dSDavid Howells .destructor = afs_flat_call_destructor, 116331143d5dSDavid Howells }; 116431143d5dSDavid Howells 1165b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = { 1166b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1167b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_data, 1168b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1169b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1170b9b1f8d5SDavid Howells }; 1171b9b1f8d5SDavid Howells 1172b9b1f8d5SDavid Howells /* 1173b9b1f8d5SDavid Howells * store a set of pages to a very large file 1174b9b1f8d5SDavid Howells */ 1175b9b1f8d5SDavid Howells static int afs_fs_store_data64(struct afs_server *server, 1176b9b1f8d5SDavid Howells struct afs_writeback *wb, 1177b9b1f8d5SDavid Howells pgoff_t first, pgoff_t last, 1178b9b1f8d5SDavid Howells unsigned offset, unsigned to, 1179b9b1f8d5SDavid Howells loff_t size, loff_t pos, loff_t i_size, 118056ff9c83SDavid Howells bool async) 1181b9b1f8d5SDavid Howells { 1182b9b1f8d5SDavid Howells struct afs_vnode *vnode = wb->vnode; 1183b9b1f8d5SDavid Howells struct afs_call *call; 1184f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1185b9b1f8d5SDavid Howells __be32 *bp; 1186b9b1f8d5SDavid Howells 1187b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1188b9b1f8d5SDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 1189b9b1f8d5SDavid Howells 1190f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64, 1191b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1192b9b1f8d5SDavid Howells (21 + 6) * 4); 1193b9b1f8d5SDavid Howells if (!call) 1194b9b1f8d5SDavid Howells return -ENOMEM; 1195b9b1f8d5SDavid Howells 1196b9b1f8d5SDavid Howells call->wb = wb; 1197b9b1f8d5SDavid Howells call->key = wb->key; 1198b9b1f8d5SDavid Howells call->reply = vnode; 1199b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1200b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1201b9b1f8d5SDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 1202b9b1f8d5SDavid Howells call->first = first; 1203b9b1f8d5SDavid Howells call->last = last; 1204b9b1f8d5SDavid Howells call->first_offset = offset; 1205b9b1f8d5SDavid Howells call->last_to = to; 1206b9b1f8d5SDavid Howells call->send_pages = true; 1207b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1208b9b1f8d5SDavid Howells 1209b9b1f8d5SDavid Howells /* marshall the parameters */ 1210b9b1f8d5SDavid Howells bp = call->request; 1211b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1212b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1213b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1214b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1215b9b1f8d5SDavid Howells 1216ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1217ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 1218b9b1f8d5SDavid Howells *bp++ = 0; /* owner */ 1219b9b1f8d5SDavid Howells *bp++ = 0; /* group */ 1220b9b1f8d5SDavid Howells *bp++ = 0; /* unix mode */ 1221b9b1f8d5SDavid Howells *bp++ = 0; /* segment size */ 1222b9b1f8d5SDavid Howells 1223b9b1f8d5SDavid Howells *bp++ = htonl(pos >> 32); 1224b9b1f8d5SDavid Howells *bp++ = htonl((u32) pos); 1225b9b1f8d5SDavid Howells *bp++ = htonl(size >> 32); 1226b9b1f8d5SDavid Howells *bp++ = htonl((u32) size); 1227b9b1f8d5SDavid Howells *bp++ = htonl(i_size >> 32); 1228b9b1f8d5SDavid Howells *bp++ = htonl((u32) i_size); 1229b9b1f8d5SDavid Howells 123056ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1231b9b1f8d5SDavid Howells } 1232b9b1f8d5SDavid Howells 123331143d5dSDavid Howells /* 123431143d5dSDavid Howells * store a set of pages 123531143d5dSDavid Howells */ 123631143d5dSDavid Howells int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, 123731143d5dSDavid Howells pgoff_t first, pgoff_t last, 123831143d5dSDavid Howells unsigned offset, unsigned to, 123956ff9c83SDavid Howells bool async) 124031143d5dSDavid Howells { 124131143d5dSDavid Howells struct afs_vnode *vnode = wb->vnode; 124231143d5dSDavid Howells struct afs_call *call; 1243f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 124431143d5dSDavid Howells loff_t size, pos, i_size; 124531143d5dSDavid Howells __be32 *bp; 124631143d5dSDavid Howells 124731143d5dSDavid Howells _enter(",%x,{%x:%u},,", 124831143d5dSDavid Howells key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); 124931143d5dSDavid Howells 1250146a1192SDavid Howells size = (loff_t)to - (loff_t)offset; 125131143d5dSDavid Howells if (first != last) 125231143d5dSDavid Howells size += (loff_t)(last - first) << PAGE_SHIFT; 125331143d5dSDavid Howells pos = (loff_t)first << PAGE_SHIFT; 125431143d5dSDavid Howells pos += offset; 125531143d5dSDavid Howells 125631143d5dSDavid Howells i_size = i_size_read(&vnode->vfs_inode); 125731143d5dSDavid Howells if (pos + size > i_size) 125831143d5dSDavid Howells i_size = size + pos; 125931143d5dSDavid Howells 126031143d5dSDavid Howells _debug("size %llx, at %llx, i_size %llx", 126131143d5dSDavid Howells (unsigned long long) size, (unsigned long long) pos, 126231143d5dSDavid Howells (unsigned long long) i_size); 126331143d5dSDavid Howells 1264b9b1f8d5SDavid Howells if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32) 1265b9b1f8d5SDavid Howells return afs_fs_store_data64(server, wb, first, last, offset, to, 126656ff9c83SDavid Howells size, pos, i_size, async); 126731143d5dSDavid Howells 1268f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData, 126931143d5dSDavid Howells (4 + 6 + 3) * 4, 127031143d5dSDavid Howells (21 + 6) * 4); 127131143d5dSDavid Howells if (!call) 127231143d5dSDavid Howells return -ENOMEM; 127331143d5dSDavid Howells 127431143d5dSDavid Howells call->wb = wb; 127531143d5dSDavid Howells call->key = wb->key; 127631143d5dSDavid Howells call->reply = vnode; 127731143d5dSDavid Howells call->service_id = FS_SERVICE; 127831143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 127931143d5dSDavid Howells call->mapping = vnode->vfs_inode.i_mapping; 128031143d5dSDavid Howells call->first = first; 128131143d5dSDavid Howells call->last = last; 128231143d5dSDavid Howells call->first_offset = offset; 128331143d5dSDavid Howells call->last_to = to; 128431143d5dSDavid Howells call->send_pages = true; 128531143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 128631143d5dSDavid Howells 128731143d5dSDavid Howells /* marshall the parameters */ 128831143d5dSDavid Howells bp = call->request; 128931143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 129031143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 129131143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 129231143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 129331143d5dSDavid Howells 1294ab94f5d0SMarc Dionne *bp++ = htonl(AFS_SET_MTIME); /* mask */ 1295ab94f5d0SMarc Dionne *bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */ 129631143d5dSDavid Howells *bp++ = 0; /* owner */ 129731143d5dSDavid Howells *bp++ = 0; /* group */ 129831143d5dSDavid Howells *bp++ = 0; /* unix mode */ 129931143d5dSDavid Howells *bp++ = 0; /* segment size */ 130031143d5dSDavid Howells 130131143d5dSDavid Howells *bp++ = htonl(pos); 130231143d5dSDavid Howells *bp++ = htonl(size); 130331143d5dSDavid Howells *bp++ = htonl(i_size); 130431143d5dSDavid Howells 130556ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 130631143d5dSDavid Howells } 130731143d5dSDavid Howells 130831143d5dSDavid Howells /* 130931143d5dSDavid Howells * deliver reply data to an FS.StoreStatus 131031143d5dSDavid Howells */ 1311d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call) 131231143d5dSDavid Howells { 131331143d5dSDavid Howells afs_dataversion_t *store_version; 131431143d5dSDavid Howells struct afs_vnode *vnode = call->reply; 131531143d5dSDavid Howells const __be32 *bp; 1316372ee163SDavid Howells int ret; 131731143d5dSDavid Howells 1318d001648eSDavid Howells _enter(""); 131931143d5dSDavid Howells 1320d001648eSDavid Howells ret = afs_transfer_reply(call); 1321372ee163SDavid Howells if (ret < 0) 1322372ee163SDavid Howells return ret; 132331143d5dSDavid Howells 132431143d5dSDavid Howells /* unmarshall the reply once we've received all of it */ 132531143d5dSDavid Howells store_version = NULL; 132631143d5dSDavid Howells if (call->operation_ID == FSSTOREDATA) 132731143d5dSDavid Howells store_version = &call->store_version; 132831143d5dSDavid Howells 132931143d5dSDavid Howells bp = call->buffer; 133031143d5dSDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); 133131143d5dSDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 133231143d5dSDavid Howells 133331143d5dSDavid Howells _leave(" = 0 [done]"); 133431143d5dSDavid Howells return 0; 133531143d5dSDavid Howells } 133631143d5dSDavid Howells 133731143d5dSDavid Howells /* 133831143d5dSDavid Howells * FS.StoreStatus operation type 133931143d5dSDavid Howells */ 134031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = { 134131143d5dSDavid Howells .name = "FS.StoreStatus", 134231143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 134331143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 134431143d5dSDavid Howells .destructor = afs_flat_call_destructor, 134531143d5dSDavid Howells }; 134631143d5dSDavid Howells 134731143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = { 134831143d5dSDavid Howells .name = "FS.StoreData", 134931143d5dSDavid Howells .deliver = afs_deliver_fs_store_status, 135031143d5dSDavid Howells .abort_to_error = afs_abort_to_error, 135131143d5dSDavid Howells .destructor = afs_flat_call_destructor, 135231143d5dSDavid Howells }; 135331143d5dSDavid Howells 1354b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = { 1355b9b1f8d5SDavid Howells .name = "FS.StoreData64", 1356b9b1f8d5SDavid Howells .deliver = afs_deliver_fs_store_status, 1357b9b1f8d5SDavid Howells .abort_to_error = afs_abort_to_error, 1358b9b1f8d5SDavid Howells .destructor = afs_flat_call_destructor, 1359b9b1f8d5SDavid Howells }; 1360b9b1f8d5SDavid Howells 1361b9b1f8d5SDavid Howells /* 1362b9b1f8d5SDavid Howells * set the attributes on a very large file, using FS.StoreData rather than 1363b9b1f8d5SDavid Howells * FS.StoreStatus so as to alter the file size also 1364b9b1f8d5SDavid Howells */ 1365b9b1f8d5SDavid Howells static int afs_fs_setattr_size64(struct afs_server *server, struct key *key, 1366b9b1f8d5SDavid Howells struct afs_vnode *vnode, struct iattr *attr, 136756ff9c83SDavid Howells bool async) 1368b9b1f8d5SDavid Howells { 1369b9b1f8d5SDavid Howells struct afs_call *call; 1370f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1371b9b1f8d5SDavid Howells __be32 *bp; 1372b9b1f8d5SDavid Howells 1373b9b1f8d5SDavid Howells _enter(",%x,{%x:%u},,", 1374b9b1f8d5SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 1375b9b1f8d5SDavid Howells 1376b9b1f8d5SDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1377b9b1f8d5SDavid Howells 1378f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status, 1379b9b1f8d5SDavid Howells (4 + 6 + 3 * 2) * 4, 1380b9b1f8d5SDavid Howells (21 + 6) * 4); 1381b9b1f8d5SDavid Howells if (!call) 1382b9b1f8d5SDavid Howells return -ENOMEM; 1383b9b1f8d5SDavid Howells 1384b9b1f8d5SDavid Howells call->key = key; 1385b9b1f8d5SDavid Howells call->reply = vnode; 1386b9b1f8d5SDavid Howells call->service_id = FS_SERVICE; 1387b9b1f8d5SDavid Howells call->port = htons(AFS_FS_PORT); 1388b9b1f8d5SDavid Howells call->store_version = vnode->status.data_version + 1; 1389b9b1f8d5SDavid Howells call->operation_ID = FSSTOREDATA; 1390b9b1f8d5SDavid Howells 1391b9b1f8d5SDavid Howells /* marshall the parameters */ 1392b9b1f8d5SDavid Howells bp = call->request; 1393b9b1f8d5SDavid Howells *bp++ = htonl(FSSTOREDATA64); 1394b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vid); 1395b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1396b9b1f8d5SDavid Howells *bp++ = htonl(vnode->fid.unique); 1397b9b1f8d5SDavid Howells 1398b9b1f8d5SDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 1399b9b1f8d5SDavid Howells 1400b9b1f8d5SDavid Howells *bp++ = 0; /* position of start of write */ 1401b9b1f8d5SDavid Howells *bp++ = 0; 1402b9b1f8d5SDavid Howells *bp++ = 0; /* size of write */ 1403b9b1f8d5SDavid Howells *bp++ = 0; 1404b9b1f8d5SDavid Howells *bp++ = htonl(attr->ia_size >> 32); /* new file length */ 1405b9b1f8d5SDavid Howells *bp++ = htonl((u32) attr->ia_size); 1406b9b1f8d5SDavid Howells 140756ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1408b9b1f8d5SDavid Howells } 1409b9b1f8d5SDavid Howells 141031143d5dSDavid Howells /* 141131143d5dSDavid Howells * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus 141231143d5dSDavid Howells * so as to alter the file size also 141331143d5dSDavid Howells */ 141431143d5dSDavid Howells static int afs_fs_setattr_size(struct afs_server *server, struct key *key, 141531143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 141656ff9c83SDavid Howells bool async) 141731143d5dSDavid Howells { 141831143d5dSDavid Howells struct afs_call *call; 1419f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 142031143d5dSDavid Howells __be32 *bp; 142131143d5dSDavid Howells 142231143d5dSDavid Howells _enter(",%x,{%x:%u},,", 142331143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 142431143d5dSDavid Howells 142531143d5dSDavid Howells ASSERT(attr->ia_valid & ATTR_SIZE); 1426b9b1f8d5SDavid Howells if (attr->ia_size >> 32) 1427b9b1f8d5SDavid Howells return afs_fs_setattr_size64(server, key, vnode, attr, 142856ff9c83SDavid Howells async); 142931143d5dSDavid Howells 1430f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status, 143131143d5dSDavid Howells (4 + 6 + 3) * 4, 143231143d5dSDavid Howells (21 + 6) * 4); 143331143d5dSDavid Howells if (!call) 143431143d5dSDavid Howells return -ENOMEM; 143531143d5dSDavid Howells 143631143d5dSDavid Howells call->key = key; 143731143d5dSDavid Howells call->reply = vnode; 143831143d5dSDavid Howells call->service_id = FS_SERVICE; 143931143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 144031143d5dSDavid Howells call->store_version = vnode->status.data_version + 1; 144131143d5dSDavid Howells call->operation_ID = FSSTOREDATA; 144231143d5dSDavid Howells 144331143d5dSDavid Howells /* marshall the parameters */ 144431143d5dSDavid Howells bp = call->request; 144531143d5dSDavid Howells *bp++ = htonl(FSSTOREDATA); 144631143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 144731143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 144831143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 144931143d5dSDavid Howells 145031143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 145131143d5dSDavid Howells 145231143d5dSDavid Howells *bp++ = 0; /* position of start of write */ 145331143d5dSDavid Howells *bp++ = 0; /* size of write */ 145431143d5dSDavid Howells *bp++ = htonl(attr->ia_size); /* new file length */ 145531143d5dSDavid Howells 145656ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 145731143d5dSDavid Howells } 145831143d5dSDavid Howells 145931143d5dSDavid Howells /* 146031143d5dSDavid Howells * set the attributes on a file, using FS.StoreData if there's a change in file 146131143d5dSDavid Howells * size, and FS.StoreStatus otherwise 146231143d5dSDavid Howells */ 146331143d5dSDavid Howells int afs_fs_setattr(struct afs_server *server, struct key *key, 146431143d5dSDavid Howells struct afs_vnode *vnode, struct iattr *attr, 146556ff9c83SDavid Howells bool async) 146631143d5dSDavid Howells { 146731143d5dSDavid Howells struct afs_call *call; 1468f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 146931143d5dSDavid Howells __be32 *bp; 147031143d5dSDavid Howells 147131143d5dSDavid Howells if (attr->ia_valid & ATTR_SIZE) 147231143d5dSDavid Howells return afs_fs_setattr_size(server, key, vnode, attr, 147356ff9c83SDavid Howells async); 147431143d5dSDavid Howells 147531143d5dSDavid Howells _enter(",%x,{%x:%u},,", 147631143d5dSDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 147731143d5dSDavid Howells 1478f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus, 147931143d5dSDavid Howells (4 + 6) * 4, 148031143d5dSDavid Howells (21 + 6) * 4); 148131143d5dSDavid Howells if (!call) 148231143d5dSDavid Howells return -ENOMEM; 148331143d5dSDavid Howells 148431143d5dSDavid Howells call->key = key; 148531143d5dSDavid Howells call->reply = vnode; 148631143d5dSDavid Howells call->service_id = FS_SERVICE; 148731143d5dSDavid Howells call->port = htons(AFS_FS_PORT); 148831143d5dSDavid Howells call->operation_ID = FSSTORESTATUS; 148931143d5dSDavid Howells 149031143d5dSDavid Howells /* marshall the parameters */ 149131143d5dSDavid Howells bp = call->request; 149231143d5dSDavid Howells *bp++ = htonl(FSSTORESTATUS); 149331143d5dSDavid Howells *bp++ = htonl(vnode->fid.vid); 149431143d5dSDavid Howells *bp++ = htonl(vnode->fid.vnode); 149531143d5dSDavid Howells *bp++ = htonl(vnode->fid.unique); 149631143d5dSDavid Howells 149731143d5dSDavid Howells xdr_encode_AFS_StoreStatus(&bp, attr); 149831143d5dSDavid Howells 149956ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 150031143d5dSDavid Howells } 150145222b9eSDavid Howells 150245222b9eSDavid Howells /* 150345222b9eSDavid Howells * deliver reply data to an FS.GetVolumeStatus 150445222b9eSDavid Howells */ 1505d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call) 150645222b9eSDavid Howells { 150745222b9eSDavid Howells const __be32 *bp; 150845222b9eSDavid Howells char *p; 150945222b9eSDavid Howells int ret; 151045222b9eSDavid Howells 1511d001648eSDavid Howells _enter("{%u}", call->unmarshall); 151245222b9eSDavid Howells 151345222b9eSDavid Howells switch (call->unmarshall) { 151445222b9eSDavid Howells case 0: 151545222b9eSDavid Howells call->offset = 0; 151645222b9eSDavid Howells call->unmarshall++; 151745222b9eSDavid Howells 151845222b9eSDavid Howells /* extract the returned status record */ 151945222b9eSDavid Howells case 1: 152045222b9eSDavid Howells _debug("extract status"); 1521d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1522d001648eSDavid Howells 12 * 4, true); 1523372ee163SDavid Howells if (ret < 0) 1524372ee163SDavid Howells return ret; 152545222b9eSDavid Howells 152645222b9eSDavid Howells bp = call->buffer; 152745222b9eSDavid Howells xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); 152845222b9eSDavid Howells call->offset = 0; 152945222b9eSDavid Howells call->unmarshall++; 153045222b9eSDavid Howells 153145222b9eSDavid Howells /* extract the volume name length */ 153245222b9eSDavid Howells case 2: 1533d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1534372ee163SDavid Howells if (ret < 0) 1535372ee163SDavid Howells return ret; 153645222b9eSDavid Howells 153745222b9eSDavid Howells call->count = ntohl(call->tmp); 153845222b9eSDavid Howells _debug("volname length: %u", call->count); 153945222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 154045222b9eSDavid Howells return -EBADMSG; 154145222b9eSDavid Howells call->offset = 0; 154245222b9eSDavid Howells call->unmarshall++; 154345222b9eSDavid Howells 154445222b9eSDavid Howells /* extract the volume name */ 154545222b9eSDavid Howells case 3: 154645222b9eSDavid Howells _debug("extract volname"); 154745222b9eSDavid Howells if (call->count > 0) { 1548d001648eSDavid Howells ret = afs_extract_data(call, call->reply3, 1549d001648eSDavid Howells call->count, true); 1550372ee163SDavid Howells if (ret < 0) 1551372ee163SDavid Howells return ret; 155245222b9eSDavid Howells } 155345222b9eSDavid Howells 155445222b9eSDavid Howells p = call->reply3; 155545222b9eSDavid Howells p[call->count] = 0; 155645222b9eSDavid Howells _debug("volname '%s'", p); 155745222b9eSDavid Howells 155845222b9eSDavid Howells call->offset = 0; 155945222b9eSDavid Howells call->unmarshall++; 156045222b9eSDavid Howells 156145222b9eSDavid Howells /* extract the volume name padding */ 156245222b9eSDavid Howells if ((call->count & 3) == 0) { 156345222b9eSDavid Howells call->unmarshall++; 156445222b9eSDavid Howells goto no_volname_padding; 156545222b9eSDavid Howells } 156645222b9eSDavid Howells call->count = 4 - (call->count & 3); 156745222b9eSDavid Howells 156845222b9eSDavid Howells case 4: 1569d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1570d001648eSDavid Howells call->count, true); 1571372ee163SDavid Howells if (ret < 0) 1572372ee163SDavid Howells return ret; 157345222b9eSDavid Howells 157445222b9eSDavid Howells call->offset = 0; 157545222b9eSDavid Howells call->unmarshall++; 157645222b9eSDavid Howells no_volname_padding: 157745222b9eSDavid Howells 157845222b9eSDavid Howells /* extract the offline message length */ 157945222b9eSDavid Howells case 5: 1580d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1581372ee163SDavid Howells if (ret < 0) 1582372ee163SDavid Howells return ret; 158345222b9eSDavid Howells 158445222b9eSDavid Howells call->count = ntohl(call->tmp); 158545222b9eSDavid Howells _debug("offline msg length: %u", call->count); 158645222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 158745222b9eSDavid Howells return -EBADMSG; 158845222b9eSDavid Howells call->offset = 0; 158945222b9eSDavid Howells call->unmarshall++; 159045222b9eSDavid Howells 159145222b9eSDavid Howells /* extract the offline message */ 159245222b9eSDavid Howells case 6: 159345222b9eSDavid Howells _debug("extract offline"); 159445222b9eSDavid Howells if (call->count > 0) { 1595d001648eSDavid Howells ret = afs_extract_data(call, call->reply3, 1596d001648eSDavid Howells call->count, true); 1597372ee163SDavid Howells if (ret < 0) 1598372ee163SDavid Howells return ret; 159945222b9eSDavid Howells } 160045222b9eSDavid Howells 160145222b9eSDavid Howells p = call->reply3; 160245222b9eSDavid Howells p[call->count] = 0; 160345222b9eSDavid Howells _debug("offline '%s'", p); 160445222b9eSDavid Howells 160545222b9eSDavid Howells call->offset = 0; 160645222b9eSDavid Howells call->unmarshall++; 160745222b9eSDavid Howells 160845222b9eSDavid Howells /* extract the offline message padding */ 160945222b9eSDavid Howells if ((call->count & 3) == 0) { 161045222b9eSDavid Howells call->unmarshall++; 161145222b9eSDavid Howells goto no_offline_padding; 161245222b9eSDavid Howells } 161345222b9eSDavid Howells call->count = 4 - (call->count & 3); 161445222b9eSDavid Howells 161545222b9eSDavid Howells case 7: 1616d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1617d001648eSDavid Howells call->count, true); 1618372ee163SDavid Howells if (ret < 0) 1619372ee163SDavid Howells return ret; 162045222b9eSDavid Howells 162145222b9eSDavid Howells call->offset = 0; 162245222b9eSDavid Howells call->unmarshall++; 162345222b9eSDavid Howells no_offline_padding: 162445222b9eSDavid Howells 162545222b9eSDavid Howells /* extract the message of the day length */ 162645222b9eSDavid Howells case 8: 1627d001648eSDavid Howells ret = afs_extract_data(call, &call->tmp, 4, true); 1628372ee163SDavid Howells if (ret < 0) 1629372ee163SDavid Howells return ret; 163045222b9eSDavid Howells 163145222b9eSDavid Howells call->count = ntohl(call->tmp); 163245222b9eSDavid Howells _debug("motd length: %u", call->count); 163345222b9eSDavid Howells if (call->count >= AFSNAMEMAX) 163445222b9eSDavid Howells return -EBADMSG; 163545222b9eSDavid Howells call->offset = 0; 163645222b9eSDavid Howells call->unmarshall++; 163745222b9eSDavid Howells 163845222b9eSDavid Howells /* extract the message of the day */ 163945222b9eSDavid Howells case 9: 164045222b9eSDavid Howells _debug("extract motd"); 164145222b9eSDavid Howells if (call->count > 0) { 1642d001648eSDavid Howells ret = afs_extract_data(call, call->reply3, 1643d001648eSDavid Howells call->count, true); 1644372ee163SDavid Howells if (ret < 0) 1645372ee163SDavid Howells return ret; 164645222b9eSDavid Howells } 164745222b9eSDavid Howells 164845222b9eSDavid Howells p = call->reply3; 164945222b9eSDavid Howells p[call->count] = 0; 165045222b9eSDavid Howells _debug("motd '%s'", p); 165145222b9eSDavid Howells 165245222b9eSDavid Howells call->offset = 0; 165345222b9eSDavid Howells call->unmarshall++; 165445222b9eSDavid Howells 165545222b9eSDavid Howells /* extract the message of the day padding */ 1656d001648eSDavid Howells call->count = (4 - (call->count & 3)) & 3; 165745222b9eSDavid Howells 165845222b9eSDavid Howells case 10: 1659d001648eSDavid Howells ret = afs_extract_data(call, call->buffer, 1660d001648eSDavid Howells call->count, false); 1661372ee163SDavid Howells if (ret < 0) 1662372ee163SDavid Howells return ret; 166345222b9eSDavid Howells 166445222b9eSDavid Howells call->offset = 0; 166545222b9eSDavid Howells call->unmarshall++; 166645222b9eSDavid Howells case 11: 166745222b9eSDavid Howells break; 166845222b9eSDavid Howells } 166945222b9eSDavid Howells 167045222b9eSDavid Howells _leave(" = 0 [done]"); 167145222b9eSDavid Howells return 0; 167245222b9eSDavid Howells } 167345222b9eSDavid Howells 167445222b9eSDavid Howells /* 167545222b9eSDavid Howells * destroy an FS.GetVolumeStatus call 167645222b9eSDavid Howells */ 167745222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call) 167845222b9eSDavid Howells { 167945222b9eSDavid Howells kfree(call->reply3); 168045222b9eSDavid Howells call->reply3 = NULL; 168145222b9eSDavid Howells afs_flat_call_destructor(call); 168245222b9eSDavid Howells } 168345222b9eSDavid Howells 168445222b9eSDavid Howells /* 168545222b9eSDavid Howells * FS.GetVolumeStatus operation type 168645222b9eSDavid Howells */ 168745222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = { 168845222b9eSDavid Howells .name = "FS.GetVolumeStatus", 168945222b9eSDavid Howells .deliver = afs_deliver_fs_get_volume_status, 169045222b9eSDavid Howells .abort_to_error = afs_abort_to_error, 169145222b9eSDavid Howells .destructor = afs_get_volume_status_call_destructor, 169245222b9eSDavid Howells }; 169345222b9eSDavid Howells 169445222b9eSDavid Howells /* 169545222b9eSDavid Howells * fetch the status of a volume 169645222b9eSDavid Howells */ 169745222b9eSDavid Howells int afs_fs_get_volume_status(struct afs_server *server, 169845222b9eSDavid Howells struct key *key, 169945222b9eSDavid Howells struct afs_vnode *vnode, 170045222b9eSDavid Howells struct afs_volume_status *vs, 170156ff9c83SDavid Howells bool async) 170245222b9eSDavid Howells { 170345222b9eSDavid Howells struct afs_call *call; 1704f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 170545222b9eSDavid Howells __be32 *bp; 170645222b9eSDavid Howells void *tmpbuf; 170745222b9eSDavid Howells 170845222b9eSDavid Howells _enter(""); 170945222b9eSDavid Howells 171045222b9eSDavid Howells tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); 171145222b9eSDavid Howells if (!tmpbuf) 171245222b9eSDavid Howells return -ENOMEM; 171345222b9eSDavid Howells 1714f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); 171545222b9eSDavid Howells if (!call) { 171645222b9eSDavid Howells kfree(tmpbuf); 171745222b9eSDavid Howells return -ENOMEM; 171845222b9eSDavid Howells } 171945222b9eSDavid Howells 172045222b9eSDavid Howells call->key = key; 172145222b9eSDavid Howells call->reply = vnode; 172245222b9eSDavid Howells call->reply2 = vs; 172345222b9eSDavid Howells call->reply3 = tmpbuf; 172445222b9eSDavid Howells call->service_id = FS_SERVICE; 172545222b9eSDavid Howells call->port = htons(AFS_FS_PORT); 172645222b9eSDavid Howells 172745222b9eSDavid Howells /* marshall the parameters */ 172845222b9eSDavid Howells bp = call->request; 172945222b9eSDavid Howells bp[0] = htonl(FSGETVOLUMESTATUS); 173045222b9eSDavid Howells bp[1] = htonl(vnode->fid.vid); 173145222b9eSDavid Howells 173256ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 173345222b9eSDavid Howells } 1734e8d6c554SDavid Howells 1735e8d6c554SDavid Howells /* 1736e8d6c554SDavid Howells * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock 1737e8d6c554SDavid Howells */ 1738d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call) 1739e8d6c554SDavid Howells { 1740e8d6c554SDavid Howells const __be32 *bp; 1741372ee163SDavid Howells int ret; 1742e8d6c554SDavid Howells 1743d001648eSDavid Howells _enter("{%u}", call->unmarshall); 1744e8d6c554SDavid Howells 1745d001648eSDavid Howells ret = afs_transfer_reply(call); 1746372ee163SDavid Howells if (ret < 0) 1747372ee163SDavid Howells return ret; 1748e8d6c554SDavid Howells 1749e8d6c554SDavid Howells /* unmarshall the reply once we've received all of it */ 1750e8d6c554SDavid Howells bp = call->buffer; 1751e8d6c554SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 1752e8d6c554SDavid Howells 1753e8d6c554SDavid Howells _leave(" = 0 [done]"); 1754e8d6c554SDavid Howells return 0; 1755e8d6c554SDavid Howells } 1756e8d6c554SDavid Howells 1757e8d6c554SDavid Howells /* 1758e8d6c554SDavid Howells * FS.SetLock operation type 1759e8d6c554SDavid Howells */ 1760e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = { 1761e8d6c554SDavid Howells .name = "FS.SetLock", 1762e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1763e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1764e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1765e8d6c554SDavid Howells }; 1766e8d6c554SDavid Howells 1767e8d6c554SDavid Howells /* 1768e8d6c554SDavid Howells * FS.ExtendLock operation type 1769e8d6c554SDavid Howells */ 1770e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = { 1771e8d6c554SDavid Howells .name = "FS.ExtendLock", 1772e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1773e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1774e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1775e8d6c554SDavid Howells }; 1776e8d6c554SDavid Howells 1777e8d6c554SDavid Howells /* 1778e8d6c554SDavid Howells * FS.ReleaseLock operation type 1779e8d6c554SDavid Howells */ 1780e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = { 1781e8d6c554SDavid Howells .name = "FS.ReleaseLock", 1782e8d6c554SDavid Howells .deliver = afs_deliver_fs_xxxx_lock, 1783e8d6c554SDavid Howells .abort_to_error = afs_abort_to_error, 1784e8d6c554SDavid Howells .destructor = afs_flat_call_destructor, 1785e8d6c554SDavid Howells }; 1786e8d6c554SDavid Howells 1787e8d6c554SDavid Howells /* 1788e8d6c554SDavid Howells * get a lock on a file 1789e8d6c554SDavid Howells */ 1790e8d6c554SDavid Howells int afs_fs_set_lock(struct afs_server *server, 1791e8d6c554SDavid Howells struct key *key, 1792e8d6c554SDavid Howells struct afs_vnode *vnode, 1793e8d6c554SDavid Howells afs_lock_type_t type, 179456ff9c83SDavid Howells bool async) 1795e8d6c554SDavid Howells { 1796e8d6c554SDavid Howells struct afs_call *call; 1797f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1798e8d6c554SDavid Howells __be32 *bp; 1799e8d6c554SDavid Howells 1800e8d6c554SDavid Howells _enter(""); 1801e8d6c554SDavid Howells 1802f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4); 1803e8d6c554SDavid Howells if (!call) 1804e8d6c554SDavid Howells return -ENOMEM; 1805e8d6c554SDavid Howells 1806e8d6c554SDavid Howells call->key = key; 1807e8d6c554SDavid Howells call->reply = vnode; 1808e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1809e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1810e8d6c554SDavid Howells 1811e8d6c554SDavid Howells /* marshall the parameters */ 1812e8d6c554SDavid Howells bp = call->request; 1813e8d6c554SDavid Howells *bp++ = htonl(FSSETLOCK); 1814e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1815e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1816e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1817e8d6c554SDavid Howells *bp++ = htonl(type); 1818e8d6c554SDavid Howells 181956ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1820e8d6c554SDavid Howells } 1821e8d6c554SDavid Howells 1822e8d6c554SDavid Howells /* 1823e8d6c554SDavid Howells * extend a lock on a file 1824e8d6c554SDavid Howells */ 1825e8d6c554SDavid Howells int afs_fs_extend_lock(struct afs_server *server, 1826e8d6c554SDavid Howells struct key *key, 1827e8d6c554SDavid Howells struct afs_vnode *vnode, 182856ff9c83SDavid Howells bool async) 1829e8d6c554SDavid Howells { 1830e8d6c554SDavid Howells struct afs_call *call; 1831f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1832e8d6c554SDavid Howells __be32 *bp; 1833e8d6c554SDavid Howells 1834e8d6c554SDavid Howells _enter(""); 1835e8d6c554SDavid Howells 1836f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4); 1837e8d6c554SDavid Howells if (!call) 1838e8d6c554SDavid Howells return -ENOMEM; 1839e8d6c554SDavid Howells 1840e8d6c554SDavid Howells call->key = key; 1841e8d6c554SDavid Howells call->reply = vnode; 1842e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1843e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1844e8d6c554SDavid Howells 1845e8d6c554SDavid Howells /* marshall the parameters */ 1846e8d6c554SDavid Howells bp = call->request; 1847e8d6c554SDavid Howells *bp++ = htonl(FSEXTENDLOCK); 1848e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1849e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1850e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1851e8d6c554SDavid Howells 185256ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1853e8d6c554SDavid Howells } 1854e8d6c554SDavid Howells 1855e8d6c554SDavid Howells /* 1856e8d6c554SDavid Howells * release a lock on a file 1857e8d6c554SDavid Howells */ 1858e8d6c554SDavid Howells int afs_fs_release_lock(struct afs_server *server, 1859e8d6c554SDavid Howells struct key *key, 1860e8d6c554SDavid Howells struct afs_vnode *vnode, 186156ff9c83SDavid Howells bool async) 1862e8d6c554SDavid Howells { 1863e8d6c554SDavid Howells struct afs_call *call; 1864f044c884SDavid Howells struct afs_net *net = afs_v2net(vnode); 1865e8d6c554SDavid Howells __be32 *bp; 1866e8d6c554SDavid Howells 1867e8d6c554SDavid Howells _enter(""); 1868e8d6c554SDavid Howells 1869f044c884SDavid Howells call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4); 1870e8d6c554SDavid Howells if (!call) 1871e8d6c554SDavid Howells return -ENOMEM; 1872e8d6c554SDavid Howells 1873e8d6c554SDavid Howells call->key = key; 1874e8d6c554SDavid Howells call->reply = vnode; 1875e8d6c554SDavid Howells call->service_id = FS_SERVICE; 1876e8d6c554SDavid Howells call->port = htons(AFS_FS_PORT); 1877e8d6c554SDavid Howells 1878e8d6c554SDavid Howells /* marshall the parameters */ 1879e8d6c554SDavid Howells bp = call->request; 1880e8d6c554SDavid Howells *bp++ = htonl(FSRELEASELOCK); 1881e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vid); 1882e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.vnode); 1883e8d6c554SDavid Howells *bp++ = htonl(vnode->fid.unique); 1884e8d6c554SDavid Howells 188556ff9c83SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, async); 1886e8d6c554SDavid Howells } 1887