2007-04-26 16:55:03 -06:00
|
|
|
/* AFS File Server client stubs
|
2005-04-16 16:20:36 -06:00
|
|
|
*
|
2007-04-26 16:55:03 -06:00
|
|
|
* Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
|
2005-04-16 16:20:36 -06: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-26 16:55:03 -06:00
|
|
|
#include <linux/circ_buf.h>
|
2005-04-16 16:20:36 -06:00
|
|
|
#include "internal.h"
|
2007-04-26 16:55:03 -06:00
|
|
|
#include "afs_fs.h"
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:59:35 -06: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-16 16:20:36 -06:00
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* decode an AFSFetchStatus block
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
|
2007-04-26 16:59:35 -06:00
|
|
|
struct afs_file_status *status,
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
struct afs_vnode *vnode,
|
|
|
|
afs_dataversion_t *store_version)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
afs_dataversion_t expected_version;
|
2007-04-26 16:55:03 -06:00
|
|
|
const __be32 *bp = *_bp;
|
|
|
|
umode_t mode;
|
2007-04-26 16:59:35 -06:00
|
|
|
u64 data_version, size;
|
2007-04-26 16:55:03 -06: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-26 16:59:35 -06:00
|
|
|
status->if_version = ntohl(*bp++);
|
|
|
|
EXTRACT(status->type);
|
|
|
|
EXTRACT(status->nlink);
|
|
|
|
size = ntohl(*bp++);
|
2007-04-26 16:55:03 -06:00
|
|
|
data_version = ntohl(*bp++);
|
2007-04-26 16:59:35 -06: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-26 16:55:03 -06:00
|
|
|
bp++; /* seg size */
|
2007-04-26 16:59:35 -06:00
|
|
|
status->mtime_client = ntohl(*bp++);
|
|
|
|
status->mtime_server = ntohl(*bp++);
|
|
|
|
EXTRACT(status->group);
|
2007-04-26 16:55:03 -06:00
|
|
|
bp++; /* sync counter */
|
|
|
|
data_version |= (u64) ntohl(*bp++) << 32;
|
2007-07-16 00:40:12 -06:00
|
|
|
EXTRACT(status->lock_count);
|
2007-04-26 16:59:35 -06:00
|
|
|
size |= (u64) ntohl(*bp++) << 32;
|
|
|
|
bp++; /* spare 4 */
|
2007-04-26 16:55:03 -06:00
|
|
|
*_bp = bp;
|
|
|
|
|
2007-04-26 16:59:35 -06:00
|
|
|
if (size != status->size) {
|
|
|
|
status->size = size;
|
|
|
|
changed |= true;
|
2007-04-26 16:55:03 -06:00
|
|
|
}
|
2007-04-26 16:59:35 -06:00
|
|
|
status->mode &= S_IALLUGO;
|
2007-04-26 16:55:03 -06:00
|
|
|
|
|
|
|
_debug("vnode time %lx, %lx",
|
2007-04-26 16:59:35 -06: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;
|
|
|
|
}
|
|
|
|
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
expected_version = status->data_version;
|
|
|
|
if (store_version)
|
|
|
|
expected_version = *store_version;
|
|
|
|
|
|
|
|
if (expected_version != data_version) {
|
2007-04-26 16:59:35 -06:00
|
|
|
status->data_version = data_version;
|
|
|
|
if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
|
|
|
|
_debug("vnode modified %llx on {%x:%u}",
|
2007-04-26 17:06:22 -06:00
|
|
|
(unsigned long long) data_version,
|
|
|
|
vnode->fid.vid, vnode->fid.vnode);
|
2007-04-26 16:59:35 -06:00
|
|
|
set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
|
|
|
|
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
|
|
|
|
}
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
} else if (store_version) {
|
|
|
|
status->data_version = data_version;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* decode an AFSCallBack block
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:55:03 -06:00
|
|
|
const __be32 *bp = *_bp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06: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-26 16:49:28 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:59:35 -06: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-16 16:20:36 -06:00
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* decode an AFSVolSync block
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
static void xdr_decode_AFSVolSync(const __be32 **_bp,
|
|
|
|
struct afs_volsync *volsync)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:55:03 -06:00
|
|
|
const __be32 *bp = *_bp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
volsync->creation = ntohl(*bp++);
|
|
|
|
bp++; /* spare2 */
|
|
|
|
bp++; /* spare3 */
|
|
|
|
bp++; /* spare4 */
|
|
|
|
bp++; /* spare5 */
|
|
|
|
bp++; /* spare6 */
|
|
|
|
*_bp = bp;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
/*
|
|
|
|
* encode the requested attributes into an AFSStoreStatus block
|
|
|
|
*/
|
|
|
|
static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
|
|
|
|
{
|
|
|
|
__be32 *bp = *_bp;
|
|
|
|
u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
|
|
|
|
|
|
|
|
mask = 0;
|
|
|
|
if (attr->ia_valid & ATTR_MTIME) {
|
|
|
|
mask |= AFS_SET_MTIME;
|
|
|
|
mtime = attr->ia_mtime.tv_sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr->ia_valid & ATTR_UID) {
|
|
|
|
mask |= AFS_SET_OWNER;
|
|
|
|
owner = attr->ia_uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr->ia_valid & ATTR_GID) {
|
|
|
|
mask |= AFS_SET_GROUP;
|
|
|
|
group = attr->ia_gid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr->ia_valid & ATTR_MODE) {
|
|
|
|
mask |= AFS_SET_MODE;
|
|
|
|
mode = attr->ia_mode & S_IALLUGO;
|
|
|
|
}
|
|
|
|
|
|
|
|
*bp++ = htonl(mask);
|
|
|
|
*bp++ = htonl(mtime);
|
|
|
|
*bp++ = htonl(owner);
|
|
|
|
*bp++ = htonl(group);
|
|
|
|
*bp++ = htonl(mode);
|
|
|
|
*bp++ = 0; /* segment size */
|
|
|
|
*_bp = bp;
|
|
|
|
}
|
|
|
|
|
2007-05-10 23:22:20 -06:00
|
|
|
/*
|
|
|
|
* decode an AFSFetchVolumeStatus block
|
|
|
|
*/
|
|
|
|
static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
|
|
|
|
struct afs_volume_status *vs)
|
|
|
|
{
|
|
|
|
const __be32 *bp = *_bp;
|
|
|
|
|
|
|
|
vs->vid = ntohl(*bp++);
|
|
|
|
vs->parent_id = ntohl(*bp++);
|
|
|
|
vs->online = ntohl(*bp++);
|
|
|
|
vs->in_service = ntohl(*bp++);
|
|
|
|
vs->blessed = ntohl(*bp++);
|
|
|
|
vs->needs_salvage = ntohl(*bp++);
|
|
|
|
vs->type = ntohl(*bp++);
|
|
|
|
vs->min_quota = ntohl(*bp++);
|
|
|
|
vs->max_quota = ntohl(*bp++);
|
|
|
|
vs->blocks_in_use = ntohl(*bp++);
|
|
|
|
vs->part_blocks_avail = ntohl(*bp++);
|
|
|
|
vs->part_max_blocks = ntohl(*bp++);
|
|
|
|
*_bp = bp;
|
|
|
|
}
|
|
|
|
|
2007-04-26 16:55:03 -06: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-26 16:59:35 -06:00
|
|
|
struct afs_vnode *vnode = call->reply;
|
2007-04-26 16:55:03 -06:00
|
|
|
const __be32 *bp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_enter(",,%u", last);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
afs_transfer_reply(call, skb);
|
|
|
|
if (!last)
|
|
|
|
return 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
if (call->reply_size != call->reply_max)
|
|
|
|
return -EBADMSG;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
/* unmarshall the reply once we've received all of it */
|
|
|
|
bp = call->buffer;
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
xdr_decode_AFSCallBack(&bp, vnode);
|
2007-04-26 16:55:03 -06:00
|
|
|
if (call->reply2)
|
|
|
|
xdr_decode_AFSVolSync(&bp, call->reply2);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2007-04-26 16:55:03 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.FetchStatus operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSFetchStatus = {
|
2007-04-26 16:57:07 -06:00
|
|
|
.name = "FS.FetchStatus",
|
2007-04-26 16:55:03 -06:00
|
|
|
.deliver = afs_deliver_fs_fetch_status,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* fetch the status information for a file
|
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
int afs_fs_fetch_file_status(struct afs_server *server,
|
2007-04-26 16:57:07 -06:00
|
|
|
struct key *key,
|
2007-04-26 16:55:03 -06:00
|
|
|
struct afs_vnode *vnode,
|
|
|
|
struct afs_volsync *volsync,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:55:03 -06:00
|
|
|
struct afs_call *call;
|
2005-04-16 16:20:36 -06:00
|
|
|
__be32 *bp;
|
|
|
|
|
2007-05-09 03:33:45 -06:00
|
|
|
_enter(",%x,{%x:%u},,",
|
2007-04-26 16:59:35 -06:00
|
|
|
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:59:35 -06:00
|
|
|
call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
|
2007-04-26 16:55:03 -06:00
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:57:07 -06:00
|
|
|
call->key = key;
|
2007-04-26 16:55:03 -06:00
|
|
|
call->reply = vnode;
|
|
|
|
call->reply2 = volsync;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* marshall the parameters */
|
2007-04-26 16:55:03 -06:00
|
|
|
bp = call->request;
|
2005-04-16 16:20:36 -06: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-26 16:55:03 -06:00
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* deliver reply data to an FS.FetchData
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
static int afs_deliver_fs_fetch_data(struct afs_call *call,
|
|
|
|
struct sk_buff *skb, bool last)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:59:35 -06:00
|
|
|
struct afs_vnode *vnode = call->reply;
|
2007-04-26 16:55:03 -06:00
|
|
|
const __be32 *bp;
|
|
|
|
struct page *page;
|
|
|
|
void *buffer;
|
2005-04-16 16:20:36 -06:00
|
|
|
int ret;
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
|
|
|
|
|
|
|
switch (call->unmarshall) {
|
|
|
|
case 0:
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
2007-05-10 04:15:21 -06:00
|
|
|
if (call->operation_ID != FSFETCHDATA64) {
|
|
|
|
call->unmarshall++;
|
|
|
|
goto no_msw;
|
|
|
|
}
|
2007-04-26 16:55:03 -06:00
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
/* extract the upper part of the returned data length of an
|
|
|
|
* FSFETCHDATA64 op (which should always be 0 using this
|
|
|
|
* client) */
|
2007-04-26 16:55:03 -06:00
|
|
|
case 1:
|
2007-05-10 04:15:21 -06:00
|
|
|
_debug("extract data length (MSW)");
|
|
|
|
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->count = ntohl(call->tmp);
|
|
|
|
_debug("DATA length MSW: %u", call->count);
|
|
|
|
if (call->count > 0)
|
|
|
|
return -EBADMSG;
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
no_msw:
|
|
|
|
/* extract the returned data length */
|
|
|
|
case 2:
|
2007-04-26 16:55:03 -06:00
|
|
|
_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-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
call->count = ntohl(call->tmp);
|
|
|
|
_debug("DATA length: %u", call->count);
|
|
|
|
if (call->count > PAGE_SIZE)
|
|
|
|
return -EBADMSG;
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the returned data */
|
2007-05-10 04:15:21 -06:00
|
|
|
case 3:
|
2007-04-26 16:55:03 -06:00
|
|
|
_debug("extract data");
|
2007-05-09 03:33:45 -06:00
|
|
|
if (call->count > 0) {
|
|
|
|
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;
|
|
|
|
}
|
2007-04-26 16:55:03 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
/* extract the metadata */
|
2007-05-10 04:15:21 -06:00
|
|
|
case 4:
|
2007-04-26 16:59:35 -06:00
|
|
|
ret = afs_extract_data(call, skb, last, call->buffer,
|
|
|
|
(21 + 3 + 6) * 4);
|
2007-04-26 16:55:03 -06:00
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bp = call->buffer;
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
xdr_decode_AFSCallBack(&bp, vnode);
|
2007-04-26 16:55:03 -06:00
|
|
|
if (call->reply2)
|
|
|
|
xdr_decode_AFSVolSync(&bp, call->reply2);
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
case 5:
|
2007-04-26 16:55:03 -06:00
|
|
|
_debug("trailer");
|
|
|
|
if (skb->len != 0)
|
|
|
|
return -EBADMSG;
|
|
|
|
break;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
if (!last)
|
|
|
|
return 0;
|
|
|
|
|
2007-05-09 03:33:45 -06:00
|
|
|
if (call->count < PAGE_SIZE) {
|
|
|
|
_debug("clear");
|
|
|
|
page = call->reply3;
|
|
|
|
buffer = kmap_atomic(page, KM_USER0);
|
|
|
|
memset(buffer + call->count, 0, PAGE_SIZE - call->count);
|
|
|
|
kunmap_atomic(buffer, KM_USER0);
|
|
|
|
}
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* FS.FetchData operation type
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
static const struct afs_call_type afs_RXFSFetchData = {
|
2007-04-26 16:57:07 -06:00
|
|
|
.name = "FS.FetchData",
|
2007-04-26 16:55:03 -06:00
|
|
|
.deliver = afs_deliver_fs_fetch_data,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
static const struct afs_call_type afs_RXFSFetchData64 = {
|
|
|
|
.name = "FS.FetchData64",
|
|
|
|
.deliver = afs_deliver_fs_fetch_data,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fetch data from a very large file
|
|
|
|
*/
|
|
|
|
static int afs_fs_fetch_data64(struct afs_server *server,
|
|
|
|
struct key *key,
|
|
|
|
struct afs_vnode *vnode,
|
|
|
|
off_t offset, size_t length,
|
|
|
|
struct page *buffer,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
ASSERTCMP(length, <, ULONG_MAX);
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->key = key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->reply2 = NULL; /* volsync */
|
|
|
|
call->reply3 = buffer;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->operation_ID = FSFETCHDATA64;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
bp[0] = htonl(FSFETCHDATA64);
|
|
|
|
bp[1] = htonl(vnode->fid.vid);
|
|
|
|
bp[2] = htonl(vnode->fid.vnode);
|
|
|
|
bp[3] = htonl(vnode->fid.unique);
|
|
|
|
bp[4] = htonl(upper_32_bits(offset));
|
|
|
|
bp[5] = htonl((u32) offset);
|
|
|
|
bp[6] = 0;
|
|
|
|
bp[7] = htonl((u32) length);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
/*
|
|
|
|
* fetch data from a file
|
|
|
|
*/
|
|
|
|
int afs_fs_fetch_data(struct afs_server *server,
|
2007-04-26 16:57:07 -06:00
|
|
|
struct key *key,
|
2007-04-26 16:55:03 -06:00
|
|
|
struct afs_vnode *vnode,
|
|
|
|
off_t offset, size_t length,
|
|
|
|
struct page *buffer,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:55:03 -06:00
|
|
|
struct afs_call *call;
|
2005-04-16 16:20:36 -06:00
|
|
|
__be32 *bp;
|
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
if (upper_32_bits(offset) || upper_32_bits(offset + length))
|
|
|
|
return afs_fs_fetch_data64(server, key, vnode, offset, length,
|
|
|
|
buffer, wait_mode);
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_enter("");
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:59:35 -06:00
|
|
|
call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
|
2007-04-26 16:55:03 -06:00
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:57:07 -06:00
|
|
|
call->key = key;
|
2007-04-26 16:55:03 -06:00
|
|
|
call->reply = vnode;
|
2007-04-26 16:59:35 -06:00
|
|
|
call->reply2 = NULL; /* volsync */
|
2007-04-26 16:55:03 -06:00
|
|
|
call->reply3 = buffer;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
2007-05-10 04:15:21 -06:00
|
|
|
call->operation_ID = FSFETCHDATA;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* marshall the parameters */
|
2007-04-26 16:55:03 -06: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-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06: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-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
if (skb->len > 0)
|
|
|
|
return -EBADMSG; /* shouldn't be any reply data */
|
|
|
|
return 0;
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
2007-04-26 16:55:03 -06:00
|
|
|
* FS.GiveUpCallBacks operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
|
2007-04-26 16:57:07 -06:00
|
|
|
.name = "FS.GiveUpCallBacks",
|
2007-04-26 16:55:03 -06: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-16 16:20:36 -06:00
|
|
|
*/
|
2007-04-26 16:55:03 -06:00
|
|
|
int afs_fs_give_up_callbacks(struct afs_server *server,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-26 16:55:03 -06:00
|
|
|
struct afs_call *call;
|
|
|
|
size_t ncallbacks;
|
|
|
|
__be32 *bp, *tp;
|
|
|
|
int loop;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
|
|
|
|
ARRAY_SIZE(server->cb_break));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_enter("{%zu},", ncallbacks);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
if (ncallbacks == 0)
|
|
|
|
return 0;
|
|
|
|
if (ncallbacks > AFSCBMAX)
|
|
|
|
ncallbacks = AFSCBMAX;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
_debug("break %zu callbacks", ncallbacks);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06: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-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* marshall the parameters */
|
2007-04-26 16:55:03 -06: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-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
ASSERT(ncallbacks > 0);
|
|
|
|
wake_up_nr(&server->cb_break_waitq, ncallbacks);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-26 16:55:03 -06:00
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
2007-04-26 16:49:28 -06:00
|
|
|
}
|
2007-04-26 16:59:35 -06: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);
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
|
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
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;
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
/* 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;
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
|
|
|
xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
/* 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);
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
|
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
/* 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;
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
if (new_dvnode != orig_dvnode)
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
|
|
|
|
NULL);
|
2007-04-26 16:59:35 -06:00
|
|
|
/* 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);
|
|
|
|
}
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* deliver reply data to an FS.StoreData
|
|
|
|
*/
|
|
|
|
static int afs_deliver_fs_store_data(struct afs_call *call,
|
|
|
|
struct sk_buff *skb, bool last)
|
|
|
|
{
|
|
|
|
struct afs_vnode *vnode = call->reply;
|
|
|
|
const __be32 *bp;
|
|
|
|
|
|
|
|
_enter(",,%u", last);
|
|
|
|
|
|
|
|
afs_transfer_reply(call, skb);
|
|
|
|
if (!last) {
|
|
|
|
_leave(" = 0 [more]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call->reply_size != call->reply_max) {
|
|
|
|
_leave(" = -EBADMSG [%u != %u]",
|
|
|
|
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,
|
|
|
|
&call->store_version);
|
|
|
|
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
|
|
|
|
|
|
|
|
afs_pages_written_back(vnode, call);
|
|
|
|
|
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.StoreData operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSStoreData = {
|
|
|
|
.name = "FS.StoreData",
|
|
|
|
.deliver = afs_deliver_fs_store_data,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
static const struct afs_call_type afs_RXFSStoreData64 = {
|
|
|
|
.name = "FS.StoreData64",
|
|
|
|
.deliver = afs_deliver_fs_store_data,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* store a set of pages to a very large file
|
|
|
|
*/
|
|
|
|
static int afs_fs_store_data64(struct afs_server *server,
|
|
|
|
struct afs_writeback *wb,
|
|
|
|
pgoff_t first, pgoff_t last,
|
|
|
|
unsigned offset, unsigned to,
|
|
|
|
loff_t size, loff_t pos, loff_t i_size,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_vnode *vnode = wb->vnode;
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter(",%x,{%x:%u},,",
|
|
|
|
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSStoreData64,
|
|
|
|
(4 + 6 + 3 * 2) * 4,
|
|
|
|
(21 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->wb = wb;
|
|
|
|
call->key = wb->key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->mapping = vnode->vfs_inode.i_mapping;
|
|
|
|
call->first = first;
|
|
|
|
call->last = last;
|
|
|
|
call->first_offset = offset;
|
|
|
|
call->last_to = to;
|
|
|
|
call->send_pages = true;
|
|
|
|
call->store_version = vnode->status.data_version + 1;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
*bp++ = htonl(FSSTOREDATA64);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
|
|
|
|
*bp++ = 0; /* mask */
|
|
|
|
*bp++ = 0; /* mtime */
|
|
|
|
*bp++ = 0; /* owner */
|
|
|
|
*bp++ = 0; /* group */
|
|
|
|
*bp++ = 0; /* unix mode */
|
|
|
|
*bp++ = 0; /* segment size */
|
|
|
|
|
|
|
|
*bp++ = htonl(pos >> 32);
|
|
|
|
*bp++ = htonl((u32) pos);
|
|
|
|
*bp++ = htonl(size >> 32);
|
|
|
|
*bp++ = htonl((u32) size);
|
|
|
|
*bp++ = htonl(i_size >> 32);
|
|
|
|
*bp++ = htonl((u32) i_size);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
/*
|
|
|
|
* store a set of pages
|
|
|
|
*/
|
|
|
|
int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
|
|
|
|
pgoff_t first, pgoff_t last,
|
|
|
|
unsigned offset, unsigned to,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_vnode *vnode = wb->vnode;
|
|
|
|
struct afs_call *call;
|
|
|
|
loff_t size, pos, i_size;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter(",%x,{%x:%u},,",
|
|
|
|
key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
|
|
|
|
|
|
|
|
size = to - offset;
|
|
|
|
if (first != last)
|
|
|
|
size += (loff_t)(last - first) << PAGE_SHIFT;
|
|
|
|
pos = (loff_t)first << PAGE_SHIFT;
|
|
|
|
pos += offset;
|
|
|
|
|
|
|
|
i_size = i_size_read(&vnode->vfs_inode);
|
|
|
|
if (pos + size > i_size)
|
|
|
|
i_size = size + pos;
|
|
|
|
|
|
|
|
_debug("size %llx, at %llx, i_size %llx",
|
|
|
|
(unsigned long long) size, (unsigned long long) pos,
|
|
|
|
(unsigned long long) i_size);
|
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
|
|
|
|
return afs_fs_store_data64(server, wb, first, last, offset, to,
|
|
|
|
size, pos, i_size, wait_mode);
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSStoreData,
|
|
|
|
(4 + 6 + 3) * 4,
|
|
|
|
(21 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->wb = wb;
|
|
|
|
call->key = wb->key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->mapping = vnode->vfs_inode.i_mapping;
|
|
|
|
call->first = first;
|
|
|
|
call->last = last;
|
|
|
|
call->first_offset = offset;
|
|
|
|
call->last_to = to;
|
|
|
|
call->send_pages = true;
|
|
|
|
call->store_version = vnode->status.data_version + 1;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
*bp++ = htonl(FSSTOREDATA);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
|
|
|
|
*bp++ = 0; /* mask */
|
|
|
|
*bp++ = 0; /* mtime */
|
|
|
|
*bp++ = 0; /* owner */
|
|
|
|
*bp++ = 0; /* group */
|
|
|
|
*bp++ = 0; /* unix mode */
|
|
|
|
*bp++ = 0; /* segment size */
|
|
|
|
|
|
|
|
*bp++ = htonl(pos);
|
|
|
|
*bp++ = htonl(size);
|
|
|
|
*bp++ = htonl(i_size);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* deliver reply data to an FS.StoreStatus
|
|
|
|
*/
|
|
|
|
static int afs_deliver_fs_store_status(struct afs_call *call,
|
|
|
|
struct sk_buff *skb, bool last)
|
|
|
|
{
|
|
|
|
afs_dataversion_t *store_version;
|
|
|
|
struct afs_vnode *vnode = call->reply;
|
|
|
|
const __be32 *bp;
|
|
|
|
|
|
|
|
_enter(",,%u", last);
|
|
|
|
|
|
|
|
afs_transfer_reply(call, skb);
|
|
|
|
if (!last) {
|
|
|
|
_leave(" = 0 [more]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (call->reply_size != call->reply_max) {
|
|
|
|
_leave(" = -EBADMSG [%u != %u]",
|
|
|
|
call->reply_size, call->reply_max);
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unmarshall the reply once we've received all of it */
|
|
|
|
store_version = NULL;
|
|
|
|
if (call->operation_ID == FSSTOREDATA)
|
|
|
|
store_version = &call->store_version;
|
|
|
|
|
|
|
|
bp = call->buffer;
|
|
|
|
xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
|
|
|
|
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
|
|
|
|
|
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.StoreStatus operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSStoreStatus = {
|
|
|
|
.name = "FS.StoreStatus",
|
|
|
|
.deliver = afs_deliver_fs_store_status,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct afs_call_type afs_RXFSStoreData_as_Status = {
|
|
|
|
.name = "FS.StoreData",
|
|
|
|
.deliver = afs_deliver_fs_store_status,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
2007-05-10 04:15:21 -06:00
|
|
|
static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
|
|
|
|
.name = "FS.StoreData64",
|
|
|
|
.deliver = afs_deliver_fs_store_status,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set the attributes on a very large file, using FS.StoreData rather than
|
|
|
|
* FS.StoreStatus so as to alter the file size also
|
|
|
|
*/
|
|
|
|
static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
|
|
|
|
struct afs_vnode *vnode, struct iattr *attr,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter(",%x,{%x:%u},,",
|
|
|
|
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
|
|
|
|
|
|
|
|
ASSERT(attr->ia_valid & ATTR_SIZE);
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
|
|
|
|
(4 + 6 + 3 * 2) * 4,
|
|
|
|
(21 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->key = key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->store_version = vnode->status.data_version + 1;
|
|
|
|
call->operation_ID = FSSTOREDATA;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
*bp++ = htonl(FSSTOREDATA64);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
|
|
|
|
xdr_encode_AFS_StoreStatus(&bp, attr);
|
|
|
|
|
|
|
|
*bp++ = 0; /* position of start of write */
|
|
|
|
*bp++ = 0;
|
|
|
|
*bp++ = 0; /* size of write */
|
|
|
|
*bp++ = 0;
|
|
|
|
*bp++ = htonl(attr->ia_size >> 32); /* new file length */
|
|
|
|
*bp++ = htonl((u32) attr->ia_size);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
/*
|
|
|
|
* set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
|
|
|
|
* so as to alter the file size also
|
|
|
|
*/
|
|
|
|
static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
|
|
|
|
struct afs_vnode *vnode, struct iattr *attr,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter(",%x,{%x:%u},,",
|
|
|
|
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
|
|
|
|
|
|
|
|
ASSERT(attr->ia_valid & ATTR_SIZE);
|
2007-05-10 04:15:21 -06:00
|
|
|
if (attr->ia_size >> 32)
|
|
|
|
return afs_fs_setattr_size64(server, key, vnode, attr,
|
|
|
|
wait_mode);
|
AFS: implement basic file write support
Implement support for writing to regular AFS files, including:
(1) write
(2) truncate
(3) fsync, fdatasync
(4) chmod, chown, chgrp, utime.
AFS writeback attempts to batch writes into as chunks as large as it can manage
up to the point that it writes back 65535 pages in one chunk or it meets a
locked page.
Furthermore, if a page has been written to using a particular key, then should
another write to that page use some other key, the first write will be flushed
before the second is allowed to take place. If the first write fails due to a
security error, then the page will be scrapped and reread before the second
write takes place.
If a page is dirty and the callback on it is broken by the server, then the
dirty data is not discarded (same behaviour as NFS).
Shared-writable mappings are not supported by this patch.
[akpm@linux-foundation.org: fix a bunch of warnings]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-09 03:33:46 -06:00
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
|
|
|
|
(4 + 6 + 3) * 4,
|
|
|
|
(21 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->key = key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->store_version = vnode->status.data_version + 1;
|
|
|
|
call->operation_ID = FSSTOREDATA;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
*bp++ = htonl(FSSTOREDATA);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
|
|
|
|
xdr_encode_AFS_StoreStatus(&bp, attr);
|
|
|
|
|
|
|
|
*bp++ = 0; /* position of start of write */
|
|
|
|
*bp++ = 0; /* size of write */
|
|
|
|
*bp++ = htonl(attr->ia_size); /* new file length */
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set the attributes on a file, using FS.StoreData if there's a change in file
|
|
|
|
* size, and FS.StoreStatus otherwise
|
|
|
|
*/
|
|
|
|
int afs_fs_setattr(struct afs_server *server, struct key *key,
|
|
|
|
struct afs_vnode *vnode, struct iattr *attr,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
if (attr->ia_valid & ATTR_SIZE)
|
|
|
|
return afs_fs_setattr_size(server, key, vnode, attr,
|
|
|
|
wait_mode);
|
|
|
|
|
|
|
|
_enter(",%x,{%x:%u},,",
|
|
|
|
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
|
|
|
|
(4 + 6) * 4,
|
|
|
|
(21 + 6) * 4);
|
|
|
|
if (!call)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call->key = key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
call->operation_ID = FSSTORESTATUS;
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
*bp++ = htonl(FSSTORESTATUS);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
|
|
|
|
xdr_encode_AFS_StoreStatus(&bp, attr);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
2007-05-10 23:22:20 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* deliver reply data to an FS.GetVolumeStatus
|
|
|
|
*/
|
|
|
|
static int afs_deliver_fs_get_volume_status(struct afs_call *call,
|
|
|
|
struct sk_buff *skb, bool last)
|
|
|
|
{
|
|
|
|
const __be32 *bp;
|
|
|
|
char *p;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
|
|
|
|
|
|
|
|
switch (call->unmarshall) {
|
|
|
|
case 0:
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the returned status record */
|
|
|
|
case 1:
|
|
|
|
_debug("extract status");
|
|
|
|
ret = afs_extract_data(call, skb, last, call->buffer,
|
|
|
|
12 * 4);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bp = call->buffer;
|
|
|
|
xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the volume name length */
|
|
|
|
case 2:
|
|
|
|
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->count = ntohl(call->tmp);
|
|
|
|
_debug("volname length: %u", call->count);
|
|
|
|
if (call->count >= AFSNAMEMAX)
|
|
|
|
return -EBADMSG;
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the volume name */
|
|
|
|
case 3:
|
|
|
|
_debug("extract volname");
|
|
|
|
if (call->count > 0) {
|
|
|
|
ret = afs_extract_data(call, skb, last, call->reply3,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = call->reply3;
|
|
|
|
p[call->count] = 0;
|
|
|
|
_debug("volname '%s'", p);
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the volume name padding */
|
|
|
|
if ((call->count & 3) == 0) {
|
|
|
|
call->unmarshall++;
|
|
|
|
goto no_volname_padding;
|
|
|
|
}
|
|
|
|
call->count = 4 - (call->count & 3);
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
ret = afs_extract_data(call, skb, last, call->buffer,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
no_volname_padding:
|
|
|
|
|
|
|
|
/* extract the offline message length */
|
|
|
|
case 5:
|
|
|
|
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->count = ntohl(call->tmp);
|
|
|
|
_debug("offline msg length: %u", call->count);
|
|
|
|
if (call->count >= AFSNAMEMAX)
|
|
|
|
return -EBADMSG;
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the offline message */
|
|
|
|
case 6:
|
|
|
|
_debug("extract offline");
|
|
|
|
if (call->count > 0) {
|
|
|
|
ret = afs_extract_data(call, skb, last, call->reply3,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = call->reply3;
|
|
|
|
p[call->count] = 0;
|
|
|
|
_debug("offline '%s'", p);
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the offline message padding */
|
|
|
|
if ((call->count & 3) == 0) {
|
|
|
|
call->unmarshall++;
|
|
|
|
goto no_offline_padding;
|
|
|
|
}
|
|
|
|
call->count = 4 - (call->count & 3);
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
ret = afs_extract_data(call, skb, last, call->buffer,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
no_offline_padding:
|
|
|
|
|
|
|
|
/* extract the message of the day length */
|
|
|
|
case 8:
|
|
|
|
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->count = ntohl(call->tmp);
|
|
|
|
_debug("motd length: %u", call->count);
|
|
|
|
if (call->count >= AFSNAMEMAX)
|
|
|
|
return -EBADMSG;
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the message of the day */
|
|
|
|
case 9:
|
|
|
|
_debug("extract motd");
|
|
|
|
if (call->count > 0) {
|
|
|
|
ret = afs_extract_data(call, skb, last, call->reply3,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = call->reply3;
|
|
|
|
p[call->count] = 0;
|
|
|
|
_debug("motd '%s'", p);
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
|
|
|
|
/* extract the message of the day padding */
|
|
|
|
if ((call->count & 3) == 0) {
|
|
|
|
call->unmarshall++;
|
|
|
|
goto no_motd_padding;
|
|
|
|
}
|
|
|
|
call->count = 4 - (call->count & 3);
|
|
|
|
|
|
|
|
case 10:
|
|
|
|
ret = afs_extract_data(call, skb, last, call->buffer,
|
|
|
|
call->count);
|
|
|
|
switch (ret) {
|
|
|
|
case 0: break;
|
|
|
|
case -EAGAIN: return 0;
|
|
|
|
default: return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->offset = 0;
|
|
|
|
call->unmarshall++;
|
|
|
|
no_motd_padding:
|
|
|
|
|
|
|
|
case 11:
|
|
|
|
_debug("trailer %d", skb->len);
|
|
|
|
if (skb->len != 0)
|
|
|
|
return -EBADMSG;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!last)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* destroy an FS.GetVolumeStatus call
|
|
|
|
*/
|
|
|
|
static void afs_get_volume_status_call_destructor(struct afs_call *call)
|
|
|
|
{
|
|
|
|
kfree(call->reply3);
|
|
|
|
call->reply3 = NULL;
|
|
|
|
afs_flat_call_destructor(call);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.GetVolumeStatus operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSGetVolumeStatus = {
|
|
|
|
.name = "FS.GetVolumeStatus",
|
|
|
|
.deliver = afs_deliver_fs_get_volume_status,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_get_volume_status_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* fetch the status of a volume
|
|
|
|
*/
|
|
|
|
int afs_fs_get_volume_status(struct afs_server *server,
|
|
|
|
struct key *key,
|
|
|
|
struct afs_vnode *vnode,
|
|
|
|
struct afs_volume_status *vs,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
void *tmpbuf;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
|
|
|
|
if (!tmpbuf)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
|
|
|
|
if (!call) {
|
|
|
|
kfree(tmpbuf);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
call->key = key;
|
|
|
|
call->reply = vnode;
|
|
|
|
call->reply2 = vs;
|
|
|
|
call->reply3 = tmpbuf;
|
|
|
|
call->service_id = FS_SERVICE;
|
|
|
|
call->port = htons(AFS_FS_PORT);
|
|
|
|
|
|
|
|
/* marshall the parameters */
|
|
|
|
bp = call->request;
|
|
|
|
bp[0] = htonl(FSGETVOLUMESTATUS);
|
|
|
|
bp[1] = htonl(vnode->fid.vid);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
2007-07-16 00:40:12 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
|
|
|
|
*/
|
|
|
|
static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
|
|
|
|
struct sk_buff *skb, bool last)
|
|
|
|
{
|
|
|
|
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_AFSVolSync(&bp, call->replyX); */
|
|
|
|
|
|
|
|
_leave(" = 0 [done]");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.SetLock operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSSetLock = {
|
|
|
|
.name = "FS.SetLock",
|
|
|
|
.deliver = afs_deliver_fs_xxxx_lock,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.ExtendLock operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSExtendLock = {
|
|
|
|
.name = "FS.ExtendLock",
|
|
|
|
.deliver = afs_deliver_fs_xxxx_lock,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FS.ReleaseLock operation type
|
|
|
|
*/
|
|
|
|
static const struct afs_call_type afs_RXFSReleaseLock = {
|
|
|
|
.name = "FS.ReleaseLock",
|
|
|
|
.deliver = afs_deliver_fs_xxxx_lock,
|
|
|
|
.abort_to_error = afs_abort_to_error,
|
|
|
|
.destructor = afs_flat_call_destructor,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get a lock on a file
|
|
|
|
*/
|
|
|
|
int afs_fs_set_lock(struct afs_server *server,
|
|
|
|
struct key *key,
|
|
|
|
struct afs_vnode *vnode,
|
|
|
|
afs_lock_type_t type,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 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(FSSETLOCK);
|
|
|
|
*bp++ = htonl(vnode->fid.vid);
|
|
|
|
*bp++ = htonl(vnode->fid.vnode);
|
|
|
|
*bp++ = htonl(vnode->fid.unique);
|
|
|
|
*bp++ = htonl(type);
|
|
|
|
|
|
|
|
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* extend a lock on a file
|
|
|
|
*/
|
|
|
|
int afs_fs_extend_lock(struct afs_server *server,
|
|
|
|
struct key *key,
|
|
|
|
struct afs_vnode *vnode,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 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(FSEXTENDLOCK);
|
|
|
|
*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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* release a lock on a file
|
|
|
|
*/
|
|
|
|
int afs_fs_release_lock(struct afs_server *server,
|
|
|
|
struct key *key,
|
|
|
|
struct afs_vnode *vnode,
|
|
|
|
const struct afs_wait_mode *wait_mode)
|
|
|
|
{
|
|
|
|
struct afs_call *call;
|
|
|
|
__be32 *bp;
|
|
|
|
|
|
|
|
_enter("");
|
|
|
|
|
|
|
|
call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 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(FSRELEASELOCK);
|
|
|
|
*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);
|
|
|
|
}
|