NFS: Split fs/nfs/inode.c

As fs/nfs/inode.c is rather large, heterogenous and unwieldy, the attached
patch splits it up into a number of files:

 (*) fs/nfs/inode.c

     Strictly inode specific functions.

 (*) fs/nfs/super.c

     Superblock management functions for NFS and NFS4, normal access, clones
     and referrals.  The NFS4 superblock functions _could_ move out into a
     separate conditionally compiled file, but it's probably not worth it as
     there're so many common bits.

 (*) fs/nfs/namespace.c

     Some namespace-specific functions have been moved here.

 (*) fs/nfs/nfs4namespace.c

     NFS4-specific namespace functions (this could be merged into the previous
     file).  This file is conditionally compiled.

 (*) fs/nfs/internal.h

     Inter-file declarations, plus a few simple utility functions moved from
     fs/nfs/inode.c.

     Additionally, all the in-.c-file externs have been moved here, and those
     files they were moved from now includes this file.

For the most part, the functions have not been changed, only some multiplexor
functions have changed significantly.

I've also:

 (*) Added some extra banner comments above some functions.

 (*) Rearranged the function order within the files to be more logical and
     better grouped (IMO), though someone may prefer a different order.

 (*) Reduced the number of #ifdefs in .c files.

 (*) Added missing __init and __exit directives.

Signed-Off-By: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2006-06-09 09:34:33 -04:00 committed by Trond Myklebust
parent 4e5ccf60c5
commit f7b422b17e
16 changed files with 1993 additions and 1802 deletions

View file

@ -4,7 +4,7 @@
obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := dir.o file.o inode.o nfs2xdr.o pagelist.o \
nfs-y := dir.o file.o inode.o super.o nfs2xdr.o pagelist.o \
proc.o read.o symlink.o unlink.o write.o \
namespace.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
@ -12,7 +12,8 @@ nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o
callback.o callback_xdr.o callback_proc.o \
nfs4namespace.o
nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-objs := $(nfs-y)

View file

@ -182,8 +182,6 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp)
/*
* Define NFS4 callback program
*/
extern struct svc_version nfs4_callback_version1;
static struct svc_version *nfs4_callback_version[] = {
[1] = &nfs4_callback_version1,
};

View file

