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.c163
1 files changed, 131 insertions, 32 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 94b4b4557..e47227011 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -7,37 +7,43 @@
*
* Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
* experimental NFS changes. Modularisation taken straight from SYS5 fs.
+ *
+ * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
+ * J.S.Peatfield@damtp.cam.ac.uk
+ *
*/
-#ifdef MODULE
#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
-#include <asm/system.h>
-#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/nfs_fs.h>
+#include <linux/nfsiod.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>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/* This is for kernel_thread */
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
extern int close_fp(struct file *filp);
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_read_inode(struct inode *);
static void nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
static struct super_operations nfs_sops = {
- NULL, /* read inode */
+ nfs_read_inode, /* read inode */
nfs_notify_change, /* notify change */
NULL, /* write inode */
nfs_put_inode, /* put inode */
@@ -47,14 +53,38 @@ static struct super_operations nfs_sops = {
NULL
};
+/*
+ * The "read_inode" function doesn't actually do anything:
+ * the real data is filled in later in nfs_fhget. Here we
+ * just mark the cache times invalid, and zero out i_mode
+ * (the latter makes "nfs_refresh_inode" do the right thing
+ * wrt pipe inodes)
+ */
+static void nfs_read_inode(struct inode * inode)
+{
+ int rsize = inode->i_sb->u.nfs_sb.s_server.rsize;
+ int size = inode->i_sb->u.nfs_sb.s_server.wsize;
+
+ if (rsize > size)
+ size = rsize;
+ inode->i_blksize = size;
+ inode->i_mode = 0;
+ inode->i_op = NULL;
+ NFS_CACHEINV(inode);
+}
+
static void nfs_put_inode(struct inode * inode)
{
- clear_inode(inode);
+ if (NFS_RENAMED_DIR(inode))
+ nfs_sillyrename_cleanup(inode);
+ if (inode->i_pipe)
+ clear_inode(inode);
}
void nfs_put_super(struct super_block *sb)
{
close_fp(sb->u.nfs_sb.s_server.file);
+ rpc_closesock(sb->u.nfs_sb.s_server.rsock);
lock_super(sb);
sb->s_dev = 0;
unlock_super(sb);
@@ -65,7 +95,7 @@ void nfs_put_super(struct super_block *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.
+ * daemon. We stash these away in the private superblock fields.
* Later we can add other mount parameters like caching values.
*/
@@ -76,7 +106,8 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
struct nfs_server *server;
unsigned int fd;
struct file *filp;
- dev_t dev = sb->s_dev;
+
+ kdev_t dev = sb->s_dev;
MOD_INC_USE_COUNT;
if (!data) {
@@ -104,6 +135,7 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
}
filp->f_count++;
lock_super(sb);
+
sb->s_blocksize = 1024; /* XXX */
sb->s_blocksize_bits = 10;
sb->s_magic = NFS_SUPER_MAGIC;
@@ -131,6 +163,38 @@ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
strcpy(server->hostname, data->hostname);
+
+ /* Start of JSP NFS patch */
+ /* Check if passed address in data->addr */
+ if (data->addr.sin_addr.s_addr == INADDR_ANY) { /* No address passed */
+ if (((struct sockaddr_in *)(&server->toaddr))->sin_addr.s_addr == INADDR_ANY) {
+ printk("NFS: Error passed unconnected socket and no address\n") ;
+ MOD_DEC_USE_COUNT;
+ return NULL ;
+ } else {
+ /* Need access to socket internals JSP */
+ struct socket *sock;
+ int dummylen ;
+
+ /* printk("NFS: using socket address\n") ;*/
+
+ sock = &((filp->f_inode)->u.socket_i);
+
+ /* extract the other end of the socket into server->toaddr */
+ sock->ops->getname(sock, &(server->toaddr), &dummylen, 1) ;
+ }
+ } else {
+ /* printk("NFS: copying passed addr to server->toaddr\n") ;*/
+ memcpy((char *)&(server->toaddr),(char *)(&data->addr),sizeof(server->toaddr));
+ }
+ /* End of JSP NFS patch */
+
+ if ((server->rsock = rpc_makesock(filp)) == NULL) {
+ printk("NFS: cannot create RPC socket.\n");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
sb->u.nfs_sb.s_root = data->root;
unlock_super(sb);
if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) {
@@ -162,7 +226,7 @@ void nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = 0;
tmp.f_ffree = 0;
tmp.f_namelen = NAME_MAX;
- memcpy_tofs(buf, &tmp, bufsiz);
+ copy_to_user(buf, &tmp, bufsiz);
}
/*
@@ -215,37 +279,34 @@ int nfs_notify_change(struct inode *inode, struct iattr *attr)
struct nfs_fattr fattr;
int error;
+ sattr.mode = (unsigned) -1;
if (attr->ia_valid & ATTR_MODE)
sattr.mode = attr->ia_mode;
- else
- sattr.mode = (unsigned) -1;
+ sattr.uid = (unsigned) -1;
if (attr->ia_valid & ATTR_UID)
sattr.uid = attr->ia_uid;
- else
- sattr.uid = (unsigned) -1;
+ sattr.gid = (unsigned) -1;
if (attr->ia_valid & ATTR_GID)
sattr.gid = attr->ia_gid;
- else
- sattr.gid = (unsigned) -1;
+
+ sattr.size = (unsigned) -1;
if (attr->ia_valid & ATTR_SIZE)
sattr.size = S_ISREG(inode->i_mode) ? attr->ia_size : -1;
- else
- sattr.size = (unsigned) -1;
+ sattr.mtime.seconds = sattr.mtime.useconds = (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;
+ }
+ sattr.atime.seconds = sattr.atime.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);
@@ -255,25 +316,63 @@ int nfs_notify_change(struct inode *inode, struct iattr *attr)
return error;
}
-#ifdef MODULE
-
/* Every kernel module contains stuff like this. */
-char kernel_version[] = UTS_RELEASE;
-
static struct file_system_type nfs_fs_type = {
nfs_read_super, "nfs", 0, NULL
};
+/*
+ * Start up an nfsiod process. This is an awful hack, because when running
+ * as a module, we will keep insmod's memory. Besides, the current->comm
+ * hack won't work in this case
+ * The best would be to have a syscall for nfs client control that (among
+ * other things) forks biod's.
+ * Alternatively, we might want to have the idle task spawn biod's on demand.
+ */
+static int run_nfsiod(void *dummy)
+{
+ int ret;
+
+#ifdef __SMP__
+ lock_kernel();
+ syscall_count++;
+#endif
+
+ MOD_INC_USE_COUNT;
+ exit_mm(current);
+ current->session = 1;
+ current->pgrp = 1;
+ sprintf(current->comm, "nfsiod");
+ ret = nfsiod();
+ MOD_DEC_USE_COUNT;
+ return ret;
+}
+
+int init_nfs_fs(void)
+{
+ /* Fork four biod's */
+ kernel_thread(run_nfsiod, NULL, 0);
+ kernel_thread(run_nfsiod, NULL, 0);
+ kernel_thread(run_nfsiod, NULL, 0);
+ kernel_thread(run_nfsiod, NULL, 0);
+ return register_filesystem(&nfs_fs_type);
+}
+
+#ifdef MODULE
int init_module(void)
{
- register_filesystem(&nfs_fs_type);
- return 0;
+ int status;
+
+ if ((status = init_nfs_fs()) == 0)
+ register_symtab(0);
+ return status;
}
void cleanup_module(void)
{
unregister_filesystem(&nfs_fs_type);
+ nfs_kfree_cache();
}
#endif