/* AFS File Server client stubs
*
* Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
* 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>
#include <linux/circ_buf.h>
#include "internal.h"
#include "afs_fs.h"
/*
* 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;
}
/*
* decode an AFSFetchStatus block
*/
static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
struct afs_file_status *status,
struct afs_vnode *vnode)
{
const __be32 *bp = *_bp;
umode_t mode;
u64 data_version, size;
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)
status->if_version = ntohl(*bp++);
EXTRACT(status->type);
EXTRACT(status->nlink);
size = ntohl(*bp++);
data_version = ntohl(*bp++);
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);
bp++; /* seg size */
status->mtime_client = ntohl(*bp++);
status->mtime_server = ntohl(*bp++);
EXTRACT(status->group);
bp++; /* sync counter */
data_version |= (u64) ntohl(*bp++) << 32;
bp++; /* lock count */
size |= (u64) ntohl(*bp++) << 32;
bp++; /* spare 4 */
*_bp = bp;
if (size != status->size) {
status->size = size;
changed |= true;
}
status->mode &= S_IALLUGO;
_debug("vnode time %lx, %lx",
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}",
data_version, vnode->fid.vid, vnode->fid.vnode);
set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
}
}
}
/*
* decode an AFSCallBack block
*/
static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
{
const __be32 *bp = *_bp;
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;
}
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;
}
/*
* dec