@ -892,7 +892,7 @@ out:
* nfs_init_directcache - create a slab cache for nfs_direct_req structures
*
*/
int nfs_init_directcache(void)
int __init nfs_init_directcache(void)
{
nfs_direct_cachep = kmem_cache_create("nfs_direct_cache",
sizeof(struct nfs_direct_req),
@ -906,10 +906,10 @@ int nfs_init_directcache(void)
}
/**
* nfs_init_directcache - destroy the slab cache for nfs_direct_req structures
* nfs_destroy_directcache - destroy the slab cache for nfs_direct_req structures
*
*/
void nfs_destroy_directcache(void)
void __exit nfs_destroy_directcache(void)
{
if (kmem_cache_destroy(nfs_direct_cachep))
printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");

File diff suppressed because it is too large Load diff

179
fs/nfs/internal.h Normal file
View file

@ -0,0 +1,179 @@
/*
* NFS internal definitions
*/
#include <linux/mount.h>
struct nfs_clone_mount {
const struct super_block *sb;
const struct dentry *dentry;
struct nfs_fh *fh;
struct nfs_fattr *fattr;
char *hostname;
char *mnt_path;
struct sockaddr_in *addr;
rpc_authflavor_t authflavor;
};
/* namespace-nfs4.c */
#ifdef CONFIG_NFS_V4
extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry);
#else
static inline
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
{
return ERR_PTR(-ENOENT);
}
#endif
/* callback_xdr.c */
extern struct svc_version nfs4_callback_version1;
/* pagelist.c */
extern int __init nfs_init_nfspagecache(void);
extern void __exit nfs_destroy_nfspagecache(void);
extern int __init nfs_init_readpagecache(void);
extern void __exit nfs_destroy_readpagecache(void);
extern int __init nfs_init_writepagecache(void);
extern void __exit nfs_destroy_writepagecache(void);
#ifdef CONFIG_NFS_DIRECTIO
extern int __init nfs_init_directcache(void);
extern void __exit nfs_destroy_directcache(void);
#else
#define nfs_init_directcache() (0)
#define nfs_destroy_directcache() do {} while(0)
#endif
/* nfs2xdr.c */
extern struct rpc_procinfo nfs_procedures[];
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
/* nfs3xdr.c */
extern struct rpc_procinfo nfs3_procedures[];
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
/* nfs4xdr.c */
extern int nfs_stat_to_errno(int);
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
/* nfs4proc.c */
extern struct rpc_procinfo nfs4_procedures[];
extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
struct nfs4_fs_locations *fs_locations,
struct page *page);
/* inode.c */
extern struct inode *nfs_alloc_inode(struct super_block *sb);
extern void nfs_destroy_inode(struct inode *);
extern int nfs_write_inode(struct inode *,int);
extern void nfs_clear_inode(struct inode *);
#ifdef CONFIG_NFS_V4
extern void nfs4_clear_inode(struct inode *);
#endif
/* super.c */
extern struct file_system_type nfs_referral_nfs4_fs_type;
extern struct file_system_type clone_nfs_fs_type;
#ifdef CONFIG_NFS_V4
extern struct file_system_type clone_nfs4_fs_type;
#endif
#ifdef CONFIG_PROC_FS
extern struct rpc_stat nfs_rpcstat;
#endif
extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void);
/* namespace.c */
extern char *nfs_path(const char *base, const struct dentry *dentry,
char *buffer, ssize_t buflen);
/*
* Determine the mount path as a string
*/
static inline char *nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
{
return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
}
/*
* Determine the device name as a string
*/
static inline char *nfs_devname(const struct vfsmount *mnt_parent,
const struct dentry *dentry,
char *buffer, ssize_t buflen)
{
return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
}
/*
* Determine the actual block size (and log2 thereof)
*/
static inline
unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
{
/* make sure blocksize is a power of two */
if ((bsize & (bsize - 1)) || nrbitsp) {
unsigned char nrbits;
for (nrbits = 31; nrbits && !(bsize & (1 << nrbits)); nrbits--)
;
bsize = 1 << nrbits;
if (nrbitsp)
*nrbitsp = nrbits;
}
return bsize;
}
/*
* Calculate the number of 512byte blocks used.
*/
static inline unsigned long nfs_calc_block_size(u64 tsize)
{
loff_t used = (tsize + 511) >> 9;
return (used > ULONG_MAX) ? ULONG_MAX : used;
}
/*
* Compute and set NFS server blocksize
*/
static inline
unsigned long nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
{
if (bsize < NFS_MIN_FILE_IO_SIZE)
bsize = NFS_DEF_FILE_IO_SIZE;
else if (bsize >= NFS_MAX_FILE_IO_SIZE)
bsize = NFS_MAX_FILE_IO_SIZE;
return nfs_block_bits(bsize, nrbitsp);
}
/*
* Determine the maximum file size for a superblock
*/
static inline
void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
{
sb->s_maxbytes = (loff_t)maxfilesize;
if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
sb->s_maxbytes = MAX_LFS_FILESIZE;
}
/*
* Check if the string represents a "valid" IPv4 address
*/
static inline int valid_ipaddr4(const char *buf)
{
int rc, count, in[4];
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
if (rc != 4)
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
return -EINVAL;
}
return 0;
}

View file

