2007-04-27 02:55:03 +04:00
/* AFS File Server client stubs
2005-04-17 02:20:36 +04:00
*
2007-04-27 02:55:03 +04:00
* Copyright ( C ) 2002 , 2007 Red Hat , Inc . All Rights Reserved .
2005-04-17 02:20:36 +04:00
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/init.h>
# include <linux/sched.h>
2007-04-27 02:55:03 +04:00
# include <linux/circ_buf.h>
2005-04-17 02:20:36 +04:00
# include "internal.h"
2007-04-27 02:55:03 +04:00
# include "afs_fs.h"
2005-04-17 02:20:36 +04:00
2007-04-27 02:59:35 +04:00
/*
* decode an AFSFid block
*/
static void xdr_decode_AFSFid ( const __be32 * * _bp , struct afs_fid * fid )
{
const __be32 * bp = * _bp ;
fid - > vid = ntohl ( * bp + + ) ;
fid - > vnode = ntohl ( * bp + + ) ;
fid - > unique = ntohl ( * bp + + ) ;
* _bp = bp ;
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* decode an AFSFetchStatus block
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
static void xdr_decode_AFSFetchStatus ( const __be32 * * _bp ,
2007-04-27 02:59:35 +04:00
struct afs_file_status * status ,
2007-04-27 02:55:03 +04:00
struct afs_vnode * vnode )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
const __be32 * bp = * _bp ;
umode_t mode ;
2007-04-27 02:59:35 +04:00
u64 data_version , size ;
2007-04-27 02:55:03 +04:00
u32 changed = 0 ; /* becomes non-zero if ctime-type changes seen */
# define EXTRACT(DST) \
do { \
u32 x = ntohl ( * bp + + ) ; \
changed | = DST - x ; \
DST = x ; \
} while ( 0 )
2007-04-27 02:59:35 +04:00
status - > if_version = ntohl ( * bp + + ) ;
EXTRACT ( status - > type ) ;
EXTRACT ( status - > nlink ) ;
size = ntohl ( * bp + + ) ;
2007-04-27 02:55:03 +04:00
data_version = ntohl ( * bp + + ) ;
2007-04-27 02:59:35 +04:00
EXTRACT ( status - > author ) ;
EXTRACT ( status - > owner ) ;
EXTRACT ( status - > caller_access ) ; /* call ticket dependent */
EXTRACT ( status - > anon_access ) ;
EXTRACT ( status - > mode ) ;
EXTRACT ( status - > parent . vnode ) ;
EXTRACT ( status - > parent . unique ) ;
2007-04-27 02:55:03 +04:00
bp + + ; /* seg size */
2007-04-27 02:59:35 +04:00
status - > mtime_client = ntohl ( * bp + + ) ;
status - > mtime_server = ntohl ( * bp + + ) ;
EXTRACT ( status - > group ) ;
2007-04-27 02:55:03 +04:00
bp + + ; /* sync counter */
data_version | = ( u64 ) ntohl ( * bp + + ) < < 32 ;
2007-04-27 02:59:35 +04:00
bp + + ; /* lock count */
size | = ( u64 ) ntohl ( * bp + + ) < < 32 ;
bp + + ; /* spare 4 */
2007-04-27 02:55:03 +04:00
* _bp = bp ;
2007-04-27 02:59:35 +04:00
if ( size ! = status - > size ) {
status - > size = size ;
changed | = true ;
2007-04-27 02:55:03 +04:00
}
2007-04-27 02:59:35 +04:00
status - > mode & = S_IALLUGO ;
2007-04-27 02:55:03 +04:00
_debug ( " vnode time %lx, %lx " ,
2007-04-27 02:59:35 +04:00
status - > mtime_client , status - > mtime_server ) ;
if ( vnode ) {
status - > parent . vid = vnode - > fid . vid ;
if ( changed & & ! test_bit ( AFS_VNODE_UNSET , & vnode - > flags ) ) {
_debug ( " vnode changed " ) ;
i_size_write ( & vnode - > vfs_inode , size ) ;
vnode - > vfs_inode . i_uid = status - > owner ;
vnode - > vfs_inode . i_gid = status - > group ;
vnode - > vfs_inode . i_version = vnode - > fid . unique ;
vnode - > vfs_inode . i_nlink = status - > nlink ;
mode = vnode - > vfs_inode . i_mode ;
mode & = ~ S_IALLUGO ;
mode | = status - > mode ;
barrier ( ) ;
vnode - > vfs_inode . i_mode = mode ;
}
vnode - > vfs_inode . i_ctime . tv_sec = status - > mtime_server ;
vnode - > vfs_inode . i_mtime = vnode - > vfs_inode . i_ctime ;
vnode - > vfs_inode . i_atime = vnode - > vfs_inode . i_ctime ;
}
if ( status - > data_version ! = data_version ) {
status - > data_version = data_version ;
if ( vnode & & ! test_bit ( AFS_VNODE_UNSET , & vnode - > flags ) ) {
_debug ( " vnode modified %llx on {%x:%u} " ,
2007-04-27 03:06:22 +04:00
( unsigned long long ) data_version ,
vnode - > fid . vid , vnode - > fid . vnode ) ;
2007-04-27 02:59:35 +04:00
set_bit ( AFS_VNODE_MODIFIED , & vnode - > flags ) ;
set_bit ( AFS_VNODE_ZAP_DATA , & vnode - > flags ) ;
}
2005-04-17 02:20:36 +04:00
}
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* decode an AFSCallBack block
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
static void xdr_decode_AFSCallBack ( const __be32 * * _bp , struct afs_vnode * vnode )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
const __be32 * bp = * _bp ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
vnode - > cb_version = ntohl ( * bp + + ) ;
vnode - > cb_expiry = ntohl ( * bp + + ) ;
vnode - > cb_type = ntohl ( * bp + + ) ;
vnode - > cb_expires = vnode - > cb_expiry + get_seconds ( ) ;
* _bp = bp ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:59:35 +04:00
static void xdr_decode_AFSCallBack_raw ( const __be32 * * _bp ,
struct afs_callback * cb )
{
const __be32 * bp = * _bp ;
cb - > version = ntohl ( * bp + + ) ;
cb - > expiry = ntohl ( * bp + + ) ;
cb - > type = ntohl ( * bp + + ) ;
* _bp = bp ;
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* decode an AFSVolSync block
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
static void xdr_decode_AFSVolSync ( const __be32 * * _bp ,
struct afs_volsync * volsync )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
const __be32 * bp = * _bp ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
volsync - > creation = ntohl ( * bp + + ) ;
bp + + ; /* spare2 */
bp + + ; /* spare3 */
bp + + ; /* spare4 */
bp + + ; /* spare5 */
bp + + ; /* spare6 */
* _bp = bp ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/*
* deliver reply data to an FS . FetchStatus
*/
static int afs_deliver_fs_fetch_status ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
2007-04-27 02:59:35 +04:00
struct afs_vnode * vnode = call - > reply ;
2007-04-27 02:55:03 +04:00
const __be32 * bp ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_enter ( " ,,%u " , last ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
2007-04-27 02:59:35 +04:00
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
xdr_decode_AFSCallBack ( & bp , vnode ) ;
2007-04-27 02:55:03 +04:00
if ( call - > reply2 )
xdr_decode_AFSVolSync ( & bp , call - > reply2 ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_leave ( " = 0 [done] " ) ;
return 0 ;
2007-04-27 02:49:28 +04:00
}
2007-04-27 02:55:03 +04:00
/*
* FS . FetchStatus operation type
*/
static const struct afs_call_type afs_RXFSFetchStatus = {
2007-04-27 02:57:07 +04:00
. name = " FS.FetchStatus " ,
2007-04-27 02:55:03 +04:00
. deliver = afs_deliver_fs_fetch_status ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
2005-04-17 02:20:36 +04:00
/*
* fetch the status information for a file
*/
2007-04-27 02:55:03 +04:00
int afs_fs_fetch_file_status ( struct afs_server * server ,
2007-04-27 02:57:07 +04:00
struct key * key ,
2007-04-27 02:55:03 +04:00
struct afs_vnode * vnode ,
struct afs_volsync * volsync ,
const struct afs_wait_mode * wait_mode )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
struct afs_call * call ;
2005-04-17 02:20:36 +04:00
__be32 * bp ;
2007-04-27 02:59:35 +04:00
_enter ( " ,%x,{%x:%d},, " ,
key_serial ( key ) , vnode - > fid . vid , vnode - > fid . vnode ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:59:35 +04:00
call = afs_alloc_flat_call ( & afs_RXFSFetchStatus , 16 , ( 21 + 3 + 6 ) * 4 ) ;
2007-04-27 02:55:03 +04:00
if ( ! call )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:57:07 +04:00
call - > key = key ;
2007-04-27 02:55:03 +04:00
call - > reply = vnode ;
call - > reply2 = volsync ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
2005-04-17 02:20:36 +04:00
/* marshall the parameters */
2007-04-27 02:55:03 +04:00
bp = call - > request ;
2005-04-17 02:20:36 +04:00
bp [ 0 ] = htonl ( FSFETCHSTATUS ) ;
bp [ 1 ] = htonl ( vnode - > fid . vid ) ;
bp [ 2 ] = htonl ( vnode - > fid . vnode ) ;
bp [ 3 ] = htonl ( vnode - > fid . unique ) ;
2007-04-27 02:55:03 +04:00
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* deliver reply data to an FS . FetchData
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
static int afs_deliver_fs_fetch_data ( struct afs_call * call ,
struct sk_buff * skb , bool last )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:59:35 +04:00
struct afs_vnode * vnode = call - > reply ;
2007-04-27 02:55:03 +04:00
const __be32 * bp ;
struct page * page ;
void * buffer ;
2005-04-17 02:20:36 +04:00
int ret ;
2007-04-27 02:55:03 +04:00
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
switch ( call - > unmarshall ) {
case 0 :
call - > offset = 0 ;
call - > unmarshall + + ;
/* extract the returned data length */
case 1 :
_debug ( " extract data length " ) ;
ret = afs_extract_data ( call , skb , last , & call - > tmp , 4 ) ;
switch ( ret ) {
case 0 : break ;
case - EAGAIN : return 0 ;
default : return ret ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
call - > count = ntohl ( call - > tmp ) ;
_debug ( " DATA length: %u " , call - > count ) ;
if ( call - > count > PAGE_SIZE )
return - EBADMSG ;
call - > offset = 0 ;
call - > unmarshall + + ;
if ( call - > count < PAGE_SIZE ) {
2007-05-03 14:11:29 +04:00
page = call - > reply3 ;
buffer = kmap_atomic ( page , KM_USER0 ) ;
2007-04-27 02:55:03 +04:00
memset ( buffer + PAGE_SIZE - call - > count , 0 ,
call - > count ) ;
kunmap_atomic ( buffer , KM_USER0 ) ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/* extract the returned data */
case 2 :
_debug ( " extract data " ) ;
page = call - > reply3 ;
buffer = kmap_atomic ( page , KM_USER0 ) ;
ret = afs_extract_data ( call , skb , last , buffer , call - > count ) ;
kunmap_atomic ( buffer , KM_USER0 ) ;
switch ( ret ) {
case 0 : break ;
case - EAGAIN : return 0 ;
default : return ret ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
call - > offset = 0 ;
call - > unmarshall + + ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/* extract the metadata */
case 3 :
2007-04-27 02:59:35 +04:00
ret = afs_extract_data ( call , skb , last , call - > buffer ,
( 21 + 3 + 6 ) * 4 ) ;
2007-04-27 02:55:03 +04:00
switch ( ret ) {
case 0 : break ;
case - EAGAIN : return 0 ;
default : return ret ;
}
bp = call - > buffer ;
2007-04-27 02:59:35 +04:00
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
xdr_decode_AFSCallBack ( & bp , vnode ) ;
2007-04-27 02:55:03 +04:00
if ( call - > reply2 )
xdr_decode_AFSVolSync ( & bp , call - > reply2 ) ;
call - > offset = 0 ;
call - > unmarshall + + ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
case 4 :
_debug ( " trailer " ) ;
if ( skb - > len ! = 0 )
return - EBADMSG ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 02:55:03 +04:00
if ( ! last )
return 0 ;
_leave ( " = 0 [done] " ) ;
return 0 ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* FS . FetchData operation type
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
static const struct afs_call_type afs_RXFSFetchData = {
2007-04-27 02:57:07 +04:00
. name = " FS.FetchData " ,
2007-04-27 02:55:03 +04:00
. deliver = afs_deliver_fs_fetch_data ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* fetch data from a file
*/
int afs_fs_fetch_data ( struct afs_server * server ,
2007-04-27 02:57:07 +04:00
struct key * key ,
2007-04-27 02:55:03 +04:00
struct afs_vnode * vnode ,
off_t offset , size_t length ,
struct page * buffer ,
const struct afs_wait_mode * wait_mode )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
struct afs_call * call ;
2005-04-17 02:20:36 +04:00
__be32 * bp ;
2007-04-27 02:55:03 +04:00
_enter ( " " ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:59:35 +04:00
call = afs_alloc_flat_call ( & afs_RXFSFetchData , 24 , ( 21 + 3 + 6 ) * 4 ) ;
2007-04-27 02:55:03 +04:00
if ( ! call )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:57:07 +04:00
call - > key = key ;
2007-04-27 02:55:03 +04:00
call - > reply = vnode ;
2007-04-27 02:59:35 +04:00
call - > reply2 = NULL ; /* volsync */
2007-04-27 02:55:03 +04:00
call - > reply3 = buffer ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
2005-04-17 02:20:36 +04:00
/* marshall the parameters */
2007-04-27 02:55:03 +04:00
bp = call - > request ;
bp [ 0 ] = htonl ( FSFETCHDATA ) ;
bp [ 1 ] = htonl ( vnode - > fid . vid ) ;
bp [ 2 ] = htonl ( vnode - > fid . vnode ) ;
bp [ 3 ] = htonl ( vnode - > fid . unique ) ;
bp [ 4 ] = htonl ( offset ) ;
bp [ 5 ] = htonl ( length ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
/*
* deliver reply data to an FS . GiveUpCallBacks
*/
static int afs_deliver_fs_give_up_callbacks ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
_enter ( " ,{%u},%d " , skb - > len , last ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
if ( skb - > len > 0 )
return - EBADMSG ; /* shouldn't be any reply data */
return 0 ;
2007-04-27 02:49:28 +04:00
}
2005-04-17 02:20:36 +04:00
/*
2007-04-27 02:55:03 +04:00
* FS . GiveUpCallBacks operation type
*/
static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
2007-04-27 02:57:07 +04:00
. name = " FS.GiveUpCallBacks " ,
2007-04-27 02:55:03 +04:00
. deliver = afs_deliver_fs_give_up_callbacks ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* give up a set of callbacks
* - the callbacks are held in the server - > cb_break ring
2005-04-17 02:20:36 +04:00
*/
2007-04-27 02:55:03 +04:00
int afs_fs_give_up_callbacks ( struct afs_server * server ,
const struct afs_wait_mode * wait_mode )
2005-04-17 02:20:36 +04:00
{
2007-04-27 02:55:03 +04:00
struct afs_call * call ;
size_t ncallbacks ;
__be32 * bp , * tp ;
int loop ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
ncallbacks = CIRC_CNT ( server - > cb_break_head , server - > cb_break_tail ,
ARRAY_SIZE ( server - > cb_break ) ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_enter ( " {%zu}, " , ncallbacks ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
if ( ncallbacks = = 0 )
return 0 ;
if ( ncallbacks > AFSCBMAX )
ncallbacks = AFSCBMAX ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
_debug ( " break %zu callbacks " , ncallbacks ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
call = afs_alloc_flat_call ( & afs_RXFSGiveUpCallBacks ,
12 + ncallbacks * 6 * 4 , 0 ) ;
if ( ! call )
return - ENOMEM ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
2005-04-17 02:20:36 +04:00
/* marshall the parameters */
2007-04-27 02:55:03 +04:00
bp = call - > request ;
tp = bp + 2 + ncallbacks * 3 ;
* bp + + = htonl ( FSGIVEUPCALLBACKS ) ;
* bp + + = htonl ( ncallbacks ) ;
* tp + + = htonl ( ncallbacks ) ;
atomic_sub ( ncallbacks , & server - > cb_break_n ) ;
for ( loop = ncallbacks ; loop > 0 ; loop - - ) {
struct afs_callback * cb =
& server - > cb_break [ server - > cb_break_tail ] ;
* bp + + = htonl ( cb - > fid . vid ) ;
* bp + + = htonl ( cb - > fid . vnode ) ;
* bp + + = htonl ( cb - > fid . unique ) ;
* tp + + = htonl ( cb - > version ) ;
* tp + + = htonl ( cb - > expiry ) ;
* tp + + = htonl ( cb - > type ) ;
smp_mb ( ) ;
server - > cb_break_tail =
( server - > cb_break_tail + 1 ) &
( ARRAY_SIZE ( server - > cb_break ) - 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-27 02:55:03 +04:00
ASSERT ( ncallbacks > 0 ) ;
wake_up_nr ( & server - > cb_break_waitq , ncallbacks ) ;
2005-04-17 02:20:36 +04:00
2007-04-27 02:55:03 +04:00
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
2007-04-27 02:49:28 +04:00
}
2007-04-27 02:59:35 +04:00
/*
* deliver reply data to an FS . CreateFile or an FS . MakeDir
*/
static int afs_deliver_fs_create_vnode ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
struct afs_vnode * vnode = call - > reply ;
const __be32 * bp ;
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
xdr_decode_AFSFid ( & bp , call - > reply2 ) ;
xdr_decode_AFSFetchStatus ( & bp , call - > reply3 , NULL ) ;
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
xdr_decode_AFSCallBack_raw ( & bp , call - > reply4 ) ;
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave ( " = 0 [done] " ) ;
return 0 ;
}
/*
* FS . CreateFile and FS . MakeDir operation type
*/
static const struct afs_call_type afs_RXFSCreateXXXX = {
. name = " FS.CreateXXXX " ,
. deliver = afs_deliver_fs_create_vnode ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* create a file or make a directory
*/
int afs_fs_create ( struct afs_server * server ,
struct key * key ,
struct afs_vnode * vnode ,
const char * name ,
umode_t mode ,
struct afs_fid * newfid ,
struct afs_file_status * newstatus ,
struct afs_callback * newcb ,
const struct afs_wait_mode * wait_mode )
{
struct afs_call * call ;
size_t namesz , reqsz , padsz ;
__be32 * bp ;
_enter ( " " ) ;
namesz = strlen ( name ) ;
padsz = ( 4 - ( namesz & 3 ) ) & 3 ;
reqsz = ( 5 * 4 ) + namesz + padsz + ( 6 * 4 ) ;
call = afs_alloc_flat_call ( & afs_RXFSCreateXXXX , reqsz ,
( 3 + 21 + 21 + 3 + 6 ) * 4 ) ;
if ( ! call )
return - ENOMEM ;
call - > key = key ;
call - > reply = vnode ;
call - > reply2 = newfid ;
call - > reply3 = newstatus ;
call - > reply4 = newcb ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
/* marshall the parameters */
bp = call - > request ;
* bp + + = htonl ( S_ISDIR ( mode ) ? FSMAKEDIR : FSCREATEFILE ) ;
* bp + + = htonl ( vnode - > fid . vid ) ;
* bp + + = htonl ( vnode - > fid . vnode ) ;
* bp + + = htonl ( vnode - > fid . unique ) ;
* bp + + = htonl ( namesz ) ;
memcpy ( bp , name , namesz ) ;
bp = ( void * ) bp + namesz ;
if ( padsz > 0 ) {
memset ( bp , 0 , padsz ) ;
bp = ( void * ) bp + padsz ;
}
* bp + + = htonl ( AFS_SET_MODE ) ;
* bp + + = 0 ; /* mtime */
* bp + + = 0 ; /* owner */
* bp + + = 0 ; /* group */
* bp + + = htonl ( mode & S_IALLUGO ) ; /* unix mode */
* bp + + = 0 ; /* segment size */
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}
/*
* deliver reply data to an FS . RemoveFile or FS . RemoveDir
*/
static int afs_deliver_fs_remove ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
struct afs_vnode * vnode = call - > reply ;
const __be32 * bp ;
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave ( " = 0 [done] " ) ;
return 0 ;
}
/*
* FS . RemoveDir / FS . RemoveFile operation type
*/
static const struct afs_call_type afs_RXFSRemoveXXXX = {
. name = " FS.RemoveXXXX " ,
. deliver = afs_deliver_fs_remove ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* remove a file or directory
*/
int afs_fs_remove ( struct afs_server * server ,
struct key * key ,
struct afs_vnode * vnode ,
const char * name ,
bool isdir ,
const struct afs_wait_mode * wait_mode )
{
struct afs_call * call ;
size_t namesz , reqsz , padsz ;
__be32 * bp ;
_enter ( " " ) ;
namesz = strlen ( name ) ;
padsz = ( 4 - ( namesz & 3 ) ) & 3 ;
reqsz = ( 5 * 4 ) + namesz + padsz ;
call = afs_alloc_flat_call ( & afs_RXFSRemoveXXXX , reqsz , ( 21 + 6 ) * 4 ) ;
if ( ! call )
return - ENOMEM ;
call - > key = key ;
call - > reply = vnode ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
/* marshall the parameters */
bp = call - > request ;
* bp + + = htonl ( isdir ? FSREMOVEDIR : FSREMOVEFILE ) ;
* bp + + = htonl ( vnode - > fid . vid ) ;
* bp + + = htonl ( vnode - > fid . vnode ) ;
* bp + + = htonl ( vnode - > fid . unique ) ;
* bp + + = htonl ( namesz ) ;
memcpy ( bp , name , namesz ) ;
bp = ( void * ) bp + namesz ;
if ( padsz > 0 ) {
memset ( bp , 0 , padsz ) ;
bp = ( void * ) bp + padsz ;
}
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}
/*
* deliver reply data to an FS . Link
*/
static int afs_deliver_fs_link ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
struct afs_vnode * dvnode = call - > reply , * vnode = call - > reply2 ;
const __be32 * bp ;
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
xdr_decode_AFSFetchStatus ( & bp , & dvnode - > status , dvnode ) ;
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave ( " = 0 [done] " ) ;
return 0 ;
}
/*
* FS . Link operation type
*/
static const struct afs_call_type afs_RXFSLink = {
. name = " FS.Link " ,
. deliver = afs_deliver_fs_link ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* make a hard link
*/
int afs_fs_link ( struct afs_server * server ,
struct key * key ,
struct afs_vnode * dvnode ,
struct afs_vnode * vnode ,
const char * name ,
const struct afs_wait_mode * wait_mode )
{
struct afs_call * call ;
size_t namesz , reqsz , padsz ;
__be32 * bp ;
_enter ( " " ) ;
namesz = strlen ( name ) ;
padsz = ( 4 - ( namesz & 3 ) ) & 3 ;
reqsz = ( 5 * 4 ) + namesz + padsz + ( 3 * 4 ) ;
call = afs_alloc_flat_call ( & afs_RXFSLink , reqsz , ( 21 + 21 + 6 ) * 4 ) ;
if ( ! call )
return - ENOMEM ;
call - > key = key ;
call - > reply = dvnode ;
call - > reply2 = vnode ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
/* marshall the parameters */
bp = call - > request ;
* bp + + = htonl ( FSLINK ) ;
* bp + + = htonl ( dvnode - > fid . vid ) ;
* bp + + = htonl ( dvnode - > fid . vnode ) ;
* bp + + = htonl ( dvnode - > fid . unique ) ;
* bp + + = htonl ( namesz ) ;
memcpy ( bp , name , namesz ) ;
bp = ( void * ) bp + namesz ;
if ( padsz > 0 ) {
memset ( bp , 0 , padsz ) ;
bp = ( void * ) bp + padsz ;
}
* bp + + = htonl ( vnode - > fid . vid ) ;
* bp + + = htonl ( vnode - > fid . vnode ) ;
* bp + + = htonl ( vnode - > fid . unique ) ;
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}
/*
* deliver reply data to an FS . Symlink
*/
static int afs_deliver_fs_symlink ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
struct afs_vnode * vnode = call - > reply ;
const __be32 * bp ;
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
xdr_decode_AFSFid ( & bp , call - > reply2 ) ;
xdr_decode_AFSFetchStatus ( & bp , call - > reply3 , NULL ) ;
xdr_decode_AFSFetchStatus ( & bp , & vnode - > status , vnode ) ;
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave ( " = 0 [done] " ) ;
return 0 ;
}
/*
* FS . Symlink operation type
*/
static const struct afs_call_type afs_RXFSSymlink = {
. name = " FS.Symlink " ,
. deliver = afs_deliver_fs_symlink ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* create a symbolic link
*/
int afs_fs_symlink ( struct afs_server * server ,
struct key * key ,
struct afs_vnode * vnode ,
const char * name ,
const char * contents ,
struct afs_fid * newfid ,
struct afs_file_status * newstatus ,
const struct afs_wait_mode * wait_mode )
{
struct afs_call * call ;
size_t namesz , reqsz , padsz , c_namesz , c_padsz ;
__be32 * bp ;
_enter ( " " ) ;
namesz = strlen ( name ) ;
padsz = ( 4 - ( namesz & 3 ) ) & 3 ;
c_namesz = strlen ( contents ) ;
c_padsz = ( 4 - ( c_namesz & 3 ) ) & 3 ;
reqsz = ( 6 * 4 ) + namesz + padsz + c_namesz + c_padsz + ( 6 * 4 ) ;
call = afs_alloc_flat_call ( & afs_RXFSSymlink , reqsz ,
( 3 + 21 + 21 + 6 ) * 4 ) ;
if ( ! call )
return - ENOMEM ;
call - > key = key ;
call - > reply = vnode ;
call - > reply2 = newfid ;
call - > reply3 = newstatus ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
/* marshall the parameters */
bp = call - > request ;
* bp + + = htonl ( FSSYMLINK ) ;
* bp + + = htonl ( vnode - > fid . vid ) ;
* bp + + = htonl ( vnode - > fid . vnode ) ;
* bp + + = htonl ( vnode - > fid . unique ) ;
* bp + + = htonl ( namesz ) ;
memcpy ( bp , name , namesz ) ;
bp = ( void * ) bp + namesz ;
if ( padsz > 0 ) {
memset ( bp , 0 , padsz ) ;
bp = ( void * ) bp + padsz ;
}
* bp + + = htonl ( c_namesz ) ;
memcpy ( bp , contents , c_namesz ) ;
bp = ( void * ) bp + c_namesz ;
if ( c_padsz > 0 ) {
memset ( bp , 0 , c_padsz ) ;
bp = ( void * ) bp + c_padsz ;
}
* bp + + = htonl ( AFS_SET_MODE ) ;
* bp + + = 0 ; /* mtime */
* bp + + = 0 ; /* owner */
* bp + + = 0 ; /* group */
* bp + + = htonl ( S_IRWXUGO ) ; /* unix mode */
* bp + + = 0 ; /* segment size */
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}
/*
* deliver reply data to an FS . Rename
*/
static int afs_deliver_fs_rename ( struct afs_call * call ,
struct sk_buff * skb , bool last )
{
struct afs_vnode * orig_dvnode = call - > reply , * new_dvnode = call - > reply2 ;
const __be32 * bp ;
_enter ( " {%u},{%u},%d " , call - > unmarshall , skb - > len , last ) ;
afs_transfer_reply ( call , skb ) ;
if ( ! last )
return 0 ;
if ( call - > reply_size ! = call - > reply_max )
return - EBADMSG ;
/* unmarshall the reply once we've received all of it */
bp = call - > buffer ;
xdr_decode_AFSFetchStatus ( & bp , & orig_dvnode - > status , orig_dvnode ) ;
if ( new_dvnode ! = orig_dvnode )
xdr_decode_AFSFetchStatus ( & bp , & new_dvnode - > status , new_dvnode ) ;
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave ( " = 0 [done] " ) ;
return 0 ;
}
/*
* FS . Rename operation type
*/
static const struct afs_call_type afs_RXFSRename = {
. name = " FS.Rename " ,
. deliver = afs_deliver_fs_rename ,
. abort_to_error = afs_abort_to_error ,
. destructor = afs_flat_call_destructor ,
} ;
/*
* create a symbolic link
*/
int afs_fs_rename ( struct afs_server * server ,
struct key * key ,
struct afs_vnode * orig_dvnode ,
const char * orig_name ,
struct afs_vnode * new_dvnode ,
const char * new_name ,
const struct afs_wait_mode * wait_mode )
{
struct afs_call * call ;
size_t reqsz , o_namesz , o_padsz , n_namesz , n_padsz ;
__be32 * bp ;
_enter ( " " ) ;
o_namesz = strlen ( orig_name ) ;
o_padsz = ( 4 - ( o_namesz & 3 ) ) & 3 ;
n_namesz = strlen ( new_name ) ;
n_padsz = ( 4 - ( n_namesz & 3 ) ) & 3 ;
reqsz = ( 4 * 4 ) +
4 + o_namesz + o_padsz +
( 3 * 4 ) +
4 + n_namesz + n_padsz ;
call = afs_alloc_flat_call ( & afs_RXFSRename , reqsz , ( 21 + 21 + 6 ) * 4 ) ;
if ( ! call )
return - ENOMEM ;
call - > key = key ;
call - > reply = orig_dvnode ;
call - > reply2 = new_dvnode ;
call - > service_id = FS_SERVICE ;
call - > port = htons ( AFS_FS_PORT ) ;
/* marshall the parameters */
bp = call - > request ;
* bp + + = htonl ( FSRENAME ) ;
* bp + + = htonl ( orig_dvnode - > fid . vid ) ;
* bp + + = htonl ( orig_dvnode - > fid . vnode ) ;
* bp + + = htonl ( orig_dvnode - > fid . unique ) ;
* bp + + = htonl ( o_namesz ) ;
memcpy ( bp , orig_name , o_namesz ) ;
bp = ( void * ) bp + o_namesz ;
if ( o_padsz > 0 ) {
memset ( bp , 0 , o_padsz ) ;
bp = ( void * ) bp + o_padsz ;
}
* bp + + = htonl ( new_dvnode - > fid . vid ) ;
* bp + + = htonl ( new_dvnode - > fid . vnode ) ;
* bp + + = htonl ( new_dvnode - > fid . unique ) ;
* bp + + = htonl ( n_namesz ) ;
memcpy ( bp , new_name , n_namesz ) ;
bp = ( void * ) bp + n_namesz ;
if ( n_padsz > 0 ) {
memset ( bp , 0 , n_padsz ) ;
bp = ( void * ) bp + n_padsz ;
}
return afs_make_call ( & server - > addr , call , GFP_NOFS , wait_mode ) ;
}