📄 vfs.c
字号:
}intnfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl){ struct inode *inode = dentry->d_inode; int error = 0; struct posix_acl *pacl = NULL, *dpacl = NULL; unsigned int flags = 0; pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS); if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA) pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); if (IS_ERR(pacl)) { error = PTR_ERR(pacl); pacl = NULL; goto out; } if (S_ISDIR(inode->i_mode)) { dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT); if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA) dpacl = NULL; else if (IS_ERR(dpacl)) { error = PTR_ERR(dpacl); dpacl = NULL; goto out; } flags = NFS4_ACL_DIR; } *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags); if (IS_ERR(*acl)) { error = PTR_ERR(*acl); *acl = NULL; } out: posix_acl_release(pacl); posix_acl_release(dpacl); return error;}#endif /* defined(CONFIG_NFS_V4) */#ifdef CONFIG_NFSD_V3/* * Check server access rights to a file system object */struct accessmap { u32 access; int how;};static struct accessmap nfs3_regaccess[] = { { NFS3_ACCESS_READ, MAY_READ }, { NFS3_ACCESS_EXECUTE, MAY_EXEC }, { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_TRUNC }, { NFS3_ACCESS_EXTEND, MAY_WRITE }, { 0, 0 }};static struct accessmap nfs3_diraccess[] = { { NFS3_ACCESS_READ, MAY_READ }, { NFS3_ACCESS_LOOKUP, MAY_EXEC }, { NFS3_ACCESS_MODIFY, MAY_EXEC|MAY_WRITE|MAY_TRUNC }, { NFS3_ACCESS_EXTEND, MAY_EXEC|MAY_WRITE }, { NFS3_ACCESS_DELETE, MAY_REMOVE }, { 0, 0 }};static struct accessmap nfs3_anyaccess[] = { /* Some clients - Solaris 2.6 at least, make an access call * to the server to check for access for things like /dev/null * (which really, the server doesn't care about). So * We provide simple access checking for them, looking * mainly at mode bits, and we make sure to ignore read-only * filesystem checks */ { NFS3_ACCESS_READ, MAY_READ }, { NFS3_ACCESS_EXECUTE, MAY_EXEC }, { NFS3_ACCESS_MODIFY, MAY_WRITE|MAY_LOCAL_ACCESS }, { NFS3_ACCESS_EXTEND, MAY_WRITE|MAY_LOCAL_ACCESS }, { 0, 0 }};__be32nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported){ struct accessmap *map; struct svc_export *export; struct dentry *dentry; u32 query, result = 0, sresult = 0; __be32 error; error = fh_verify(rqstp, fhp, 0, MAY_NOP); if (error) goto out; export = fhp->fh_export; dentry = fhp->fh_dentry; if (S_ISREG(dentry->d_inode->i_mode)) map = nfs3_regaccess; else if (S_ISDIR(dentry->d_inode->i_mode)) map = nfs3_diraccess; else map = nfs3_anyaccess; query = *access; for (; map->access; map++) { if (map->access & query) { __be32 err2; sresult |= map->access; err2 = nfsd_permission(rqstp, export, dentry, map->how); switch (err2) { case nfs_ok: result |= map->access; break; /* the following error codes just mean the access was not allowed, * rather than an error occurred */ case nfserr_rofs: case nfserr_acces: case nfserr_perm: /* simply don't "or" in the access bit. */ break; default: error = err2; goto out; } } } *access = result; if (supported) *supported = sresult; out: return error;}#endif /* CONFIG_NFSD_V3 *//* * Open an existing file or directory. * The access argument indicates the type of open (read/write/lock) * N.B. After this call fhp needs an fh_put */__be32nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access, struct file **filp){ struct dentry *dentry; struct inode *inode; int flags = O_RDONLY|O_LARGEFILE; __be32 err; int host_err; /* * If we get here, then the client has already done an "open", * and (hopefully) checked permission - so allow OWNER_OVERRIDE * in case a chmod has now revoked permission. */ err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Disallow write access to files with the append-only bit set * or any access when mandatory locking enabled */ err = nfserr_perm; if (IS_APPEND(inode) && (access & MAY_WRITE)) goto out; /* * We must ignore files (but only files) which might have mandatory * locks on them because there is no way to know if the accesser has * the lock. */ if (S_ISREG((inode)->i_mode) && mandatory_lock(inode)) goto out; if (!inode->i_fop) goto out; /* * Check to see if there are any leases on this file. * This may block while leases are broken. */ host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0)); if (host_err == -EWOULDBLOCK) host_err = -ETIMEDOUT; if (host_err) /* NOMEM or WOULDBLOCK */ goto out_nfserr; if (access & MAY_WRITE) { if (access & MAY_READ) flags = O_RDWR|O_LARGEFILE; else flags = O_WRONLY|O_LARGEFILE; DQUOT_INIT(inode); } *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); if (IS_ERR(*filp)) host_err = PTR_ERR(*filp);out_nfserr: err = nfserrno(host_err);out: return err;}/* * Close a file. */voidnfsd_close(struct file *filp){ fput(filp);}/* * Sync a file * As this calls fsync (not fdatasync) there is no need for a write_inode * after it. */static inline int nfsd_dosync(struct file *filp, struct dentry *dp, const struct file_operations *fop){ struct inode *inode = dp->d_inode; int (*fsync) (struct file *, struct dentry *, int); int err; err = filemap_fdatawrite(inode->i_mapping); if (err == 0 && fop && (fsync = fop->fsync)) err = fsync(filp, dp, 0); if (err == 0) err = filemap_fdatawait(inode->i_mapping); return err;} static intnfsd_sync(struct file *filp){ int err; struct inode *inode = filp->f_path.dentry->d_inode; dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name); mutex_lock(&inode->i_mutex); err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op); mutex_unlock(&inode->i_mutex); return err;}intnfsd_sync_dir(struct dentry *dp){ return nfsd_dosync(NULL, dp, dp->d_inode->i_fop);}/* * Obtain the readahead parameters for the file * specified by (dev, ino). */static inline struct raparms *nfsd_get_raparms(dev_t dev, ino_t ino){ struct raparms *ra, **rap, **frap = NULL; int depth = 0; unsigned int hash; struct raparm_hbucket *rab; hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK; rab = &raparm_hash[hash]; spin_lock(&rab->pb_lock); for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) { if (ra->p_ino == ino && ra->p_dev == dev) goto found; depth++; if (ra->p_count == 0) frap = rap; } depth = nfsdstats.ra_size*11/10; if (!frap) { spin_unlock(&rab->pb_lock); return NULL; } rap = frap; ra = *frap; ra->p_dev = dev; ra->p_ino = ino; ra->p_set = 0; ra->p_hindex = hash;found: if (rap != &rab->pb_head) { *rap = ra->p_next; ra->p_next = rab->pb_head; rab->pb_head = ra; } ra->p_count++; nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++; spin_unlock(&rab->pb_lock); return ra;}/* * Grab and keep cached pages associated with a file in the svc_rqst * so that they can be passed to the network sendmsg/sendpage routines * directly. They will be released after the sending has completed. */static intnfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, struct splice_desc *sd){ struct svc_rqst *rqstp = sd->u.data; struct page **pp = rqstp->rq_respages + rqstp->rq_resused; struct page *page = buf->page; size_t size; int ret; ret = buf->ops->confirm(pipe, buf); if (unlikely(ret)) return ret; size = sd->len; if (rqstp->rq_res.page_len == 0) { get_page(page); put_page(*pp); *pp = page; rqstp->rq_resused++; rqstp->rq_res.page_base = buf->offset; rqstp->rq_res.page_len = size; } else if (page != pp[-1]) { get_page(page); if (*pp) put_page(*pp); *pp = page; rqstp->rq_resused++; rqstp->rq_res.page_len += size; } else rqstp->rq_res.page_len += size; return size;}static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, struct splice_desc *sd){ return __splice_from_pipe(pipe, sd, nfsd_splice_actor);}static inline int svc_msnfs(struct svc_fh *ffhp){#ifdef MSNFS return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);#else return 0;#endif}static __be32nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long *count){ struct inode *inode; struct raparms *ra; mm_segment_t oldfs; __be32 err; int host_err; err = nfserr_perm; inode = file->f_path.dentry->d_inode; if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) goto out; /* Get readahead parameters */ ra = nfsd_get_raparms(inode->i_sb->s_dev, inode->i_ino); if (ra && ra->p_set) file->f_ra = ra->p_ra; if (file->f_op->splice_read && rqstp->rq_splice_ok) { struct splice_desc sd = { .len = 0, .total_len = *count, .pos = offset, .u.data = rqstp, }; rqstp->rq_resused = 1; host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor); } else { oldfs = get_fs(); set_fs(KERNEL_DS); host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); } /* Write back readahead params */ if (ra) { struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex]; spin_lock(&rab->pb_lock); ra->p_ra = file->f_ra; ra->p_set = 1; ra->p_count--; spin_unlock(&rab->pb_lock); } if (host_err >= 0) { nfsdstats.io_read += host_err; *count = host_err; err = 0; fsnotify_access(file->f_path.dentry); } else err = nfserrno(host_err);out: return err;}static void kill_suid(struct dentry *dentry){ struct iattr ia; ia.ia_valid = ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; mutex_lock(&dentry->d_inode->i_mutex); notify_change(dentry, &ia); mutex_unlock(&dentry->d_inode->i_mutex);}static __be32nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, int *stablep){ struct svc_export *exp; struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; __be32 err = 0; int host_err; int stable = *stablep;#ifdef MSNFS err = nfserr_perm; if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (!lock_may_write(file->f_path.dentry->d_inode, offset, cnt))) goto out;#endif dentry = file->f_path.dentry; inode = dentry->d_inode; exp = fhp->fh_export; /* * Request sync writes if * - the sync export option has been set, or * - the client requested O_SYNC behavior (NFSv3 feature). * - The file system doesn't support fsync(). * When gathered writes have been configured for this volume, * flushing the data to disk is handled separately below. */ if (file->f_op->fsync == 0) {/* COMMIT3 cannot work */ stable = 2; *stablep = 2; /* FILE_SYNC */ } if (!EX_ISSYNC(exp)) stable = 0; if (stable && !EX_WGATHER(exp)) file->f_flags |= O_SYNC; /* Write the data. */ oldfs = get_fs(); set_fs(KERNEL_DS); host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); set_fs(oldfs); if (host_err >= 0) { nfsdstats.io_write += cnt; fsnotify_modify(file->f_path.dentry); } /* clear setuid/setgid flag after write */ if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) kill_suid(dentry); if (host_err >= 0 && stable) { static ino_t last_ino; static dev_t last_dev; /* * Gathered writes: If another process is currently * writing to the file, there's a high chance * this is another nfsd (triggered by a bulk write * from a client's biod). Rather than syncing the * file with each write request, we sleep for 10 msec. * * I don't know if this roughly approximates * C. Juszak's idea of gathered writes, but it's a * nice and simple solution (IMHO), and it seems to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -