📄 inode.c
字号:
/* * 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/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/time.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/unistd.h>#include <linux/sunrpc/clnt.h>#include <linux/sunrpc/stats.h>#include <linux/nfs_fs.h>#include <linux/nfs_mount.h>#include <linux/nfs4_mount.h>#include <linux/lockd/bind.h>#include <linux/smp_lock.h>#include <linux/seq_file.h>#include <linux/mount.h>#include <linux/nfs_idmap.h>#include <linux/vfs.h>#include <asm/system.h>#include <asm/uaccess.h>#include "delegation.h"#define NFSDBG_FACILITY NFSDBG_VFS#define NFS_PARANOIA 1/* Maximum number of readahead requests * FIXME: this should really be a sysctl so that users may tune it to suit * their needs. People that do NFS over a slow network, might for * instance want to reduce it to something closer to 1 for improved * interactive response. */#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)static void nfs_invalidate_inode(struct inode *);static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long);static struct inode *nfs_alloc_inode(struct super_block *sb);static void nfs_destroy_inode(struct inode *);static int nfs_write_inode(struct inode *,int);static void nfs_delete_inode(struct inode *);static void nfs_clear_inode(struct inode *);static void nfs_umount_begin(struct super_block *);static int nfs_statfs(struct super_block *, struct kstatfs *);static int nfs_show_options(struct seq_file *, struct vfsmount *);static struct super_operations nfs_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs_write_inode, .delete_inode = nfs_delete_inode, .statfs = nfs_statfs, .clear_inode = nfs_clear_inode, .umount_begin = nfs_umount_begin, .show_options = nfs_show_options,};/* * RPC cruft for NFS */struct rpc_stat nfs_rpcstat = { .program = &nfs_program};static struct rpc_version * nfs_version[] = { NULL, NULL, &nfs_version2,#if defined(CONFIG_NFS_V3) &nfs_version3,#elif defined(CONFIG_NFS_V4) NULL,#endif#if defined(CONFIG_NFS_V4) &nfs_version4,#endif};struct rpc_program nfs_program = { .name = "nfs", .number = NFS_PROGRAM, .nrvers = sizeof(nfs_version) / sizeof(nfs_version[0]), .version = nfs_version, .stats = &nfs_rpcstat, .pipe_dir_name = "/nfs",};static inline unsigned longnfs_fattr_to_ino_t(struct nfs_fattr *fattr){ return nfs_fileid_to_ino_t(fattr->fileid);}static intnfs_write_inode(struct inode *inode, int sync){ int flags = sync ? FLUSH_WAIT : 0; int ret; ret = nfs_commit_inode(inode, 0, 0, flags); if (ret < 0) return ret; return 0;}static voidnfs_delete_inode(struct inode * inode){ dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); nfs_wb_all(inode); /* * The following should never happen... */ if (nfs_have_writebacks(inode)) { printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); } clear_inode(inode);}/* * For the moment, the only task for the NFS clear_inode method is to * release the mmap credential */static voidnfs_clear_inode(struct inode *inode){ struct nfs_inode *nfsi = NFS_I(inode); struct rpc_cred *cred; nfs_wb_all(inode); BUG_ON (!list_empty(&nfsi->open_files)); cred = nfsi->cache_access.cred; if (cred) put_rpccred(cred); BUG_ON(atomic_read(&nfsi->data_updates) != 0);}voidnfs_umount_begin(struct super_block *sb){ struct nfs_server *server = NFS_SB(sb); struct rpc_clnt *rpc; /* -EIO all pending I/O */ if ((rpc = server->client) != NULL) rpc_killall_tasks(rpc);}static inline unsigned longnfs_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 longnfs_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 longnfs_block_size(unsigned long bsize, unsigned char *nrbitsp){ if (bsize < 1024) bsize = NFS_DEF_FILE_IO_BUFFER_SIZE; else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) bsize = NFS_MAX_FILE_IO_BUFFER_SIZE; return nfs_block_bits(bsize, nrbitsp);}/* * Obtain the root inode of the file system. */static struct inode *nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo){ struct nfs_server *server = NFS_SB(sb); struct inode *rooti; int error; error = server->rpc_ops->getroot(server, rootfh, fsinfo); if (error < 0) { dprintk("nfs_get_root: getattr error = %d\n", -error); return ERR_PTR(error); } rooti = nfs_fhget(sb, rootfh, fsinfo->fattr); if (!rooti) return ERR_PTR(-ENOMEM); return rooti;}/* * Do NFS version-independent mount processing, and sanity checking */static intnfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor){ struct nfs_server *server; struct inode *root_inode; struct nfs_fattr fattr; struct nfs_fsinfo fsinfo = { .fattr = &fattr, }; struct nfs_pathconf pathinfo = { .fattr = &fattr, }; int no_root_error = 0; /* We probably want something more informative here */ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); server = NFS_SB(sb); sb->s_magic = NFS_SUPER_MAGIC; root_inode = nfs_get_root(sb, &server->fh, &fsinfo); /* Did getting the root inode fail? */ if (IS_ERR(root_inode)) { no_root_error = PTR_ERR(root_inode); goto out_no_root; } sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) { no_root_error = -ENOMEM; goto out_no_root; } sb->s_root->d_op = server->rpc_ops->dentry_ops; /* Get some general file system info */ if (server->namelen == 0 && server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) server->namelen = pathinfo.max_namelen; /* Work out a lot of parameters */ if (server->rsize == 0) server->rsize = nfs_block_size(fsinfo.rtpref, NULL); if (server->wsize == 0) server->wsize = nfs_block_size(fsinfo.wtpref, NULL); if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax) server->rsize = nfs_block_size(fsinfo.rtmax, NULL); if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax) server->wsize = nfs_block_size(fsinfo.wtmax, NULL); server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if (server->rpages > NFS_READ_MAXIOV) { server->rpages = NFS_READ_MAXIOV; server->rsize = server->rpages << PAGE_CACHE_SHIFT; } server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; if (server->wpages > NFS_WRITE_MAXIOV) { server->wpages = NFS_WRITE_MAXIOV; server->wsize = server->wpages << PAGE_CACHE_SHIFT; } if (sb->s_blocksize == 0) sb->s_blocksize = nfs_block_bits(server->wsize, &sb->s_blocksize_bits); server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); server->dtsize = nfs_block_size(fsinfo.dtpref, NULL); if (server->dtsize > PAGE_CACHE_SIZE) server->dtsize = PAGE_CACHE_SIZE; if (server->dtsize > server->rsize) server->dtsize = server->rsize; if (server->flags & NFS_MOUNT_NOAC) { server->acregmin = server->acregmax = 0; server->acdirmin = server->acdirmax = 0; sb->s_flags |= MS_SYNCHRONOUS; } server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; sb->s_maxbytes = fsinfo.maxfilesize; if (sb->s_maxbytes > MAX_LFS_FILESIZE) sb->s_maxbytes = MAX_LFS_FILESIZE; /* We're airborne Set socket buffersize */ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); return 0; /* Yargs. It didn't work out. */out_no_root: dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error); if (!IS_ERR(root_inode)) iput(root_inode); return no_root_error;}/* * Create an RPC client handle. */static struct rpc_clnt *nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data){ struct rpc_timeout timeparms; struct rpc_xprt *xprt = NULL; struct rpc_clnt *clnt = NULL; int tcp = (data->flags & NFS_MOUNT_TCP); /* Initialize timeout values */ timeparms.to_initval = data->timeo * HZ / 10; timeparms.to_retries = data->retrans; timeparms.to_maxval = tcp ? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT; timeparms.to_exponential = 1; if (!timeparms.to_initval) timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10; if (!timeparms.to_retries) timeparms.to_retries = 5; /* create transport and client */ xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, &server->addr, &timeparms); if (IS_ERR(xprt)) { printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); return (struct rpc_clnt *)xprt; } clnt = rpc_create_client(xprt, server->hostname, &nfs_program, server->rpc_ops->version, data->pseudoflavor); if (IS_ERR(clnt)) { printk(KERN_WARNING "NFS: cannot create RPC client.\n"); goto out_fail; } clnt->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0; clnt->cl_chatty = 1; return clnt;out_fail: xprt_destroy(xprt); return clnt;}/* * The way this works is that the mount process passes a structure * in the data argument which contains the server's IP address * and the root file handle obtained from the server's mount * daemon. We stash these away in the private superblock fields. */static intnfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent){ struct nfs_server *server; rpc_authflavor_t authflavor; server = NFS_SB(sb); sb->s_blocksize_bits = 0; sb->s_blocksize = 0; if (data->bsize) sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); if (data->rsize) server->rsize = nfs_block_size(data->rsize, NULL); if (data->wsize) server->wsize = nfs_block_size(data->wsize, NULL); server->flags = data->flags & NFS_MOUNT_FLAGMASK; server->acregmin = data->acregmin*HZ; server->acregmax = data->acregmax*HZ; server->acdirmin = data->acdirmin*HZ; server->acdirmax = data->acdirmax*HZ; /* Start lockd here, before we might error out */ if (!(server->flags & NFS_MOUNT_NONLM)) lockd_up(); server->namelen = data->namlen; server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL); if (!server->hostname) return -ENOMEM; strcpy(server->hostname, data->hostname); /* Check NFS protocol revision and initialize RPC op vector * and file handle pool. */ if (server->flags & NFS_MOUNT_VER3) {#ifdef CONFIG_NFS_V3 server->rpc_ops = &nfs_v3_clientops; server->caps |= NFS_CAP_READDIRPLUS; if (data->version < 4) { printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n"); return -EIO; }#else printk(KERN_NOTICE "NFS: NFSv3 not supported.\n"); return -EIO;#endif } else { server->rpc_ops = &nfs_v2_clientops; } /* Fill in pseudoflavor for mount version < 5 */ if (!(data->flags & NFS_MOUNT_SECFLAVOUR)) data->pseudoflavor = RPC_AUTH_UNIX; authflavor = data->pseudoflavor; /* save for sb_init() */ /* XXX maybe we want to add a server->pseudoflavor field */ /* Create RPC client handles */ server->client = nfs_create_client(server, data); if (IS_ERR(server->client)) return PTR_ERR(server->client); /* RFC 2623, sec 2.3.2 */ if (authflavor != RPC_AUTH_UNIX) { server->client_sys = rpc_clone_client(server->client); if (IS_ERR(server->client_sys)) return PTR_ERR(server->client_sys); if (!rpcauth_create(RPC_AUTH_UNIX, server->client_sys)) return -ENOMEM; } else { atomic_inc(&server->client->cl_count); server->client_sys = server->client; } if (server->flags & NFS_MOUNT_VER3) { if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN) server->namelen = NFS3_MAXNAMLEN; } else { if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN) server->namelen = NFS2_MAXNAMLEN; } sb->s_op = &nfs_sops; return nfs_sb_init(sb, authflavor);}static intnfs_statfs(struct super_block *sb, struct kstatfs *buf){ struct nfs_server *server = NFS_SB(sb); unsigned char blockbits; unsigned long blockres; struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode); struct nfs_fattr fattr; struct nfs_fsstat res = { .fattr = &fattr, }; int error; lock_kernel(); error = server->rpc_ops->statfs(server, rootfh, &res); buf->f_type = NFS_SUPER_MAGIC; if (error < 0) goto out_err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -