diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1994-11-28 11:59:19 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1994-11-28 11:59:19 +0000 |
commit | 1513ff9b7899ab588401c89db0e99903dbf5f886 (patch) | |
tree | f69cc81a940a502ea23d664c3ffb2d215a479667 /fs/nfs/inode.c |
Import of Linus's Linux 1.1.68
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c new file mode 100644 index 000000000..17f2cb6f0 --- /dev/null +++ b/fs/nfs/inode.c @@ -0,0 +1,240 @@ +/* + * 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(struct inode *, struct iattr *); +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->files->fd[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(struct inode *inode, struct iattr *attr) +{ + struct nfs_sattr sattr; + struct nfs_fattr fattr; + int error; + + if (attr->ia_valid & ATTR_MODE) + sattr.mode = attr->ia_mode; + else + sattr.mode = (unsigned) -1; + + if (attr->ia_valid & ATTR_UID) + sattr.uid = attr->ia_uid; + else + sattr.uid = (unsigned) -1; + + if (attr->ia_valid & ATTR_GID) + sattr.gid = attr->ia_gid; + else + sattr.gid = (unsigned) -1; + + if (attr->ia_valid & ATTR_SIZE) + sattr.size = S_ISREG(inode->i_mode) ? attr->ia_size : -1; + else + sattr.size = (unsigned) -1; + + if (attr->ia_valid & ATTR_MTIME) { + sattr.mtime.seconds = attr->ia_mtime; + sattr.mtime.useconds = 0; + } else + sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1; + + if (attr->ia_valid & ATTR_ATIME) { + sattr.atime.seconds = attr->ia_atime; + sattr.atime.useconds = 0; + } else + 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; +} |