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 209416351f2SDavid Howells _enter(",%x,{%x:%u},,", 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 /* extract the returned data */ 26908e0e7c8SDavid Howells case 2: 27008e0e7c8SDavid Howells _debug("extract data"); 271416351f2SDavid Howells if (call->count > 0) { 27208e0e7c8SDavid Howells page = call->reply3; 27308e0e7c8SDavid Howells buffer = kmap_atomic(page, KM_USER0); 274416351f2SDavid Howells ret = afs_extract_data(call, skb, last, buffer, 275416351f2SDavid Howells call->count); 27608e0e7c8SDavid Howells kunmap_atomic(buffer, KM_USER0); 27708e0e7c8SDavid Howells switch (ret) { 27808e0e7c8SDavid Howells case 0: break; 27908e0e7c8SDavid Howells case -EAGAIN: return 0; 28008e0e7c8SDavid Howells default: return ret; 2811da177e4SLinus Torvalds } 282416351f2SDavid Howells } 2831da177e4SLinus Torvalds 28408e0e7c8SDavid Howells call->offset = 0; 28508e0e7c8SDavid Howells call->unmarshall++; 28608e0e7c8SDavid Howells 28708e0e7c8SDavid Howells /* extract the metadata */ 28808e0e7c8SDavid Howells case 3: 289260a9803SDavid Howells ret = afs_extract_data(call, skb, last, call->buffer, 290260a9803SDavid Howells (21 + 3 + 6) * 4); 29108e0e7c8SDavid Howells switch (ret) { 29208e0e7c8SDavid Howells case 0: break; 29308e0e7c8SDavid Howells case -EAGAIN: return 0; 29408e0e7c8SDavid Howells default: return ret; 295ec26815aSDavid Howells } 2961da177e4SLinus Torvalds 29708e0e7c8SDavid Howells bp = call->buffer; 298260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 299260a9803SDavid Howells xdr_decode_AFSCallBack(&bp, vnode); 30008e0e7c8SDavid Howells if (call->reply2) 30108e0e7c8SDavid Howells xdr_decode_AFSVolSync(&bp, call->reply2); 3021da177e4SLinus Torvalds 30308e0e7c8SDavid Howells call->offset = 0; 30408e0e7c8SDavid Howells call->unmarshall++; 3051da177e4SLinus Torvalds 30608e0e7c8SDavid Howells case 4: 30708e0e7c8SDavid Howells _debug("trailer"); 30808e0e7c8SDavid Howells if (skb->len != 0) 30908e0e7c8SDavid Howells return -EBADMSG; 3101da177e4SLinus Torvalds break; 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds 31308e0e7c8SDavid Howells if (!last) 31408e0e7c8SDavid Howells return 0; 3151da177e4SLinus Torvalds 316416351f2SDavid Howells if (call->count < PAGE_SIZE) { 317416351f2SDavid Howells _debug("clear"); 318416351f2SDavid Howells page = call->reply3; 319416351f2SDavid Howells buffer = kmap_atomic(page, KM_USER0); 320416351f2SDavid Howells memset(buffer + call->count, 0, PAGE_SIZE - call->count); 321416351f2SDavid Howells kunmap_atomic(buffer, KM_USER0); 322416351f2SDavid Howells } 323416351f2SDavid Howells 32408e0e7c8SDavid Howells _leave(" = 0 [done]"); 32508e0e7c8SDavid Howells return 0; 326ec26815aSDavid Howells } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds /* 32908e0e7c8SDavid Howells * FS.FetchData operation type 3301da177e4SLinus Torvalds */ 33108e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = { 33200d3b7a4SDavid Howells .name = "FS.FetchData", 33308e0e7c8SDavid Howells .deliver = afs_deliver_fs_fetch_data, 33408e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 33508e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 33608e0e7c8SDavid Howells }; 33708e0e7c8SDavid Howells 33808e0e7c8SDavid Howells /* 33908e0e7c8SDavid Howells * fetch data from a file 34008e0e7c8SDavid Howells */ 34108e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server, 34200d3b7a4SDavid Howells struct key *key, 3431da177e4SLinus Torvalds struct afs_vnode *vnode, 34408e0e7c8SDavid Howells off_t offset, size_t length, 34508e0e7c8SDavid Howells struct page *buffer, 34608e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 3471da177e4SLinus Torvalds { 34808e0e7c8SDavid Howells struct afs_call *call; 34908e0e7c8SDavid Howells __be32 *bp; 3501da177e4SLinus Torvalds 35108e0e7c8SDavid Howells _enter(""); 3521da177e4SLinus Torvalds 353260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4); 35408e0e7c8SDavid Howells if (!call) 35508e0e7c8SDavid Howells return -ENOMEM; 3561da177e4SLinus Torvalds 35700d3b7a4SDavid Howells call->key = key; 35808e0e7c8SDavid Howells call->reply = vnode; 359260a9803SDavid Howells call->reply2 = NULL; /* volsync */ 36008e0e7c8SDavid Howells call->reply3 = buffer; 36108e0e7c8SDavid Howells call->service_id = FS_SERVICE; 36208e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds /* marshall the parameters */ 36508e0e7c8SDavid Howells bp = call->request; 36608e0e7c8SDavid Howells bp[0] = htonl(FSFETCHDATA); 36708e0e7c8SDavid Howells bp[1] = htonl(vnode->fid.vid); 36808e0e7c8SDavid Howells bp[2] = htonl(vnode->fid.vnode); 36908e0e7c8SDavid Howells bp[3] = htonl(vnode->fid.unique); 37008e0e7c8SDavid Howells bp[4] = htonl(offset); 37108e0e7c8SDavid Howells bp[5] = htonl(length); 3721da177e4SLinus Torvalds 37308e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 37608e0e7c8SDavid Howells /* 37708e0e7c8SDavid Howells * deliver reply data to an FS.GiveUpCallBacks 37808e0e7c8SDavid Howells */ 37908e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call, 38008e0e7c8SDavid Howells struct sk_buff *skb, bool last) 38108e0e7c8SDavid Howells { 38208e0e7c8SDavid Howells _enter(",{%u},%d", skb->len, last); 3831da177e4SLinus Torvalds 38408e0e7c8SDavid Howells if (skb->len > 0) 38508e0e7c8SDavid Howells return -EBADMSG; /* shouldn't be any reply data */ 38608e0e7c8SDavid Howells return 0; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 38908e0e7c8SDavid Howells /* 39008e0e7c8SDavid Howells * FS.GiveUpCallBacks operation type 39108e0e7c8SDavid Howells */ 39208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = { 39300d3b7a4SDavid Howells .name = "FS.GiveUpCallBacks", 39408e0e7c8SDavid Howells .deliver = afs_deliver_fs_give_up_callbacks, 39508e0e7c8SDavid Howells .abort_to_error = afs_abort_to_error, 39608e0e7c8SDavid Howells .destructor = afs_flat_call_destructor, 39708e0e7c8SDavid Howells }; 3981da177e4SLinus Torvalds 39908e0e7c8SDavid Howells /* 40008e0e7c8SDavid Howells * give up a set of callbacks 40108e0e7c8SDavid Howells * - the callbacks are held in the server->cb_break ring 40208e0e7c8SDavid Howells */ 40308e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server, 40408e0e7c8SDavid Howells const struct afs_wait_mode *wait_mode) 40508e0e7c8SDavid Howells { 40608e0e7c8SDavid Howells struct afs_call *call; 40708e0e7c8SDavid Howells size_t ncallbacks; 40808e0e7c8SDavid Howells __be32 *bp, *tp; 40908e0e7c8SDavid Howells int loop; 4101da177e4SLinus Torvalds 41108e0e7c8SDavid Howells ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail, 41208e0e7c8SDavid Howells ARRAY_SIZE(server->cb_break)); 41308e0e7c8SDavid Howells 41408e0e7c8SDavid Howells _enter("{%zu},", ncallbacks); 41508e0e7c8SDavid Howells 41608e0e7c8SDavid Howells if (ncallbacks == 0) 41708e0e7c8SDavid Howells return 0; 41808e0e7c8SDavid Howells if (ncallbacks > AFSCBMAX) 41908e0e7c8SDavid Howells ncallbacks = AFSCBMAX; 42008e0e7c8SDavid Howells 42108e0e7c8SDavid Howells _debug("break %zu callbacks", ncallbacks); 42208e0e7c8SDavid Howells 42308e0e7c8SDavid Howells call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks, 42408e0e7c8SDavid Howells 12 + ncallbacks * 6 * 4, 0); 42508e0e7c8SDavid Howells if (!call) 42608e0e7c8SDavid Howells return -ENOMEM; 42708e0e7c8SDavid Howells 42808e0e7c8SDavid Howells call->service_id = FS_SERVICE; 42908e0e7c8SDavid Howells call->port = htons(AFS_FS_PORT); 43008e0e7c8SDavid Howells 43108e0e7c8SDavid Howells /* marshall the parameters */ 43208e0e7c8SDavid Howells bp = call->request; 43308e0e7c8SDavid Howells tp = bp + 2 + ncallbacks * 3; 43408e0e7c8SDavid Howells *bp++ = htonl(FSGIVEUPCALLBACKS); 43508e0e7c8SDavid Howells *bp++ = htonl(ncallbacks); 43608e0e7c8SDavid Howells *tp++ = htonl(ncallbacks); 43708e0e7c8SDavid Howells 43808e0e7c8SDavid Howells atomic_sub(ncallbacks, &server->cb_break_n); 43908e0e7c8SDavid Howells for (loop = ncallbacks; loop > 0; loop--) { 44008e0e7c8SDavid Howells struct afs_callback *cb = 44108e0e7c8SDavid Howells &server->cb_break[server->cb_break_tail]; 44208e0e7c8SDavid Howells 44308e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vid); 44408e0e7c8SDavid Howells *bp++ = htonl(cb->fid.vnode); 44508e0e7c8SDavid Howells *bp++ = htonl(cb->fid.unique); 44608e0e7c8SDavid Howells *tp++ = htonl(cb->version); 44708e0e7c8SDavid Howells *tp++ = htonl(cb->expiry); 44808e0e7c8SDavid Howells *tp++ = htonl(cb->type); 44908e0e7c8SDavid Howells smp_mb(); 45008e0e7c8SDavid Howells server->cb_break_tail = 45108e0e7c8SDavid Howells (server->cb_break_tail + 1) & 45208e0e7c8SDavid Howells (ARRAY_SIZE(server->cb_break) - 1); 453ec26815aSDavid Howells } 45408e0e7c8SDavid Howells 45508e0e7c8SDavid Howells ASSERT(ncallbacks > 0); 45608e0e7c8SDavid Howells wake_up_nr(&server->cb_break_waitq, ncallbacks); 45708e0e7c8SDavid Howells 45808e0e7c8SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 45908e0e7c8SDavid Howells } 460260a9803SDavid Howells 461260a9803SDavid Howells /* 462260a9803SDavid Howells * deliver reply data to an FS.CreateFile or an FS.MakeDir 463260a9803SDavid Howells */ 464260a9803SDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call, 465260a9803SDavid Howells struct sk_buff *skb, bool last) 466260a9803SDavid Howells { 467260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 468260a9803SDavid Howells const __be32 *bp; 469260a9803SDavid Howells 470260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 471260a9803SDavid Howells 472260a9803SDavid Howells afs_transfer_reply(call, skb); 473260a9803SDavid Howells if (!last) 474260a9803SDavid Howells return 0; 475260a9803SDavid Howells 476260a9803SDavid Howells if (call->reply_size != call->reply_max) 477260a9803SDavid Howells return -EBADMSG; 478260a9803SDavid Howells 479260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 480260a9803SDavid Howells bp = call->buffer; 481260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 482260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); 483260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 484260a9803SDavid Howells xdr_decode_AFSCallBack_raw(&bp, call->reply4); 485260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 486260a9803SDavid Howells 487260a9803SDavid Howells _leave(" = 0 [done]"); 488260a9803SDavid Howells return 0; 489260a9803SDavid Howells } 490260a9803SDavid Howells 491260a9803SDavid Howells /* 492260a9803SDavid Howells * FS.CreateFile and FS.MakeDir operation type 493260a9803SDavid Howells */ 494260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = { 495260a9803SDavid Howells .name = "FS.CreateXXXX", 496260a9803SDavid Howells .deliver = afs_deliver_fs_create_vnode, 497260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 498260a9803SDavid Howells .destructor = afs_flat_call_destructor, 499260a9803SDavid Howells }; 500260a9803SDavid Howells 501260a9803SDavid Howells /* 502260a9803SDavid Howells * create a file or make a directory 503260a9803SDavid Howells */ 504260a9803SDavid Howells int afs_fs_create(struct afs_server *server, 505260a9803SDavid Howells struct key *key, 506260a9803SDavid Howells struct afs_vnode *vnode, 507260a9803SDavid Howells const char *name, 508260a9803SDavid Howells umode_t mode, 509260a9803SDavid Howells struct afs_fid *newfid, 510260a9803SDavid Howells struct afs_file_status *newstatus, 511260a9803SDavid Howells struct afs_callback *newcb, 512260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 513260a9803SDavid Howells { 514260a9803SDavid Howells struct afs_call *call; 515260a9803SDavid Howells size_t namesz, reqsz, padsz; 516260a9803SDavid Howells __be32 *bp; 517260a9803SDavid Howells 518260a9803SDavid Howells _enter(""); 519260a9803SDavid Howells 520260a9803SDavid Howells namesz = strlen(name); 521260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 522260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (6 * 4); 523260a9803SDavid Howells 524260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz, 525260a9803SDavid Howells (3 + 21 + 21 + 3 + 6) * 4); 526260a9803SDavid Howells if (!call) 527260a9803SDavid Howells return -ENOMEM; 528260a9803SDavid Howells 529260a9803SDavid Howells call->key = key; 530260a9803SDavid Howells call->reply = vnode; 531260a9803SDavid Howells call->reply2 = newfid; 532260a9803SDavid Howells call->reply3 = newstatus; 533260a9803SDavid Howells call->reply4 = newcb; 534260a9803SDavid Howells call->service_id = FS_SERVICE; 535260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 536260a9803SDavid Howells 537260a9803SDavid Howells /* marshall the parameters */ 538260a9803SDavid Howells bp = call->request; 539260a9803SDavid Howells *bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE); 540260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 541260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 542260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 543260a9803SDavid Howells *bp++ = htonl(namesz); 544260a9803SDavid Howells memcpy(bp, name, namesz); 545260a9803SDavid Howells bp = (void *) bp + namesz; 546260a9803SDavid Howells if (padsz > 0) { 547260a9803SDavid Howells memset(bp, 0, padsz); 548260a9803SDavid Howells bp = (void *) bp + padsz; 549260a9803SDavid Howells } 550260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 551260a9803SDavid Howells *bp++ = 0; /* mtime */ 552260a9803SDavid Howells *bp++ = 0; /* owner */ 553260a9803SDavid Howells *bp++ = 0; /* group */ 554260a9803SDavid Howells *bp++ = htonl(mode & S_IALLUGO); /* unix mode */ 555260a9803SDavid Howells *bp++ = 0; /* segment size */ 556260a9803SDavid Howells 557260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 558260a9803SDavid Howells } 559260a9803SDavid Howells 560260a9803SDavid Howells /* 561260a9803SDavid Howells * deliver reply data to an FS.RemoveFile or FS.RemoveDir 562260a9803SDavid Howells */ 563260a9803SDavid Howells static int afs_deliver_fs_remove(struct afs_call *call, 564260a9803SDavid Howells struct sk_buff *skb, bool last) 565260a9803SDavid Howells { 566260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 567260a9803SDavid Howells const __be32 *bp; 568260a9803SDavid Howells 569260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 570260a9803SDavid Howells 571260a9803SDavid Howells afs_transfer_reply(call, skb); 572260a9803SDavid Howells if (!last) 573260a9803SDavid Howells return 0; 574260a9803SDavid Howells 575260a9803SDavid Howells if (call->reply_size != call->reply_max) 576260a9803SDavid Howells return -EBADMSG; 577260a9803SDavid Howells 578260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 579260a9803SDavid Howells bp = call->buffer; 580260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 581260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 582260a9803SDavid Howells 583260a9803SDavid Howells _leave(" = 0 [done]"); 584260a9803SDavid Howells return 0; 585260a9803SDavid Howells } 586260a9803SDavid Howells 587260a9803SDavid Howells /* 588260a9803SDavid Howells * FS.RemoveDir/FS.RemoveFile operation type 589260a9803SDavid Howells */ 590260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = { 591260a9803SDavid Howells .name = "FS.RemoveXXXX", 592260a9803SDavid Howells .deliver = afs_deliver_fs_remove, 593260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 594260a9803SDavid Howells .destructor = afs_flat_call_destructor, 595260a9803SDavid Howells }; 596260a9803SDavid Howells 597260a9803SDavid Howells /* 598260a9803SDavid Howells * remove a file or directory 599260a9803SDavid Howells */ 600260a9803SDavid Howells int afs_fs_remove(struct afs_server *server, 601260a9803SDavid Howells struct key *key, 602260a9803SDavid Howells struct afs_vnode *vnode, 603260a9803SDavid Howells const char *name, 604260a9803SDavid Howells bool isdir, 605260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 606260a9803SDavid Howells { 607260a9803SDavid Howells struct afs_call *call; 608260a9803SDavid Howells size_t namesz, reqsz, padsz; 609260a9803SDavid Howells __be32 *bp; 610260a9803SDavid Howells 611260a9803SDavid Howells _enter(""); 612260a9803SDavid Howells 613260a9803SDavid Howells namesz = strlen(name); 614260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 615260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz; 616260a9803SDavid Howells 617260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4); 618260a9803SDavid Howells if (!call) 619260a9803SDavid Howells return -ENOMEM; 620260a9803SDavid Howells 621260a9803SDavid Howells call->key = key; 622260a9803SDavid Howells call->reply = vnode; 623260a9803SDavid Howells call->service_id = FS_SERVICE; 624260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 625260a9803SDavid Howells 626260a9803SDavid Howells /* marshall the parameters */ 627260a9803SDavid Howells bp = call->request; 628260a9803SDavid Howells *bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE); 629260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 630260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 631260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 632260a9803SDavid Howells *bp++ = htonl(namesz); 633260a9803SDavid Howells memcpy(bp, name, namesz); 634260a9803SDavid Howells bp = (void *) bp + namesz; 635260a9803SDavid Howells if (padsz > 0) { 636260a9803SDavid Howells memset(bp, 0, padsz); 637260a9803SDavid Howells bp = (void *) bp + padsz; 638260a9803SDavid Howells } 639260a9803SDavid Howells 640260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 641260a9803SDavid Howells } 642260a9803SDavid Howells 643260a9803SDavid Howells /* 644260a9803SDavid Howells * deliver reply data to an FS.Link 645260a9803SDavid Howells */ 646260a9803SDavid Howells static int afs_deliver_fs_link(struct afs_call *call, 647260a9803SDavid Howells struct sk_buff *skb, bool last) 648260a9803SDavid Howells { 649260a9803SDavid Howells struct afs_vnode *dvnode = call->reply, *vnode = call->reply2; 650260a9803SDavid Howells const __be32 *bp; 651260a9803SDavid Howells 652260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 653260a9803SDavid Howells 654260a9803SDavid Howells afs_transfer_reply(call, skb); 655260a9803SDavid Howells if (!last) 656260a9803SDavid Howells return 0; 657260a9803SDavid Howells 658260a9803SDavid Howells if (call->reply_size != call->reply_max) 659260a9803SDavid Howells return -EBADMSG; 660260a9803SDavid Howells 661260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 662260a9803SDavid Howells bp = call->buffer; 663260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 664260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode); 665260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 666260a9803SDavid Howells 667260a9803SDavid Howells _leave(" = 0 [done]"); 668260a9803SDavid Howells return 0; 669260a9803SDavid Howells } 670260a9803SDavid Howells 671260a9803SDavid Howells /* 672260a9803SDavid Howells * FS.Link operation type 673260a9803SDavid Howells */ 674260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = { 675260a9803SDavid Howells .name = "FS.Link", 676260a9803SDavid Howells .deliver = afs_deliver_fs_link, 677260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 678260a9803SDavid Howells .destructor = afs_flat_call_destructor, 679260a9803SDavid Howells }; 680260a9803SDavid Howells 681260a9803SDavid Howells /* 682260a9803SDavid Howells * make a hard link 683260a9803SDavid Howells */ 684260a9803SDavid Howells int afs_fs_link(struct afs_server *server, 685260a9803SDavid Howells struct key *key, 686260a9803SDavid Howells struct afs_vnode *dvnode, 687260a9803SDavid Howells struct afs_vnode *vnode, 688260a9803SDavid Howells const char *name, 689260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 690260a9803SDavid Howells { 691260a9803SDavid Howells struct afs_call *call; 692260a9803SDavid Howells size_t namesz, reqsz, padsz; 693260a9803SDavid Howells __be32 *bp; 694260a9803SDavid Howells 695260a9803SDavid Howells _enter(""); 696260a9803SDavid Howells 697260a9803SDavid Howells namesz = strlen(name); 698260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 699260a9803SDavid Howells reqsz = (5 * 4) + namesz + padsz + (3 * 4); 700260a9803SDavid Howells 701260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4); 702260a9803SDavid Howells if (!call) 703260a9803SDavid Howells return -ENOMEM; 704260a9803SDavid Howells 705260a9803SDavid Howells call->key = key; 706260a9803SDavid Howells call->reply = dvnode; 707260a9803SDavid Howells call->reply2 = vnode; 708260a9803SDavid Howells call->service_id = FS_SERVICE; 709260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 710260a9803SDavid Howells 711260a9803SDavid Howells /* marshall the parameters */ 712260a9803SDavid Howells bp = call->request; 713260a9803SDavid Howells *bp++ = htonl(FSLINK); 714260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vid); 715260a9803SDavid Howells *bp++ = htonl(dvnode->fid.vnode); 716260a9803SDavid Howells *bp++ = htonl(dvnode->fid.unique); 717260a9803SDavid Howells *bp++ = htonl(namesz); 718260a9803SDavid Howells memcpy(bp, name, namesz); 719260a9803SDavid Howells bp = (void *) bp + namesz; 720260a9803SDavid Howells if (padsz > 0) { 721260a9803SDavid Howells memset(bp, 0, padsz); 722260a9803SDavid Howells bp = (void *) bp + padsz; 723260a9803SDavid Howells } 724260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 725260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 726260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 727260a9803SDavid Howells 728260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 729260a9803SDavid Howells } 730260a9803SDavid Howells 731260a9803SDavid Howells /* 732260a9803SDavid Howells * deliver reply data to an FS.Symlink 733260a9803SDavid Howells */ 734260a9803SDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call, 735260a9803SDavid Howells struct sk_buff *skb, bool last) 736260a9803SDavid Howells { 737260a9803SDavid Howells struct afs_vnode *vnode = call->reply; 738260a9803SDavid Howells const __be32 *bp; 739260a9803SDavid Howells 740260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 741260a9803SDavid Howells 742260a9803SDavid Howells afs_transfer_reply(call, skb); 743260a9803SDavid Howells if (!last) 744260a9803SDavid Howells return 0; 745260a9803SDavid Howells 746260a9803SDavid Howells if (call->reply_size != call->reply_max) 747260a9803SDavid Howells return -EBADMSG; 748260a9803SDavid Howells 749260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 750260a9803SDavid Howells bp = call->buffer; 751260a9803SDavid Howells xdr_decode_AFSFid(&bp, call->reply2); 752260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); 753260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); 754260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 755260a9803SDavid Howells 756260a9803SDavid Howells _leave(" = 0 [done]"); 757260a9803SDavid Howells return 0; 758260a9803SDavid Howells } 759260a9803SDavid Howells 760260a9803SDavid Howells /* 761260a9803SDavid Howells * FS.Symlink operation type 762260a9803SDavid Howells */ 763260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = { 764260a9803SDavid Howells .name = "FS.Symlink", 765260a9803SDavid Howells .deliver = afs_deliver_fs_symlink, 766260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 767260a9803SDavid Howells .destructor = afs_flat_call_destructor, 768260a9803SDavid Howells }; 769260a9803SDavid Howells 770260a9803SDavid Howells /* 771260a9803SDavid Howells * create a symbolic link 772260a9803SDavid Howells */ 773260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server, 774260a9803SDavid Howells struct key *key, 775260a9803SDavid Howells struct afs_vnode *vnode, 776260a9803SDavid Howells const char *name, 777260a9803SDavid Howells const char *contents, 778260a9803SDavid Howells struct afs_fid *newfid, 779260a9803SDavid Howells struct afs_file_status *newstatus, 780260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 781260a9803SDavid Howells { 782260a9803SDavid Howells struct afs_call *call; 783260a9803SDavid Howells size_t namesz, reqsz, padsz, c_namesz, c_padsz; 784260a9803SDavid Howells __be32 *bp; 785260a9803SDavid Howells 786260a9803SDavid Howells _enter(""); 787260a9803SDavid Howells 788260a9803SDavid Howells namesz = strlen(name); 789260a9803SDavid Howells padsz = (4 - (namesz & 3)) & 3; 790260a9803SDavid Howells 791260a9803SDavid Howells c_namesz = strlen(contents); 792260a9803SDavid Howells c_padsz = (4 - (c_namesz & 3)) & 3; 793260a9803SDavid Howells 794260a9803SDavid Howells reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4); 795260a9803SDavid Howells 796260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz, 797260a9803SDavid Howells (3 + 21 + 21 + 6) * 4); 798260a9803SDavid Howells if (!call) 799260a9803SDavid Howells return -ENOMEM; 800260a9803SDavid Howells 801260a9803SDavid Howells call->key = key; 802260a9803SDavid Howells call->reply = vnode; 803260a9803SDavid Howells call->reply2 = newfid; 804260a9803SDavid Howells call->reply3 = newstatus; 805260a9803SDavid Howells call->service_id = FS_SERVICE; 806260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 807260a9803SDavid Howells 808260a9803SDavid Howells /* marshall the parameters */ 809260a9803SDavid Howells bp = call->request; 810260a9803SDavid Howells *bp++ = htonl(FSSYMLINK); 811260a9803SDavid Howells *bp++ = htonl(vnode->fid.vid); 812260a9803SDavid Howells *bp++ = htonl(vnode->fid.vnode); 813260a9803SDavid Howells *bp++ = htonl(vnode->fid.unique); 814260a9803SDavid Howells *bp++ = htonl(namesz); 815260a9803SDavid Howells memcpy(bp, name, namesz); 816260a9803SDavid Howells bp = (void *) bp + namesz; 817260a9803SDavid Howells if (padsz > 0) { 818260a9803SDavid Howells memset(bp, 0, padsz); 819260a9803SDavid Howells bp = (void *) bp + padsz; 820260a9803SDavid Howells } 821260a9803SDavid Howells *bp++ = htonl(c_namesz); 822260a9803SDavid Howells memcpy(bp, contents, c_namesz); 823260a9803SDavid Howells bp = (void *) bp + c_namesz; 824260a9803SDavid Howells if (c_padsz > 0) { 825260a9803SDavid Howells memset(bp, 0, c_padsz); 826260a9803SDavid Howells bp = (void *) bp + c_padsz; 827260a9803SDavid Howells } 828260a9803SDavid Howells *bp++ = htonl(AFS_SET_MODE); 829260a9803SDavid Howells *bp++ = 0; /* mtime */ 830260a9803SDavid Howells *bp++ = 0; /* owner */ 831260a9803SDavid Howells *bp++ = 0; /* group */ 832260a9803SDavid Howells *bp++ = htonl(S_IRWXUGO); /* unix mode */ 833260a9803SDavid Howells *bp++ = 0; /* segment size */ 834260a9803SDavid Howells 835260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 836260a9803SDavid Howells } 837260a9803SDavid Howells 838260a9803SDavid Howells /* 839260a9803SDavid Howells * deliver reply data to an FS.Rename 840260a9803SDavid Howells */ 841260a9803SDavid Howells static int afs_deliver_fs_rename(struct afs_call *call, 842260a9803SDavid Howells struct sk_buff *skb, bool last) 843260a9803SDavid Howells { 844260a9803SDavid Howells struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2; 845260a9803SDavid Howells const __be32 *bp; 846260a9803SDavid Howells 847260a9803SDavid Howells _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); 848260a9803SDavid Howells 849260a9803SDavid Howells afs_transfer_reply(call, skb); 850260a9803SDavid Howells if (!last) 851260a9803SDavid Howells return 0; 852260a9803SDavid Howells 853260a9803SDavid Howells if (call->reply_size != call->reply_max) 854260a9803SDavid Howells return -EBADMSG; 855260a9803SDavid Howells 856260a9803SDavid Howells /* unmarshall the reply once we've received all of it */ 857260a9803SDavid Howells bp = call->buffer; 858260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode); 859260a9803SDavid Howells if (new_dvnode != orig_dvnode) 860260a9803SDavid Howells xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode); 861260a9803SDavid Howells /* xdr_decode_AFSVolSync(&bp, call->replyX); */ 862260a9803SDavid Howells 863260a9803SDavid Howells _leave(" = 0 [done]"); 864260a9803SDavid Howells return 0; 865260a9803SDavid Howells } 866260a9803SDavid Howells 867260a9803SDavid Howells /* 868260a9803SDavid Howells * FS.Rename operation type 869260a9803SDavid Howells */ 870260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = { 871260a9803SDavid Howells .name = "FS.Rename", 872260a9803SDavid Howells .deliver = afs_deliver_fs_rename, 873260a9803SDavid Howells .abort_to_error = afs_abort_to_error, 874260a9803SDavid Howells .destructor = afs_flat_call_destructor, 875260a9803SDavid Howells }; 876260a9803SDavid Howells 877260a9803SDavid Howells /* 878260a9803SDavid Howells * create a symbolic link 879260a9803SDavid Howells */ 880260a9803SDavid Howells int afs_fs_rename(struct afs_server *server, 881260a9803SDavid Howells struct key *key, 882260a9803SDavid Howells struct afs_vnode *orig_dvnode, 883260a9803SDavid Howells const char *orig_name, 884260a9803SDavid Howells struct afs_vnode *new_dvnode, 885260a9803SDavid Howells const char *new_name, 886260a9803SDavid Howells const struct afs_wait_mode *wait_mode) 887260a9803SDavid Howells { 888260a9803SDavid Howells struct afs_call *call; 889260a9803SDavid Howells size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz; 890260a9803SDavid Howells __be32 *bp; 891260a9803SDavid Howells 892260a9803SDavid Howells _enter(""); 893260a9803SDavid Howells 894260a9803SDavid Howells o_namesz = strlen(orig_name); 895260a9803SDavid Howells o_padsz = (4 - (o_namesz & 3)) & 3; 896260a9803SDavid Howells 897260a9803SDavid Howells n_namesz = strlen(new_name); 898260a9803SDavid Howells n_padsz = (4 - (n_namesz & 3)) & 3; 899260a9803SDavid Howells 900260a9803SDavid Howells reqsz = (4 * 4) + 901260a9803SDavid Howells 4 + o_namesz + o_padsz + 902260a9803SDavid Howells (3 * 4) + 903260a9803SDavid Howells 4 + n_namesz + n_padsz; 904260a9803SDavid Howells 905260a9803SDavid Howells call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4); 906260a9803SDavid Howells if (!call) 907260a9803SDavid Howells return -ENOMEM; 908260a9803SDavid Howells 909260a9803SDavid Howells call->key = key; 910260a9803SDavid Howells call->reply = orig_dvnode; 911260a9803SDavid Howells call->reply2 = new_dvnode; 912260a9803SDavid Howells call->service_id = FS_SERVICE; 913260a9803SDavid Howells call->port = htons(AFS_FS_PORT); 914260a9803SDavid Howells 915260a9803SDavid Howells /* marshall the parameters */ 916260a9803SDavid Howells bp = call->request; 917260a9803SDavid Howells *bp++ = htonl(FSRENAME); 918260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vid); 919260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.vnode); 920260a9803SDavid Howells *bp++ = htonl(orig_dvnode->fid.unique); 921260a9803SDavid Howells *bp++ = htonl(o_namesz); 922260a9803SDavid Howells memcpy(bp, orig_name, o_namesz); 923260a9803SDavid Howells bp = (void *) bp + o_namesz; 924260a9803SDavid Howells if (o_padsz > 0) { 925260a9803SDavid Howells memset(bp, 0, o_padsz); 926260a9803SDavid Howells bp = (void *) bp + o_padsz; 927260a9803SDavid Howells } 928260a9803SDavid Howells 929260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vid); 930260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.vnode); 931260a9803SDavid Howells *bp++ = htonl(new_dvnode->fid.unique); 932260a9803SDavid Howells *bp++ = htonl(n_namesz); 933260a9803SDavid Howells memcpy(bp, new_name, n_namesz); 934260a9803SDavid Howells bp = (void *) bp + n_namesz; 935260a9803SDavid Howells if (n_padsz > 0) { 936260a9803SDavid Howells memset(bp, 0, n_padsz); 937260a9803SDavid Howells bp = (void *) bp + n_padsz; 938260a9803SDavid Howells } 939260a9803SDavid Howells 940260a9803SDavid Howells return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); 941260a9803SDavid Howells } 942