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> 131da177e4SLinus Torvalds #include <linux/sched.h> 1408e0e7c8SDavid Howells #include <linux/circ_buf.h> 151da177e4SLinus Torvalds #include "internal.h" 1608e0e7c8SDavid Howells #include "afs_fs.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* 19260a9803SDavid Howells * decode an AFSFid block 20260a9803SDavid Howells */ 21260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) 22260a9803SDavid Howells { 23260a9803SDavid Howells const __be32 *bp = *_bp; 24260a9803SDavid Howells 25260a9803SDavid Howells fid->vid = ntohl(*bp++); 26260a9803SDavid Howells fid->vnode = ntohl(*bp++); 27260a9803SDavid Howells fid->unique = ntohl(*bp++); 28260a9803SDavid Howells *_bp = bp; 29260a9803SDavid Howells } 30260a9803SDavid Howells 31260a9803SDavid Howells /* 3208e0e7c8SDavid Howells * decode an AFSFetchStatus block 331da177e4SLinus Torvalds */ 3408e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp, 35260a9803SDavid Howells struct afs_file_status *status, 3608e0e7c8SDavid Howells struct afs_vnode *vnode) 371da177e4SLinus Torvalds { 3808e0e7c8SDavid Howells const __be32 *bp = *_bp; 3908e0e7c8SDavid Howells umode_t mode; 40260a9803SDavid Howells u64 data_version, size; 4108e0e7c8SDavid Howells u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ 4208e0e7c8SDavid Howells 4308e0e7c8SDavid Howells #define EXTRACT(DST) \ 4408e0e7c8SDavid Howells do { \ 4508e0e7c8SDavid Howells u32 x = ntohl(*bp++); \ 4608e0e7c8SDavid Howells changed |= DST - x; \ 4708e0e7c8SDavid Howells DST = x; \ 4808e0e7c8SDavid Howells } while (0) 4908e0e7c8SDavid Howells 50260a9803SDavid Howells status->if_version = ntohl(*bp++); 51260a9803SDavid Howells EXTRACT(status->type); 52260a9803SDavid Howells EXTRACT(status->nlink); 53260a9803SDavid Howells size = ntohl(*bp++); 5408e0e7c8SDavid Howells data_version = ntohl(*bp++); 55260a9803SDavid Howells EXTRACT(status->author); 56260a9803SDavid Howells EXTRACT(status->owner); 57260a9803SDavid Howells EXTRACT(status->caller_access); /* call ticket dependent */ 58260a9803SDavid Howells EXTRACT(status->anon_access); 59260a9803SDavid Howells EXTRACT(status->mode); 60260a9803SDavid Howells EXTRACT(status->parent.vnode); 61260a9803SDavid Howells EXTRACT(status->parent.unique); 6208e0e7c8SDavid Howells bp++; /* seg size */ 63260a9803SDavid Howells status->mtime_client = ntohl(*bp++); 64260a9803SDavid Howells status->mtime_server = ntohl(*bp++); 65260a9803SDavid Howells EXTRACT(status->group); 6608e0e7c8SDavid Howells bp++; /* sync counter */ 6708e0e7c8SDavid Howells data_version |= (u64) ntohl(*bp++) << 32; 68260a9803SDavid Howells bp++; /* lock count */ 69260a9803SDavid Howells size |= (u64) ntohl(*bp++) << 32; 7008e0e7c8SDavid Howells bp++; /* spare 4 */ 7108e0e7c8SDavid Howells *_bp = bp; 7208e0e7c8SDavid Howells 73260a9803SDavid Howells if (size != status->size) { 74260a9803SDavid Howells status->size = size; 75260a9803SDavid Howells changed |= true; 76260a9803SDavid Howells } 77260a9803SDavid Howells status->mode &= S_IALLUGO; 7808e0e7c8SDavid Howells 79260a9803SDavid Howells _debug("vnode time %lx, %lx", 80260a9803SDavid Howells status->mtime_client, status->mtime_server); 81260a9803SDavid Howells 82260a9803SDavid Howells if (vnode) { 83260a9803SDavid Howells status->parent.vid = vnode->fid.vid; 84260a9803SDavid Howells if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 85260a9803SDavid Howells _debug("vnode changed"); 86260a9803SDavid Howells i_size_write(&vnode->vfs_inode, size); 87260a9803SDavid Howells vnode->vfs_inode.i_uid = status->owner; 88260a9803SDavid Howells vnode->vfs_inode.i_gid = status->group; 89260a9803SDavid Howells vnode->vfs_inode.i_version = vnode->fid.unique; 90260a9803SDavid Howells vnode->vfs_inode.i_nlink = status->nlink; 91260a9803SDavid Howells 9208e0e7c8SDavid Howells mode = vnode->vfs_inode.i_mode; 9308e0e7c8SDavid Howells mode &= ~S_IALLUGO; 94260a9803SDavid Howells mode |= status->mode; 95260a9803SDavid Howells barrier(); 9608e0e7c8SDavid Howells vnode->vfs_inode.i_mode = mode; 9708e0e7c8SDavid Howells } 9808e0e7c8SDavid Howells 99260a9803SDavid Howells vnode->vfs_inode.i_ctime.tv_sec = status->mtime_server; 10008e0e7c8SDavid Howells vnode->vfs_inode.i_mtime = vnode->vfs_inode.i_ctime; 10108e0e7c8SDavid Howells vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; 102260a9803SDavid Howells } 10308e0e7c8SDavid Howells 104260a9803SDavid Howells if (status->data_version != data_version) { 105260a9803SDavid Howells status->data_version = data_version; 106260a9803SDavid Howells if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { 107260a9803SDavid Howells _debug("vnode modified %llx on {%x:%u}", 108ba3e0e1aSDavid S. Miller (unsigned long long) data_version, 109ba3e0e1aSDavid S. Miller vnode->fid.vid, vnode->fid.vnode); 11008e0e7c8SDavid Howells set_bit(AFS_VNODE_MODIFIED, &vnode->flags); 11108e0e7c8SDavid Howells set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); 1121da177e4SLinus Torvalds } 113ec26815aSDavid Howells } 114260a9803SDavid Howells } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* 11708e0e7c8SDavid Howells * decode an AFSCallBack block 1181da177e4SLinus Torvalds */ 11908e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode) 1201da177e4SLinus Torvalds { 12108e0e7c8SDavid Howells const __be32 *bp = *_bp; 1221da177e4SLinus Torvalds 12308e0e7c8SDavid Howells vnode->cb_version = ntohl(*bp++); 12408e0e7c8SDavid Howells vnode->cb_expiry = ntohl(*bp++); 12508e0e7c8SDavid Howells vnode->cb_type = ntohl(*bp++); 12608e0e7c8SDavid Howells vnode->cb_expires = vnode->cb_expiry + get_seconds(); 12708e0e7c8SDavid Howells *_bp = bp; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 130260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp, 131260a9803SDavid Howells struct afs_callback *cb) 132260a9803SDavid Howells { 133260a9803SDavid Howells const __be32 *bp = *_bp; 134260a9803SDavid Howells 135260a9803SDavid Howells cb->version = ntohl(*bp++); 136260a9803SDavid Howells cb->expiry = ntohl(*bp++); 137260a9803SDavid Howells cb->type = ntohl(*bp++); 138260a9803SDavid Howells *_bp = bp; 139260a9803SDavid Howells } 140260a9803SDavid Howells 1411da177e4SLinus Torvalds /* 14208e0e7c8SDavid Howells * decode an AFSVolSync block 1431da177e4SLinus Torvalds */ 14408e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp, 14508e0e7c8SDavid Howells struct afs_volsync *volsync) 1461da177e4SLinus Torvalds { 14708e0e7c8SDavid Howells const __be32 *bp = *_bp; 1481da177e4SLinus Torvalds 14908e0e7c8SDavid Howells volsync->creation = ntohl(*bp++); 15008e0e7c8SDavid Howells bp++; /* spare2 */ 15108e0e7c8SDavid Howells bp++; /* spare3 */ 15208e0e7c8SDavid Howells bp++; /* spare4 */ 15308e0e7c8SDavid Howells bp++; /* spare5 */ 15408e0e7c8SDavid Howells bp++; /* spare6 */ 15508e0e7c8SDavid Howells *_bp = bp; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 15808e0e7c8SDavid Howells /* 15908e0e7c8SDavid Howells * deliver reply data to an FS.FetchStatus 16008e0e7c8SDavid Howells */ 16108e0e7c8SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call, 16208e0e7c8SDavid Howells struct sk_buff *skb, bool last) 16308e0e7c8SDavid Howells { 164260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 16508e0e7c8SDavid Howells const __be32 *bp; 1661da177e4SLinus Torvalds 16708e0e7c8SDavid Howells _enter(",,%u", last); 1681da177e4SLinus Torvalds 16908e0e7c8SDavid Howells afs_transfer_reply(call, skb); 17008e0e7c8SDavid Howells if (!last) 17108e0e7c8SDavid Howells return 0; 1721da177e4SLinus Torvalds 17308e0e7c8SDavid Howells if (call->reply_size != call->reply_max) 17408e0e7c8SDavid Howells return -EBADMSG; 1751da177e4SLinus Torvalds 17608e0e7c8SDavid Howells /* unmarshall the reply once we've received all of it */ 17708e0e7c8SDavid Howells bp = call->buffer; 178260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 179260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 18008e0e7c8SDavid Howells if (call->reply2) 18108e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 1821da177e4SLinus Torvalds 18308e0e7c8SDavid Howells _leave(" = 0 [done]"); 18408e0e7c8SDavid Howells return 0; 185ec26815aSDavid Howells } 18608e0e7c8SDavid Howells 18708e0e7c8SDavid Howells /* 18808e0e7c8SDavid Howells * FS.FetchStatus operation type 18908e0e7c8SDavid Howells */ 19008e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = { 19100d3b7a4SDavid Howells .name = "FS.FetchStatus", 19208e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_status, 19308e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 19408e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 19508e0e7c8SDavid Howells }; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds /* 1981da177e4SLinus Torvalds * fetch the status information for a file 1991da177e4SLinus Torvalds */ 20008e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server, 20100d3b7a4SDavid Howells struct key *key, 2021da177e4SLinus Torvalds struct afs_vnode *vnode, 20308e0e7c8SDavid Howells struct afs_volsync *volsync, 20408e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 2051da177e4SLinus Torvalds { 20608e0e7c8SDavid Howells struct afs_call *call; 2071da177e4SLinus Torvalds __be32 *bp; 2081da177e4SLinus Torvalds 209260a9803SDavid Howells _enter(",%x,{%x:%d},,", 210260a9803SDavid Howells key_serial(key), vnode->fid.vid, vnode->fid.vnode); 2111da177e4SLinus Torvalds 212260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); 21308e0e7c8SDavid Howells if (!call) 21408e0e7c8SDavid Howells return -ENOMEM; 2151da177e4SLinus Torvalds 21600d3b7a4SDavid Howells call->key = key; 21708e0e7c8SDavid Howells call->reply = vnode; 21808e0e7c8SDavid Howells call->reply2 = volsync; 21908e0e7c8SDavid Howells call->service_id = FS_SERVICE; 22008e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* marshall the parameters */ 22308e0e7c8SDavid Howells bp = call->request; 2241da177e4SLinus Torvalds bp[0] = htonl(FSFETCHSTATUS); 2251da177e4SLinus Torvalds bp[1] = htonl(vnode->fid.vid); 2261da177e4SLinus Torvalds bp[2] = htonl(vnode->fid.vnode); 2271da177e4SLinus Torvalds bp[3] = htonl(vnode->fid.unique); 2281da177e4SLinus Torvalds 22908e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 230ec26815aSDavid Howells } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /* 23308e0e7c8SDavid Howells * deliver reply data to an FS.FetchData 2341da177e4SLinus Torvalds */ 23508e0e7c8SDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call, 23608e0e7c8SDavid Howells struct sk_buff *skb, bool last) 2371da177e4SLinus Torvalds { 238260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 23908e0e7c8SDavid Howells const __be32 *bp; 24008e0e7c8SDavid Howells struct page *page; 24108e0e7c8SDavid Howells void *buffer; 2421da177e4SLinus Torvalds int ret; 2431da177e4SLinus Torvalds 24408e0e7c8SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 2451da177e4SLinus Torvalds 24608e0e7c8SDavid Howells switch (call->unmarshall) { 24708e0e7c8SDavid Howells case 0: 24808e0e7c8SDavid Howells call->offset = 0; 24908e0e7c8SDavid Howells call->unmarshall++; 2501da177e4SLinus Torvalds 25108e0e7c8SDavid Howells /* extract the returned data length */ 25208e0e7c8SDavid Howells case 1: 25308e0e7c8SDavid Howells _debug("extract data length"); 25408e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, &call->tmp, 4); 25508e0e7c8SDavid Howells switch (ret) { 25608e0e7c8SDavid Howells case 0: break; 25708e0e7c8SDavid Howells case -EAGAIN: return 0; 25808e0e7c8SDavid Howells default: return ret; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 26108e0e7c8SDavid Howells call->count = ntohl(call->tmp); 26208e0e7c8SDavid Howells _debug("DATA length: %u", call->count); 26308e0e7c8SDavid Howells if (call->count > PAGE_SIZE) 26408e0e7c8SDavid Howells return -EBADMSG; 26508e0e7c8SDavid Howells call->offset = 0; 26608e0e7c8SDavid Howells call->unmarshall++; 2671da177e4SLinus Torvalds 26808e0e7c8SDavid Howells if (call->count < PAGE_SIZE) { 26908e0e7c8SDavid Howells buffer = kmap_atomic(call->reply3, KM_USER0); 27008e0e7c8SDavid Howells memset(buffer + PAGE_SIZE - call->count, 0, 27108e0e7c8SDavid Howells call->count); 27208e0e7c8SDavid Howells kunmap_atomic(buffer, KM_USER0); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 27508e0e7c8SDavid Howells /* extract the returned data */ 27608e0e7c8SDavid Howells case 2: 27708e0e7c8SDavid Howells _debug("extract data"); 27808e0e7c8SDavid Howells page = call->reply3; 27908e0e7c8SDavid Howells buffer = kmap_atomic(page, KM_USER0); 28008e0e7c8SDavid Howells ret = afs_extract_data(call, skb, last, buffer, call->count); 28108e0e7c8SDavid Howells kunmap_atomic(buffer, KM_USER0); 28208e0e7c8SDavid Howells switch (ret) { 28308e0e7c8SDavid Howells case 0: break; 28408e0e7c8SDavid Howells case -EAGAIN: return 0; 28508e0e7c8SDavid Howells default: return ret; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 28808e0e7c8SDavid Howells call->offset = 0; 28908e0e7c8SDavid Howells call->unmarshall++; 29008e0e7c8SDavid Howells 29108e0e7c8SDavid Howells /* extract the metadata */ 29208e0e7c8SDavid Howells case 3: 293260a9803SDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 294260a9803SDavid Howells (21 + 3 + 6) * 4); 29508e0e7c8SDavid Howells switch (ret) { 29608e0e7c8SDavid Howells case 0: break; 29708e0e7c8SDavid Howells case -EAGAIN: return 0; 29808e0e7c8SDavid Howells default: return ret; 299ec26815aSDavid Howells } 3001da177e4SLinus Torvalds 30108e0e7c8SDavid Howells bp = call->buffer; 302260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 303260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 30408e0e7c8SDavid Howells if (call->reply2) 30508e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 3061da177e4SLinus Torvalds 30708e0e7c8SDavid Howells call->offset = 0; 30808e0e7c8SDavid Howells call->unmarshall++; 3091da177e4SLinus Torvalds 31008e0e7c8SDavid Howells case 4: 31108e0e7c8SDavid Howells _debug("trailer"); 31208e0e7c8SDavid Howells if (skb->len != 0) 31308e0e7c8SDavid Howells return -EBADMSG; 3141da177e4SLinus Torvalds break; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 31708e0e7c8SDavid Howells if (!last) 31808e0e7c8SDavid Howells return 0; 3191da177e4SLinus Torvalds 32008e0e7c8SDavid Howells _leave(" = 0 [done]"); 32108e0e7c8SDavid Howells return 0; 322ec26815aSDavid Howells } 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* 32508e0e7c8SDavid Howells * FS.FetchData operation type 3261da177e4SLinus Torvalds */ 32708e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 32800d3b7a4SDavid Howells .name = "FS.FetchData", 32908e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 33008e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 33108e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 33208e0e7c8SDavid Howells }; 33308e0e7c8SDavid Howells 33408e0e7c8SDavid Howells /* 33508e0e7c8SDavid Howells * fetch data from a file 33608e0e7c8SDavid Howells */ 33708e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 33800d3b7a4SDavid Howells struct key *key, 3391da177e4SLinus Torvalds struct afs_vnode *vnode, 34008e0e7c8SDavid Howells off_t offset, size_t length, 34108e0e7c8SDavid Howells struct page *buffer, 34208e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 3431da177e4SLinus Torvalds { 34408e0e7c8SDavid Howells struct afs_call *call; 34508e0e7c8SDavid Howells __be32 *bp; 3461da177e4SLinus Torvalds 34708e0e7c8SDavid Howells _enter(""); 3481da177e4SLinus Torvalds 349260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 35008e0e7c8SDavid Howells if (!call) 35108e0e7c8SDavid Howells return -ENOMEM; 3521da177e4SLinus Torvalds 35300d3b7a4SDavid Howells call->key = key; 35408e0e7c8SDavid Howells call->reply = vnode; 355260a9803SDavid Howells call->reply2 = NULL; /* volsync */ 35608e0e7c8SDavid Howells call->reply3 = buffer; 35708e0e7c8SDavid Howells call->service_id = FS_SERVICE; 35808e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* marshall the parameters */ 36108e0e7c8SDavid Howells bp = call->request; 36208e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 36308e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 36408e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 36508e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 36608e0e7c8SDavid Howells bp[4] = htonl(offset); 36708e0e7c8SDavid Howells bp[5] = htonl(length); 3681da177e4SLinus Torvalds 36908e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 37208e0e7c8SDavid Howells /* 37308e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 37408e0e7c8SDavid Howells */ 37508e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, 37608e0e7c8SDavid Howells struct sk_buff *skb, bool last) 37708e0e7c8SDavid Howells { 37808e0e7c8SDavid Howells _enter(",{%u},%d", skb->len, last); 3791da177e4SLinus Torvalds 38008e0e7c8SDavid Howells if (skb->len > 0) 38108e0e7c8SDavid Howells return -EBADMSG; /* shouldn't be any reply data */ 38208e0e7c8SDavid Howells return 0; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds 38508e0e7c8SDavid Howells /* 38608e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 38708e0e7c8SDavid Howells */ 38808e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 38900d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 39008e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 39108e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 39208e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 39308e0e7c8SDavid Howells }; 3941da177e4SLinus Torvalds 39508e0e7c8SDavid Howells /* 39608e0e7c8SDavid Howells * give up a set of callbacks 39708e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 39808e0e7c8SDavid Howells */ 39908e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server, 40008e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 40108e0e7c8SDavid Howells { 40208e0e7c8SDavid Howells struct afs_call *call; 40308e0e7c8SDavid Howells size_t ncallbacks; 40408e0e7c8SDavid Howells __be32 *bp, *tp; 40508e0e7c8SDavid Howells int loop; 4061da177e4SLinus Torvalds 40708e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 40808e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 40908e0e7c8SDavid Howells 41008e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 41108e0e7c8SDavid Howells 41208e0e7c8SDavid Howells if (ncallbacks == 0) 41308e0e7c8SDavid Howells return 0; 41408e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 41508e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 41608e0e7c8SDavid Howells 41708e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 41808e0e7c8SDavid Howells 41908e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, 42008e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 42108e0e7c8SDavid Howells if (!call) 42208e0e7c8SDavid Howells return -ENOMEM; 42308e0e7c8SDavid Howells 42408e0e7c8SDavid Howells call->service_id = FS_SERVICE; 42508e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 42608e0e7c8SDavid Howells 42708e0e7c8SDavid Howells /* marshall the parameters */ 42808e0e7c8SDavid Howells bp = call->request; 42908e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 43008e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 43108e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 43208e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 43308e0e7c8SDavid Howells 43408e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 43508e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 43608e0e7c8SDavid Howells struct afs_callback *cb = 43708e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 43808e0e7c8SDavid Howells 43908e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 44008e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 44108e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 44208e0e7c8SDavid Howells *tp++ = htonl(cb->version); 44308e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 44408e0e7c8SDavid Howells *tp++ = htonl(cb->type); 44508e0e7c8SDavid Howells smp_mb(); 44608e0e7c8SDavid Howells server->cb_break_tail = 44708e0e7c8SDavid Howells (server->cb_break_tail + 1) & 44808e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 449ec26815aSDavid Howells } 45008e0e7c8SDavid Howells 45108e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 45208e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 45308e0e7c8SDavid Howells 45408e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 45508e0e7c8SDavid Howells } 456260a9803SDavid Howells 457260a9803SDavid Howells /* 458260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 459260a9803SDavid Howells */ 460260a9803SDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call, 461260a9803SDavid Howells struct sk_buff *skb, bool last) 462260a9803SDavid Howells { 463260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 464260a9803SDavid Howells const __be32 *bp; 465260a9803SDavid Howells 466260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 467260a9803SDavid Howells 468260a9803SDavid Howells afs_transfer_reply(call, skb); 469260a9803SDavid Howells if (!last) 470260a9803SDavid Howells return 0; 471260a9803SDavid Howells 472260a9803SDavid Howells if (call->reply_size != call->reply_max) 473260a9803SDavid Howells return -EBADMSG; 474260a9803SDavid Howells 475260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 476260a9803SDavid Howells bp = call->buffer; 477260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 478260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); 479260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 480260a9803SDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply4); 481260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 482260a9803SDavid Howells 483260a9803SDavid Howells _leave(" = 0 [done]"); 484260a9803SDavid Howells return 0; 485260a9803SDavid Howells } 486260a9803SDavid Howells 487260a9803SDavid Howells /* 488260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 489260a9803SDavid Howells */ 490260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = { 491260a9803SDavid Howells .name = "FS.CreateXXXX", 492260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 493260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 494260a9803SDavid Howells .destructor = afs_flat_call_destructor, 495260a9803SDavid Howells }; 496260a9803SDavid Howells 497260a9803SDavid Howells /* 498260a9803SDavid Howells * create a file or make a directory 499260a9803SDavid Howells */ 500260a9803SDavid Howells int afs_fs_create(struct afs_server *server, 501260a9803SDavid Howells struct key *key, 502260a9803SDavid Howells struct afs_vnode *vnode, 503260a9803SDavid Howells const char *name, 504260a9803SDavid Howells umode_t mode, 505260a9803SDavid Howells struct afs_fid *newfid, 506260a9803SDavid Howells struct afs_file_status *newstatus, 507260a9803SDavid Howells struct afs_callback *newcb, 508260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 509260a9803SDavid Howells { 510260a9803SDavid Howells struct afs_call *call; 511260a9803SDavid Howells size_t namesz, reqsz, padsz; 512260a9803SDavid Howells __be32 *bp; 513260a9803SDavid Howells 514260a9803SDavid Howells _enter(""); 515260a9803SDavid Howells 516260a9803SDavid Howells namesz = strlen(name); 517260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 518260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 519260a9803SDavid Howells 520260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, 521260a9803SDavid Howells (3 + 21 + 21 + 3 + 6) * 4); 522260a9803SDavid Howells if (!call) 523260a9803SDavid Howells return -ENOMEM; 524260a9803SDavid Howells 525260a9803SDavid Howells call->key = key; 526260a9803SDavid Howells call->reply = vnode; 527260a9803SDavid Howells call->reply2 = newfid; 528260a9803SDavid Howells call->reply3 = newstatus; 529260a9803SDavid Howells call->reply4 = newcb; 530260a9803SDavid Howells call->service_id = FS_SERVICE; 531260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 532260a9803SDavid Howells 533260a9803SDavid Howells /* marshall the parameters */ 534260a9803SDavid Howells bp = call->request; 535260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 536260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 537260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 538260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 539260a9803SDavid Howells *bp++ = htonl(namesz); 540260a9803SDavid Howells memcpy(bp, name, namesz); 541260a9803SDavid Howells bp = (void *) bp + namesz; 542260a9803SDavid Howells if (padsz > 0) { 543260a9803SDavid Howells memset(bp, 0, padsz); 544260a9803SDavid Howells bp = (void *) bp + padsz; 545260a9803SDavid Howells } 546260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 547260a9803SDavid Howells *bp++ = 0; /* mtime */ 548260a9803SDavid Howells *bp++ = 0; /* owner */ 549260a9803SDavid Howells *bp++ = 0; /* group */ 550260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 551260a9803SDavid Howells *bp++ = 0; /* segment size */ 552260a9803SDavid Howells 553260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 554260a9803SDavid Howells } 555260a9803SDavid Howells 556260a9803SDavid Howells /* 557260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 558260a9803SDavid Howells */ 559260a9803SDavid Howells static int afs_deliver_fs_remove(struct afs_call *call, 560260a9803SDavid Howells struct sk_buff *skb, bool last) 561260a9803SDavid Howells { 562260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 563260a9803SDavid Howells const __be32 *bp; 564260a9803SDavid Howells 565260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 566260a9803SDavid Howells 567260a9803SDavid Howells afs_transfer_reply(call, skb); 568260a9803SDavid Howells if (!last) 569260a9803SDavid Howells return 0; 570260a9803SDavid Howells 571260a9803SDavid Howells if (call->reply_size != call->reply_max) 572260a9803SDavid Howells return -EBADMSG; 573260a9803SDavid Howells 574260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 575260a9803SDavid Howells bp = call->buffer; 576260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 577260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 578260a9803SDavid Howells 579260a9803SDavid Howells _leave(" = 0 [done]"); 580260a9803SDavid Howells return 0; 581260a9803SDavid Howells } 582260a9803SDavid Howells 583260a9803SDavid Howells /* 584260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 585260a9803SDavid Howells */ 586260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = { 587260a9803SDavid Howells .name = "FS.RemoveXXXX", 588260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 589260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 590260a9803SDavid Howells .destructor = afs_flat_call_destructor, 591260a9803SDavid Howells }; 592260a9803SDavid Howells 593260a9803SDavid Howells /* 594260a9803SDavid Howells * remove a file or directory 595260a9803SDavid Howells */ 596260a9803SDavid Howells int afs_fs_remove(struct afs_server *server, 597260a9803SDavid Howells struct key *key, 598260a9803SDavid Howells struct afs_vnode *vnode, 599260a9803SDavid Howells const char *name, 600260a9803SDavid Howells bool isdir, 601260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 602260a9803SDavid Howells { 603260a9803SDavid Howells struct afs_call *call; 604260a9803SDavid Howells size_t namesz, reqsz, padsz; 605260a9803SDavid Howells __be32 *bp; 606260a9803SDavid Howells 607260a9803SDavid Howells _enter(""); 608260a9803SDavid Howells 609260a9803SDavid Howells namesz = strlen(name); 610260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 611260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 612260a9803SDavid Howells 613260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); 614260a9803SDavid Howells if (!call) 615260a9803SDavid Howells return -ENOMEM; 616260a9803SDavid Howells 617260a9803SDavid Howells call->key = key; 618260a9803SDavid Howells call->reply = vnode; 619260a9803SDavid Howells call->service_id = FS_SERVICE; 620260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 621260a9803SDavid Howells 622260a9803SDavid Howells /* marshall the parameters */ 623260a9803SDavid Howells bp = call->request; 624260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 625260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 626260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 627260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 628260a9803SDavid Howells *bp++ = htonl(namesz); 629260a9803SDavid Howells memcpy(bp, name, namesz); 630260a9803SDavid Howells bp = (void *) bp + namesz; 631260a9803SDavid Howells if (padsz > 0) { 632260a9803SDavid Howells memset(bp, 0, padsz); 633260a9803SDavid Howells bp = (void *) bp + padsz; 634260a9803SDavid Howells } 635260a9803SDavid Howells 636260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 637260a9803SDavid Howells } 638260a9803SDavid Howells 639260a9803SDavid Howells /* 640260a9803SDavid Howells * deliver reply data to an FS.Link 641260a9803SDavid Howells */ 642260a9803SDavid Howells static int afs_deliver_fs_link(struct afs_call *call, 643260a9803SDavid Howells struct sk_buff *skb, bool last) 644260a9803SDavid Howells { 645260a9803SDavid Howells struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; 646260a9803SDavid Howells const __be32 *bp; 647260a9803SDavid Howells 648260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 649260a9803SDavid Howells 650260a9803SDavid Howells afs_transfer_reply(call, skb); 651260a9803SDavid Howells if (!last) 652260a9803SDavid Howells return 0; 653260a9803SDavid Howells 654260a9803SDavid Howells if (call->reply_size != call->reply_max) 655260a9803SDavid Howells return -EBADMSG; 656260a9803SDavid Howells 657260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 658260a9803SDavid Howells bp = call->buffer; 659260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 660260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode); 661260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 662260a9803SDavid Howells 663260a9803SDavid Howells _leave(" = 0 [done]"); 664260a9803SDavid Howells return 0; 665260a9803SDavid Howells } 666260a9803SDavid Howells 667260a9803SDavid Howells /* 668260a9803SDavid Howells * FS.Link operation type 669260a9803SDavid Howells */ 670260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 671260a9803SDavid Howells .name = "FS.Link", 672260a9803SDavid Howells .deliver = afs_deliver_fs_link, 673260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 674260a9803SDavid Howells .destructor = afs_flat_call_destructor, 675260a9803SDavid Howells }; 676260a9803SDavid Howells 677260a9803SDavid Howells /* 678260a9803SDavid Howells * make a hard link 679260a9803SDavid Howells */ 680260a9803SDavid Howells int afs_fs_link(struct afs_server *server, 681260a9803SDavid Howells struct key *key, 682260a9803SDavid Howells struct afs_vnode *dvnode, 683260a9803SDavid Howells struct afs_vnode *vnode, 684260a9803SDavid Howells const char *name, 685260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 686260a9803SDavid Howells { 687260a9803SDavid Howells struct afs_call *call; 688260a9803SDavid Howells size_t namesz, reqsz, padsz; 689260a9803SDavid Howells __be32 *bp; 690260a9803SDavid Howells 691260a9803SDavid Howells _enter(""); 692260a9803SDavid Howells 693260a9803SDavid Howells namesz = strlen(name); 694260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 695260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 696260a9803SDavid Howells 697260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 698260a9803SDavid Howells if (!call) 699260a9803SDavid Howells return -ENOMEM; 700260a9803SDavid Howells 701260a9803SDavid Howells call->key = key; 702260a9803SDavid Howells call->reply = dvnode; 703260a9803SDavid Howells call->reply2 = vnode; 704260a9803SDavid Howells call->service_id = FS_SERVICE; 705260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 706260a9803SDavid Howells 707260a9803SDavid Howells /* marshall the parameters */ 708260a9803SDavid Howells bp = call->request; 709260a9803SDavid Howells *bp++ = htonl(FSLINK); 710260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 711260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 712260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 713260a9803SDavid Howells *bp++ = htonl(namesz); 714260a9803SDavid Howells memcpy(bp, name, namesz); 715260a9803SDavid Howells bp = (void *) bp + namesz; 716260a9803SDavid Howells if (padsz > 0) { 717260a9803SDavid Howells memset(bp, 0, padsz); 718260a9803SDavid Howells bp = (void *) bp + padsz; 719260a9803SDavid Howells } 720260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 721260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 722260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 723260a9803SDavid Howells 724260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 725260a9803SDavid Howells } 726260a9803SDavid Howells 727260a9803SDavid Howells /* 728260a9803SDavid Howells * deliver reply data to an FS.Symlink 729260a9803SDavid Howells */ 730260a9803SDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call, 731260a9803SDavid Howells struct sk_buff *skb, bool last) 732260a9803SDavid Howells { 733260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 734260a9803SDavid Howells const __be32 *bp; 735260a9803SDavid Howells 736260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 737260a9803SDavid Howells 738260a9803SDavid Howells afs_transfer_reply(call, skb); 739260a9803SDavid Howells if (!last) 740260a9803SDavid Howells return 0; 741260a9803SDavid Howells 742260a9803SDavid Howells if (call->reply_size != call->reply_max) 743260a9803SDavid Howells return -EBADMSG; 744260a9803SDavid Howells 745260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 746260a9803SDavid Howells bp = call->buffer; 747260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 748260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); 749260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 750260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 751260a9803SDavid Howells 752260a9803SDavid Howells _leave(" = 0 [done]"); 753260a9803SDavid Howells return 0; 754260a9803SDavid Howells } 755260a9803SDavid Howells 756260a9803SDavid Howells /* 757260a9803SDavid Howells * FS.Symlink operation type 758260a9803SDavid Howells */ 759260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 760260a9803SDavid Howells .name = "FS.Symlink", 761260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 762260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 763260a9803SDavid Howells .destructor = afs_flat_call_destructor, 764260a9803SDavid Howells }; 765260a9803SDavid Howells 766260a9803SDavid Howells /* 767260a9803SDavid Howells * create a symbolic link 768260a9803SDavid Howells */ 769260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server, 770260a9803SDavid Howells struct key *key, 771260a9803SDavid Howells struct afs_vnode *vnode, 772260a9803SDavid Howells const char *name, 773260a9803SDavid Howells const char *contents, 774260a9803SDavid Howells struct afs_fid *newfid, 775260a9803SDavid Howells struct afs_file_status *newstatus, 776260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 777260a9803SDavid Howells { 778260a9803SDavid Howells struct afs_call *call; 779260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 780260a9803SDavid Howells __be32 *bp; 781260a9803SDavid Howells 782260a9803SDavid Howells _enter(""); 783260a9803SDavid Howells 784260a9803SDavid Howells namesz = strlen(name); 785260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 786260a9803SDavid Howells 787260a9803SDavid Howells c_namesz = strlen(contents); 788260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 789260a9803SDavid Howells 790260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 791260a9803SDavid Howells 792260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, 793260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 794260a9803SDavid Howells if (!call) 795260a9803SDavid Howells return -ENOMEM; 796260a9803SDavid Howells 797260a9803SDavid Howells call->key = key; 798260a9803SDavid Howells call->reply = vnode; 799260a9803SDavid Howells call->reply2 = newfid; 800260a9803SDavid Howells call->reply3 = newstatus; 801260a9803SDavid Howells call->service_id = FS_SERVICE; 802260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 803260a9803SDavid Howells 804260a9803SDavid Howells /* marshall the parameters */ 805260a9803SDavid Howells bp = call->request; 806260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 807260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 808260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 809260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 810260a9803SDavid Howells *bp++ = htonl(namesz); 811260a9803SDavid Howells memcpy(bp, name, namesz); 812260a9803SDavid Howells bp = (void *) bp + namesz; 813260a9803SDavid Howells if (padsz > 0) { 814260a9803SDavid Howells memset(bp, 0, padsz); 815260a9803SDavid Howells bp = (void *) bp + padsz; 816260a9803SDavid Howells } 817260a9803SDavid Howells *bp++ = htonl(c_namesz); 818260a9803SDavid Howells memcpy(bp, contents, c_namesz); 819260a9803SDavid Howells bp = (void *) bp + c_namesz; 820260a9803SDavid Howells if (c_padsz > 0) { 821260a9803SDavid Howells memset(bp, 0, c_padsz); 822260a9803SDavid Howells bp = (void *) bp + c_padsz; 823260a9803SDavid Howells } 824260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 825260a9803SDavid Howells *bp++ = 0; /* mtime */ 826260a9803SDavid Howells *bp++ = 0; /* owner */ 827260a9803SDavid Howells *bp++ = 0; /* group */ 828260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 829260a9803SDavid Howells *bp++ = 0; /* segment size */ 830260a9803SDavid Howells 831260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 832260a9803SDavid Howells } 833260a9803SDavid Howells 834260a9803SDavid Howells /* 835260a9803SDavid Howells * deliver reply data to an FS.Rename 836260a9803SDavid Howells */ 837260a9803SDavid Howells static int afs_deliver_fs_rename(struct afs_call *call, 838260a9803SDavid Howells struct sk_buff *skb, bool last) 839260a9803SDavid Howells { 840260a9803SDavid Howells struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; 841260a9803SDavid Howells const __be32 *bp; 842260a9803SDavid Howells 843260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 844260a9803SDavid Howells 845260a9803SDavid Howells afs_transfer_reply(call, skb); 846260a9803SDavid Howells if (!last) 847260a9803SDavid Howells return 0; 848260a9803SDavid Howells 849260a9803SDavid Howells if (call->reply_size != call->reply_max) 850260a9803SDavid Howells return -EBADMSG; 851260a9803SDavid Howells 852260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 853260a9803SDavid Howells bp = call->buffer; 854260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode); 855260a9803SDavid Howells if (new_dvnode != orig_dvnode) 856260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode); 857260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 858260a9803SDavid Howells 859260a9803SDavid Howells _leave(" = 0 [done]"); 860260a9803SDavid Howells return 0; 861260a9803SDavid Howells } 862260a9803SDavid Howells 863260a9803SDavid Howells /* 864260a9803SDavid Howells * FS.Rename operation type 865260a9803SDavid Howells */ 866260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 867260a9803SDavid Howells .name = "FS.Rename", 868260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 869260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 870260a9803SDavid Howells .destructor = afs_flat_call_destructor, 871260a9803SDavid Howells }; 872260a9803SDavid Howells 873260a9803SDavid Howells /* 874260a9803SDavid Howells * create a symbolic link 875260a9803SDavid Howells */ 876260a9803SDavid Howells int afs_fs_rename(struct afs_server *server, 877260a9803SDavid Howells struct key *key, 878260a9803SDavid Howells struct afs_vnode *orig_dvnode, 879260a9803SDavid Howells const char *orig_name, 880260a9803SDavid Howells struct afs_vnode *new_dvnode, 881260a9803SDavid Howells const char *new_name, 882260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 883260a9803SDavid Howells { 884260a9803SDavid Howells struct afs_call *call; 885260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 886260a9803SDavid Howells __be32 *bp; 887260a9803SDavid Howells 888260a9803SDavid Howells _enter(""); 889260a9803SDavid Howells 890260a9803SDavid Howells o_namesz = strlen(orig_name); 891260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 892260a9803SDavid Howells 893260a9803SDavid Howells n_namesz = strlen(new_name); 894260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 895260a9803SDavid Howells 896260a9803SDavid Howells reqsz = (4 * 4) + 897260a9803SDavid Howells 4 + o_namesz + o_padsz + 898260a9803SDavid Howells (3 * 4) + 899260a9803SDavid Howells 4 + n_namesz + n_padsz; 900260a9803SDavid Howells 901260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 902260a9803SDavid Howells if (!call) 903260a9803SDavid Howells return -ENOMEM; 904260a9803SDavid Howells 905260a9803SDavid Howells call->key = key; 906260a9803SDavid Howells call->reply = orig_dvnode; 907260a9803SDavid Howells call->reply2 = new_dvnode; 908260a9803SDavid Howells call->service_id = FS_SERVICE; 909260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 910260a9803SDavid Howells 911260a9803SDavid Howells /* marshall the parameters */ 912260a9803SDavid Howells bp = call->request; 913260a9803SDavid Howells *bp++ = htonl(FSRENAME); 914260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 915260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 916260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 917260a9803SDavid Howells *bp++ = htonl(o_namesz); 918260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 919260a9803SDavid Howells bp = (void *) bp + o_namesz; 920260a9803SDavid Howells if (o_padsz > 0) { 921260a9803SDavid Howells memset(bp, 0, o_padsz); 922260a9803SDavid Howells bp = (void *) bp + o_padsz; 923260a9803SDavid Howells } 924260a9803SDavid Howells 925260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 926260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 927260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 928260a9803SDavid Howells *bp++ = htonl(n_namesz); 929260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 930260a9803SDavid Howells bp = (void *) bp + n_namesz; 931260a9803SDavid Howells if (n_padsz > 0) { 932260a9803SDavid Howells memset(bp, 0, n_padsz); 933260a9803SDavid Howells bp = (void *) bp + n_padsz; 934260a9803SDavid Howells } 935260a9803SDavid Howells 936260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 937260a9803SDavid Howells } 938