@ -15,14 +15,63 @@
#include <linux/string.h>
#include <linux/sunrpc/clnt.h>
#include <linux/vfs.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_VFS
LIST_HEAD(nfs_automount_list);
static void nfs_expire_automounts(void *list);
LIST_HEAD(nfs_automount_list);
static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
int nfs_mountpoint_expiry_timeout = 500 * HZ;
/*
* nfs_path - reconstruct the path given an arbitrary dentry
* @base - arbitrary string to prepend to the path
* @dentry - pointer to dentry
* @buffer - result buffer
* @buflen - length of buffer
*
* Helper function for constructing the path from the
* root dentry to an arbitrary hashed dentry.
*
* This is mainly for use in figuring out the path on the
* server side when automounting on top of an existing partition.
*/
char *nfs_path(const char *base, const struct dentry *dentry,
char *buffer, ssize_t buflen)
{
char *end = buffer+buflen;
int namelen;
*--end = '\0';
buflen--;
spin_lock(&dcache_lock);
while (!IS_ROOT(dentry)) {
namelen = dentry->d_name.len;
buflen -= namelen + 1;
if (buflen < 0)
goto Elong;
end -= namelen;
memcpy(end, dentry->d_name.name, namelen);
*--end = '/';
dentry = dentry->d_parent;
}
spin_unlock(&dcache_lock);
namelen = strlen(base);
/* Strip off excess slashes in base string */
while (namelen > 0 && base[namelen - 1] == '/')
namelen--;
buflen -= namelen;
if (buflen < 0)
goto Elong;
end -= namelen;
memcpy(end, base, namelen);
return end;
Elong:
return ERR_PTR(-ENAMETOOLONG);
}
/*
* nfs_follow_mountpoint - handle crossing a mountpoint on the server
* @dentry - dentry of mountpoint
@ -117,3 +166,64 @@ void nfs_release_automount_timer(void)
flush_scheduled_work();
}
}
/*
* Clone a mountpoint of the appropriate type
*/
static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, char *devname,
struct nfs_clone_mount *mountdata)
{
#ifdef CONFIG_NFS_V4
struct vfsmount *mnt = NULL;
switch (server->rpc_ops->version) {
case 2:
case 3:
mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
break;
case 4:
mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
}
return mnt;
#else
return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
#endif
}
/**
* nfs_do_submount - set up mountpoint when crossing a filesystem boundary
* @mnt_parent - mountpoint of parent directory
* @dentry - parent directory
* @fh - filehandle for new root dentry
* @fattr - attributes for new root inode
*
*/
struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
const struct dentry *dentry, struct nfs_fh *fh,
struct nfs_fattr *fattr)
{
struct nfs_clone_mount mountdata = {
.sb = mnt_parent->mnt_sb,
.dentry = dentry,
.fh = fh,
.fattr = fattr,
};
struct vfsmount *mnt = ERR_PTR(-ENOMEM);
char *page = (char *) __get_free_page(GFP_USER);
char *devname;
dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
dentry->d_parent->d_name.name,
dentry->d_name.name);
if (page == NULL)
goto out;
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
mnt = (struct vfsmount *)devname;
if (IS_ERR(devname))
goto free_page;
mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata);
free_page:
free_page((unsigned long)page);
out:
dprintk("%s: done\n", __FUNCTION__);
return mnt;
}

View file

@ -27,8 +27,6 @@
#define NFSDBG_FACILITY NFSDBG_XDR
/* #define NFS_PARANOIA 1 */
extern int nfs_stat_to_errno(int stat);
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO

View file

@ -20,11 +20,10 @@
#include <linux/nfs_mount.h>
#include "iostat.h"
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
extern struct rpc_procinfo nfs3_procedures[];
/* A wrapper to handle the EJUKEBOX error message */
static int
nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
@ -809,8 +808,6 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return status;
}
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
static int nfs3_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
if (nfs3_async_handle_jukebox(task, data->inode))

View file

