📄 inode.c
字号:
rpc_shutdown_client(server->client); goto nfsv3_try_again; } if (!root_inode) goto out_no_root; sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) goto out_no_root; sb->s_root->d_op = &nfs_dentry_operations; /* Get some general file system info */ if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) { if (server->namelen == 0) server->namelen = fsinfo.namelen; } else { printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n"); goto out_no_root; } /* Work out a lot of parameters */ if (data->rsize == 0) server->rsize = nfs_block_size(fsinfo.rtpref, NULL); if (data->wsize == 0) server->wsize = nfs_block_size(fsinfo.wtpref, NULL); /* NFSv3: we don't have bsize, but rather rtmult and wtmult... */ if (!fsinfo.bsize) fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult; /* Also make sure we don't go below rsize/wsize since * RPC calls are expensive */ if (fsinfo.bsize < server->rsize) fsinfo.bsize = server->rsize; if (fsinfo.bsize < server->wsize) fsinfo.bsize = server->wsize; if (data->bsize == 0) sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits); if (server->rsize > fsinfo.rtmax) server->rsize = fsinfo.rtmax; if (server->wsize > fsinfo.wtmax) server->wsize = fsinfo.wtmax; 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; } 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; maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN; if (server->namelen == 0 || server->namelen > maxlen) server->namelen = maxlen; sb->s_maxbytes = fsinfo.maxfilesize; /* Fire up the writeback cache */ if (nfs_reqlist_alloc(server) < 0) { printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n"); goto failure_kill_reqlist; } /* We're airborne */ /* Check whether to start the lockd process */ if (!(server->flags & NFS_MOUNT_NONLM)) lockd_up(); return sb; /* Yargs. It didn't work out. */ failure_kill_reqlist: nfs_reqlist_exit(server);out_no_root: printk("nfs_read_super: get root inode failed\n"); iput(root_inode); rpciod_down(); goto out_shutdown;out_no_iod: printk(KERN_WARNING "NFS: couldn't start rpciod!\n");out_shutdown: rpc_shutdown_client(server->client); goto out_free_host;out_no_client: printk(KERN_WARNING "NFS: cannot create RPC client.\n"); xprt_destroy(xprt); goto out_free_host;out_no_xprt: printk(KERN_WARNING "NFS: cannot create RPC transport.\n");out_free_host: nfs_reqlist_free(server); kfree(server->hostname);out_unlock: goto out_fail;out_no_remote: printk("NFS: mount program didn't pass remote address!\n"); goto out_fail;out_miss_args: printk("nfs_read_super: missing data argument\n");out_fail: return NULL;}static intnfs_statfs(struct super_block *sb, struct statfs *buf){ struct nfs_server *server = &sb->u.nfs_sb.s_server; unsigned char blockbits; unsigned long blockres; struct nfs_fsinfo res; int error; error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res); buf->f_type = NFS_SUPER_MAGIC; if (error < 0) goto out_err; if (res.bsize == 0) res.bsize = sb->s_blocksize; buf->f_bsize = nfs_block_bits(res.bsize, &blockbits); blockres = (1 << blockbits) - 1; buf->f_blocks = (res.tbytes + blockres) >> blockbits; buf->f_bfree = (res.fbytes + blockres) >> blockbits; buf->f_bavail = (res.abytes + blockres) >> blockbits; buf->f_files = res.tfiles; buf->f_ffree = res.afiles; if (res.namelen == 0 || res.namelen > server->namelen) res.namelen = server->namelen; buf->f_namelen = res.namelen; return 0; out_err: printk("nfs_statfs: statfs error = %d\n", -error); buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; return 0;}static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt){ static struct proc_nfs_info { int flag; char *str; char *nostr; } nfs_info[] = { { NFS_MOUNT_SOFT, ",soft", ",hard" }, { NFS_MOUNT_INTR, ",intr", "" }, { NFS_MOUNT_POSIX, ",posix", "" }, { NFS_MOUNT_TCP, ",tcp", ",udp" }, { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" }, { 0, NULL, NULL } }; struct proc_nfs_info *nfs_infop; struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server; seq_printf(m, ",v%d", nfss->rpc_ops->version); seq_printf(m, ",rsize=%d", nfss->rsize); seq_printf(m, ",wsize=%d", nfss->wsize); if (nfss->acregmin != 3*HZ) seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ); if (nfss->acregmax != 60*HZ) seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ); if (nfss->acdirmin != 30*HZ) seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ); if (nfss->acdirmax != 60*HZ) seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ); for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) { if (nfss->flags & nfs_infop->flag) seq_puts(m, nfs_infop->str); else seq_puts(m, nfs_infop->nostr); } seq_puts(m, ",addr="); seq_escape(m, nfss->hostname, " \t\n\\"); return 0;}/* * Invalidate the local caches */voidnfs_zap_caches(struct inode *inode){ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; invalidate_inode_pages(inode); memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); NFS_CACHEINV(inode);}/* * Invalidate, but do not unhash, the inode */static voidnfs_invalidate_inode(struct inode *inode){ umode_t save_mode = inode->i_mode; make_bad_inode(inode); inode->i_mode = save_mode; nfs_zap_caches(inode);}/* * Fill in inode information from the fattr. */static voidnfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr){ /* * Check whether the mode has been set, as we only want to * do this once. (We don't allow inodes to change types.) */ if (inode->i_mode == 0) { NFS_FILEID(inode) = fattr->fileid; NFS_FSID(inode) = fattr->fsid; inode->i_mode = fattr->mode; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. */ inode->i_op = &nfs_file_inode_operations; if (S_ISREG(inode->i_mode)) { inode->i_fop = &nfs_file_operations; inode->i_data.a_ops = &nfs_file_aops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &nfs_dir_inode_operations; inode->i_fop = &nfs_dir_operations; } else if (S_ISLNK(inode->i_mode)) inode->i_op = &nfs_symlink_inode_operations; else init_special_inode(inode, inode->i_mode, fattr->rdev); memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)); } nfs_refresh_inode(inode, fattr);}struct nfs_find_desc { struct nfs_fh *fh; struct nfs_fattr *fattr;};/* * In NFSv3 we can have 64bit inode numbers. In order to support * this, and re-exported directories (also seen in NFSv2) * we are forced to allow 2 different inodes to have the same * i_ino. */static intnfs_find_actor(struct inode *inode, unsigned long ino, void *opaque){ struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; struct nfs_fh *fh = desc->fh; struct nfs_fattr *fattr = desc->fattr; if (NFS_FSID(inode) != fattr->fsid) return 0; if (NFS_FILEID(inode) != fattr->fileid) return 0; if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0) return 0; /* Force an attribute cache update if inode->i_count == 0 */ if (!atomic_read(&inode->i_count)) NFS_CACHEINV(inode); return 1;}intnfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr){ /* Empty inodes are not stale */ if (!inode->i_mode) return 0; if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) return 1; if (is_bad_inode(inode) || NFS_STALE(inode)) return 1; /* Has the filehandle changed? If so is the old one stale? */ if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 && __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE) return 1; return 0;}/* * 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. * */struct inode *nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr){ struct super_block *sb = dentry->d_sb; dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (long long)fattr->fileid); return __nfs_fhget(sb, fhandle, fattr);}/* * Look up the inode by super block and fattr->fileid. */static struct inode *__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr){ struct nfs_find_desc desc = { fh, fattr }; struct inode *inode = NULL; unsigned long ino; if ((fattr->valid & NFS_ATTR_FATTR) == 0) goto out_no_inode; if (!fattr->nlink) { printk("NFS: Buggy server - nlink == 0!\n"); goto out_no_inode; } ino = nfs_fattr_to_ino_t(fattr); if (!(inode = iget4(sb, ino, nfs_find_actor, &desc))) goto out_no_inode; nfs_fill_inode(inode, fh, fattr); dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n", inode->i_dev, (long long)NFS_FILEID(inode), atomic_read(&inode->i_count));out: return inode;out_no_inode: printk("__nfs_fhget: iget failed\n"); goto out;}intnfs_notify_change(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; int error; /* * Make sure the inode is up-to-date. */ error = nfs_revalidate(dentry); if (error) {#ifdef NFS_PARANOIAprintk("nfs_notify_change: revalidate failed, error=%d\n", error);#endif goto out; } if (!S_ISREG(inode->i_mode)) attr->ia_valid &= ~ATTR_SIZE; filemap_fdatasync(inode->i_mapping); error = nfs_wb_all(inode); filemap_fdatawait(inode->i_mapping); if (error) goto out; error = NFS_PROTO(inode)->setattr(inode, &fattr, attr); if (error) goto out; /* * If we changed the size or mtime, update the inode * now to avoid invalidating the page cache. */ if (attr->ia_valid & ATTR_SIZE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -