URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [nfs/] [inode.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * linux/fs/nfs/inode.c * * Copyright (C) 1992 Rick Sladkey * * nfs inode and superblock handling functions * * 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 * */ #include <linux/module.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/segment.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 = { nfs_read_inode, /* 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 }; /* * 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) { 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); MOD_DEC_USE_COUNT; } /* * 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 these 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; kdev_t dev = sb->s_dev; MOD_INC_USE_COUNT; if (!data) { printk("nfs_read_super: missing data argument\n"); sb->s_dev = 0; MOD_DEC_USE_COUNT; 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; MOD_DEC_USE_COUNT; return NULL; } if (!S_ISSOCK(filp->f_inode->i_mode)) { printk("nfs_read_super: not a socket\n"); sb->s_dev = 0; MOD_DEC_USE_COUNT; 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); /* 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))) { sb->s_dev = 0; printk("nfs_read_super: get root inode failed\n"); MOD_DEC_USE_COUNT; return NULL; } return sb; } void nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { int error; struct nfs_fsinfo res; struct statfs tmp; 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; } tmp.f_type = NFS_SUPER_MAGIC; tmp.f_bsize = res.bsize; tmp.f_blocks = res.blocks; tmp.f_bfree = res.bfree; tmp.f_bavail = res.bavail; tmp.f_files = 0; tmp.f_ffree = 0; tmp.f_namelen = NAME_MAX; memcpy_tofs(buf, &tmp, bufsiz); } /* * 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; sattr.mode = (unsigned) -1; if (attr->ia_valid & ATTR_MODE) sattr.mode = attr->ia_mode; sattr.uid = (unsigned) -1; if (attr->ia_valid & ATTR_UID) sattr.uid = attr->ia_uid; sattr.gid = (unsigned) -1; if (attr->ia_valid & ATTR_GID) sattr.gid = attr->ia_gid; sattr.size = (unsigned) -1; if (attr->ia_valid & ATTR_SIZE) sattr.size = S_ISREG(inode->i_mode) ? attr->ia_size : -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; } sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1; if (attr->ia_valid & ATTR_ATIME) { sattr.atime.seconds = attr->ia_atime; sattr.atime.useconds = 0; } 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; } /* Every kernel module contains stuff like this. */ 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"); #ifndef MODULE current->blocked = ~0UL; #endif 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) { 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