@ -22,14 +22,13 @@
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
#include <linux/nfsacl.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_XDR
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
extern int nfs_stat_to_errno(int);
/*
* Declare the space requirements for NFS arguments and replies as
* number of 32bit-words

201
fs/nfs/nfs4namespace.c Normal file
View file

@ -0,0 +1,201 @@
/*
* linux/fs/nfs/nfs4namespace.c
*
* Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
*
* NFSv4 namespace
*/
#include <linux/config.h>
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/nfs_fs.h>
#include <linux/string.h>
#include <linux/sunrpc/clnt.h>
#include <linux/vfs.h>
#include <linux/inet.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_VFS
/*
* Check if fs_root is valid
*/
static inline char *nfs4_pathname_string(struct nfs4_pathname *pathname,
char *buffer, ssize_t buflen)
{
char *end = buffer + buflen;
int n;
*--end = '\0';
buflen--;
n = pathname->ncomponents;
while (--n >= 0) {
struct nfs4_string *component = &pathname->components[n];
buflen -= component->len + 1;
if (buflen < 0)
goto Elong;
end -= component->len;
memcpy(end, component->data, component->len);
*--end = '/';
}
return end;
Elong:
return ERR_PTR(-ENAMETOOLONG);
}
/**
* nfs_follow_referral - set up mountpoint when hitting a referral on moved error
* @mnt_parent - mountpoint of parent directory
* @dentry - parent directory
* @fspath - fs path returned in fs_locations
* @mntpath - mount path to new server
* @hostname - hostname of new server
* @addr - host addr of new server
*
*/
static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent,
const struct dentry *dentry,
struct nfs4_fs_locations *locations)
{
struct vfsmount *mnt = ERR_PTR(-ENOENT);
struct nfs_clone_mount mountdata = {
.sb = mnt_parent->mnt_sb,
.dentry = dentry,
.authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
};
char *page, *page2;
char *path, *fs_path;
char *devname;
int loc, s;
if (locations == NULL || locations->nlocations <= 0)
goto out;
dprintk("%s: referral at %s/%s\n", __FUNCTION__,
dentry->d_parent->d_name.name, dentry->d_name.name);
/* Ensure fs path is a prefix of current dentry path */
page = (char *) __get_free_page(GFP_USER);
if (page == NULL)
goto out;
page2 = (char *) __get_free_page(GFP_USER);
if (page2 == NULL)
goto out;
path = nfs4_path(dentry, page, PAGE_SIZE);
if (IS_ERR(path))
goto out_free;
fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
if (IS_ERR(fs_path))
goto out_free;
if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
goto out_free;
}
devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
if (IS_ERR(devname)) {
mnt = (struct vfsmount *)devname;
goto out_free;
}
loc = 0;
while (loc < locations->nlocations && IS_ERR(mnt)) {
struct nfs4_fs_location *location = &locations->locations[loc];
char *mnt_path;
if (location == NULL || location->nservers <= 0 ||
location->rootpath.ncomponents == 0) {
loc++;
continue;
}
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
if (IS_ERR(mnt_path)) {
loc++;
continue;
}
mountdata.mnt_path = mnt_path;
s = 0;
while (s < location->nservers) {
struct sockaddr_in addr = {};
if (location->servers[s].len <= 0 ||
valid_ipaddr4(location->servers[s].data) < 0) {
s++;
continue;
}
mountdata.hostname = location->servers[s].data;
addr.sin_addr.s_addr = in_aton(mountdata.hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(NFS_PORT);
mountdata.addr = &addr;
mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
if (!IS_ERR(mnt)) {
break;
}
s++;
}
loc++;
}
out_free:
free_page((unsigned long)page);
free_page((unsigned long)page2);
out:
dprintk("%s: done\n", __FUNCTION__);
return mnt;
}
/*
* nfs_do_refmount - handle crossing a referral on server
* @dentry - dentry of referral
* @nd - nameidata info
*
*/
struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
{
struct vfsmount *mnt = ERR_PTR(-ENOENT);
struct dentry *parent;
struct nfs4_fs_locations *fs_locations = NULL;
struct page *page;
int err;
/* BUG_ON(IS_ROOT(dentry)); */
dprintk("%s: enter\n", __FUNCTION__);
page = alloc_page(GFP_KERNEL);
if (page == NULL)
goto out;
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
if (fs_locations == NULL)
goto out_free;
/* Get locations */
parent = dget_parent(dentry);
dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
dput(parent);
if (err != 0 || fs_locations->nlocations <= 0 ||
fs_locations->fs_path.ncomponents <= 0)
goto out_free;
mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations);
out_free:
__free_page(page);
kfree(fs_locations);
out:
dprintk("%s: done\n", __FUNCTION__);
return mnt;
}

View file

@ -65,8 +65,6 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *)
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[];
/* Prevent leaks of NFSv4 errors into userland */
int nfs4_map_errors(int err)

View file

@ -378,7 +378,7 @@ out:
return res;
}
int nfs_init_nfspagecache(void)
int __init nfs_init_nfspagecache(void)
{
nfs_page_cachep = kmem_cache_create("nfs_page",
sizeof(struct nfs_page),
@ -390,7 +390,7 @@ int nfs_init_nfspagecache(void)
return 0;
}
void nfs_destroy_nfspagecache(void)
void __exit nfs_destroy_nfspagecache(void)
{
if (kmem_cache_destroy(nfs_page_cachep))
printk(KERN_INFO "nfs_page: not all structures were freed\n");

View file

@ -44,11 +44,10 @@
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
extern struct rpc_procinfo nfs_procedures[];
/*
* Bare-bones access to getattr: this is for nfs_read_super.
*/
@ -611,8 +610,6 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return 0;
}
extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
if (task->tk_status >= 0) {

View file

@ -694,7 +694,7 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
return ret;
}
int nfs_init_readpagecache(void)
int __init nfs_init_readpagecache(void)
{
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
sizeof(struct nfs_read_data),
@ -711,7 +711,7 @@ int nfs_init_readpagecache(void)
return 0;
}
void nfs_destroy_readpagecache(void)
void __exit nfs_destroy_readpagecache(void)
{
mempool_destroy(nfs_rdata_mempool);
if (kmem_cache_destroy(nfs_rdata_cachep))

1468
fs/nfs/super.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1529,7 +1529,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
return ret;
}
int nfs_init_writepagecache(void)
int __init nfs_init_writepagecache(void)
{
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
sizeof(struct nfs_write_data),
@ -1551,7 +1551,7 @@ int nfs_init_writepagecache(void)
return 0;
}
void nfs_destroy_writepagecache(void)
void __exit nfs_destroy_writepagecache(void)
{
mempool_destroy(nfs_commit_mempool);
mempool_destroy(nfs_wdata_mempool);