summaryrefslogtreecommitdiffstats
path: root/fs/nfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r--fs/nfs/inode.c240
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;
+}