58217f5900
WOO HOO!
233 lines
6.2 KiB
C
233 lines
6.2 KiB
C
/*
|
|
* linux/fs/nfs/inode.c
|
|
*
|
|
* Copyright (C) 1992 Rick Sladkey
|
|
*
|
|
* nfs inode and superblock handling functions
|
|
*/
|
|
|
|
#include <asm/system.h>
|
|
#include <asm/segment.h>
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/nfs_fs.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/string.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/locks.h>
|
|
|
|
extern int close_fp(struct file *filp, unsigned int fd);
|
|
|
|
static int nfs_notify_change(int, struct inode *);
|
|
static void nfs_put_inode(struct inode *);
|
|
static void nfs_put_super(struct super_block *);
|
|
static void nfs_statfs(struct super_block *, struct statfs *);
|
|
|
|
static struct super_operations nfs_sops = {
|
|
NULL, /* read inode */
|
|
nfs_notify_change, /* notify change */
|
|
NULL, /* write inode */
|
|
nfs_put_inode, /* put inode */
|
|
nfs_put_super, /* put superblock */
|
|
NULL, /* write superblock */
|
|
nfs_statfs, /* stat filesystem */
|
|
NULL
|
|
};
|
|
|
|
static void nfs_put_inode(struct inode * inode)
|
|
{
|
|
clear_inode(inode);
|
|
}
|
|
|
|
void nfs_put_super(struct super_block *sb)
|
|
{
|
|
/* No locks should be open on this, so 0 should be safe as a fd. */
|
|
close_fp(sb->u.nfs_sb.s_server.file, 0);
|
|
lock_super(sb);
|
|
sb->s_dev = 0;
|
|
unlock_super(sb);
|
|
}
|
|
|
|
/*
|
|
* The way this works is that the mount process passes a structure
|
|
* in the data argument which contains an open socket to the NFS
|
|
* server and the root file handle obtained from the server's mount
|
|
* daemon. We stash theses away in the private superblock fields.
|
|
* Later we can add other mount parameters like caching values.
|
|
*/
|
|
|
|
struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
|
|
int silent)
|
|
{
|
|
struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data;
|
|
struct nfs_server *server;
|
|
unsigned int fd;
|
|
struct file *filp;
|
|
dev_t dev = sb->s_dev;
|
|
|
|
if (!data) {
|
|
printk("nfs_read_super: missing data argument\n");
|
|
sb->s_dev = 0;
|
|
return NULL;
|
|
}
|
|
fd = data->fd;
|
|
if (data->version != NFS_MOUNT_VERSION) {
|
|
printk("nfs warning: mount version %s than kernel\n",
|
|
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
|
|
}
|
|
if (fd >= NR_OPEN || !(filp = current->filp[fd])) {
|
|
printk("nfs_read_super: invalid file descriptor\n");
|
|
sb->s_dev = 0;
|
|
return NULL;
|
|
}
|
|
if (!S_ISSOCK(filp->f_inode->i_mode)) {
|
|
printk("nfs_read_super: not a socket\n");
|
|
sb->s_dev = 0;
|
|
return NULL;
|
|
}
|
|
filp->f_count++;
|
|
lock_super(sb);
|
|
sb->s_blocksize = 1024; /* XXX */
|
|
sb->s_blocksize_bits = 10;
|
|
sb->s_magic = NFS_SUPER_MAGIC;
|
|
sb->s_dev = dev;
|
|
sb->s_op = &nfs_sops;
|
|
server = &sb->u.nfs_sb.s_server;
|
|
server->file = filp;
|
|
server->lock = 0;
|
|
server->wait = NULL;
|
|
server->flags = data->flags;
|
|
server->rsize = data->rsize;
|
|
if (server->rsize <= 0)
|
|
server->rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
|
|
else if (server->rsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
|
|
server->rsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
|
|
server->wsize = data->wsize;
|
|
if (server->wsize <= 0)
|
|
server->wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
|
|
else if (server->wsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
|
|
server->wsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
|
|
server->timeo = data->timeo*HZ/10;
|
|
server->retrans = data->retrans;
|
|
server->acregmin = data->acregmin*HZ;
|
|
server->acregmax = data->acregmax*HZ;
|
|
server->acdirmin = data->acdirmin*HZ;
|
|
server->acdirmax = data->acdirmax*HZ;
|
|
strcpy(server->hostname, data->hostname);
|
|
sb->u.nfs_sb.s_root = data->root;
|
|
unlock_super(sb);
|
|
if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) {
|
|
sb->s_dev = 0;
|
|
printk("nfs_read_super: get root inode failed\n");
|
|
return NULL;
|
|
}
|
|
return sb;
|
|
}
|
|
|
|
void nfs_statfs(struct super_block *sb, struct statfs *buf)
|
|
{
|
|
int error;
|
|
struct nfs_fsinfo res;
|
|
|
|
put_fs_long(NFS_SUPER_MAGIC, &buf->f_type);
|
|
error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
|
|
&res);
|
|
if (error) {
|
|
printk("nfs_statfs: statfs error = %d\n", -error);
|
|
res.bsize = res.blocks = res.bfree = res.bavail = 0;
|
|
}
|
|
put_fs_long(res.bsize, &buf->f_bsize);
|
|
put_fs_long(res.blocks, &buf->f_blocks);
|
|
put_fs_long(res.bfree, &buf->f_bfree);
|
|
put_fs_long(res.bavail, &buf->f_bavail);
|
|
put_fs_long(0, &buf->f_files);
|
|
put_fs_long(0, &buf->f_ffree);
|
|
/* We should really try to interrogate the remote server to find
|
|
it's maximum name length here */
|
|
put_fs_long(NAME_MAX, &buf->f_namelen);
|
|
}
|
|
|
|
/*
|
|
* This is our own version of iget that looks up inodes by file handle
|
|
* instead of inode number. We use this technique instead of using
|
|
* the vfs read_inode function because there is no way to pass the
|
|
* file handle or current attributes into the read_inode function.
|
|
* We just have to be careful not to subvert iget's special handling
|
|
* of mount points.
|
|
*/
|
|
|
|
struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
|
|
struct nfs_fattr *fattr)
|
|
{
|
|
struct nfs_fattr newfattr;
|
|
int error;
|
|
struct inode *inode;
|
|
|
|
if (!sb) {
|
|
printk("nfs_fhget: super block is NULL\n");
|
|
return NULL;
|
|
}
|
|
if (!fattr) {
|
|
error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle,
|
|
&newfattr);
|
|
if (error) {
|
|
printk("nfs_fhget: getattr error = %d\n", -error);
|
|
return NULL;
|
|
}
|
|
fattr = &newfattr;
|
|
}
|
|
if (!(inode = iget(sb, fattr->fileid))) {
|
|
printk("nfs_fhget: iget failed\n");
|
|
return NULL;
|
|
}
|
|
if (inode->i_dev == sb->s_dev) {
|
|
if (inode->i_ino != fattr->fileid) {
|
|
printk("nfs_fhget: unexpected inode from iget\n");
|
|
return inode;
|
|
}
|
|
*NFS_FH(inode) = *fhandle;
|
|
nfs_refresh_inode(inode, fattr);
|
|
}
|
|
return inode;
|
|
}
|
|
|
|
int nfs_notify_change(int flags, struct inode *inode)
|
|
{
|
|
struct nfs_sattr sattr;
|
|
struct nfs_fattr fattr;
|
|
int error;
|
|
|
|
if (flags & NOTIFY_MODE)
|
|
sattr.mode = inode->i_mode;
|
|
else
|
|
sattr.mode = (unsigned) -1;
|
|
if (flags & NOTIFY_UIDGID) {
|
|
sattr.uid = inode->i_uid;
|
|
sattr.gid = inode->i_gid;
|
|
}
|
|
else
|
|
sattr.uid = sattr.gid = (unsigned) -1;
|
|
if (flags & NOTIFY_SIZE)
|
|
sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1;
|
|
else
|
|
sattr.size = (unsigned) -1;
|
|
if (flags & NOTIFY_TIME) {
|
|
sattr.mtime.seconds = inode->i_mtime;
|
|
sattr.mtime.useconds = 0;
|
|
sattr.atime.seconds = inode->i_atime;
|
|
sattr.atime.useconds = 0;
|
|
}
|
|
else {
|
|
sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1;
|
|
sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1;
|
|
}
|
|
error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
|
|
&sattr, &fattr);
|
|
if (!error)
|
|
nfs_refresh_inode(inode, &fattr);
|
|
inode->i_dirt = 0;
|
|
return error;
|
|
}
|
|
|