vfs.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,815 行 · 第 1/3 页
C
1,815 行
*/ v_mtime = verifier[0]&0x7fffffff; v_atime = verifier[1]&0x7fffffff; v_mode = S_IFREG | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */ | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */ ; } if (dchild->d_inode) { err = 0; switch (createmode) { case NFS3_CREATE_UNCHECKED: if (! S_ISREG(dchild->d_inode->i_mode)) err = nfserr_exist; else if (truncp) { /* in nfsv4, we need to treat this case a little * differently. we don't want to truncate the * file now; this would be wrong if the OPEN * fails for some other reason. furthermore, * if the size is nonzero, we should ignore it * according to spec! */ *truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size; } else { iap->ia_valid &= ATTR_SIZE; goto set_attr; } break; case NFS3_CREATE_EXCLUSIVE: if ( dchild->d_inode->i_mtime.tv_sec == v_mtime && dchild->d_inode->i_atime.tv_sec == v_atime && dchild->d_inode->i_mode == v_mode && dchild->d_inode->i_size == 0 ) break; /* fallthru */ case NFS3_CREATE_GUARDED: err = nfserr_exist; } goto out; } err = vfs_create(dirp, dchild, iap->ia_mode, NULL); if (err < 0) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) { nfsd_sync_dir(dentry); /* setattr will sync the child (or not) */ } /* * Update the filehandle to get the new inode info. */ err = fh_update(resfhp); if (err) goto out; if (createmode == NFS3_CREATE_EXCLUSIVE) { /* Cram the verifier into atime/mtime/mode */ iap->ia_valid = ATTR_MTIME|ATTR_ATIME | ATTR_MTIME_SET|ATTR_ATIME_SET | ATTR_MODE; /* XXX someone who knows this better please fix it for nsec */ iap->ia_mtime.tv_sec = v_mtime; iap->ia_atime.tv_sec = v_atime; iap->ia_mtime.tv_nsec = 0; iap->ia_atime.tv_nsec = 0; iap->ia_mode = v_mode; } /* Set file attributes. * Mode has already been set but we might need to reset it * for CREATE_EXCLUSIVE * Irix appears to send along the gid when it tries to * implement setgid directories via NFS. Clear out all that cruft. */ set_attr: if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); out: fh_unlock(fhp); if (dchild && !IS_ERR(dchild)) dput(dchild); return err; out_nfserr: err = nfserrno(err); goto out;}#endif /* CONFIG_NFSD_V3 *//* * Read a symlink. On entry, *lenp must contain the maximum path length that * fits into the buffer. On return, it contains the true length. * N.B. After this call fhp needs an fh_put */intnfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp){ struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; int err; err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP); if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; err = nfserr_inval; if (!inode->i_op || !inode->i_op->readlink) goto out; touch_atime(fhp->fh_export->ex_mnt, dentry); /* N.B. Why does this call need a get_fs()?? * Remove the set_fs and watch the fireworks:-) --okir */ oldfs = get_fs(); set_fs(KERNEL_DS); err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); if (err < 0) goto out_nfserr; *lenp = err; err = 0;out: return err;out_nfserr: err = nfserrno(err); goto out;}/* * Create a symlink and look up its inode * N.B. After this call _both_ fhp and resfhp need an fh_put */intnfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, char *path, int plen, struct svc_fh *resfhp, struct iattr *iap){ struct dentry *dentry, *dnew; int err, cerr; umode_t mode; err = nfserr_noent; if (!flen || !plen) goto out; err = nfserr_exist; if (isdotent(fname, flen)) goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) goto out; fh_lock(fhp); dentry = fhp->fh_dentry; dnew = lookup_one_len(fname, dentry, flen); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; mode = S_IALLUGO; /* Only the MODE ATTRibute is even vaguely meaningful */ if (iap && (iap->ia_valid & ATTR_MODE)) mode = iap->ia_mode & S_IALLUGO; if (unlikely(path[plen] != 0)) { char *path_alloced = kmalloc(plen+1, GFP_KERNEL); if (path_alloced == NULL) err = -ENOMEM; else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); kfree(path_alloced); } } else err = vfs_symlink(dentry->d_inode, dnew, path, mode); if (!err) { if (EX_ISSYNC(fhp->fh_export)) nfsd_sync_dir(dentry); } else err = nfserrno(err); fh_unlock(fhp); cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); dput(dnew); if (err==0) err = cerr;out: return err;out_nfserr: err = nfserrno(err); goto out;}/* * Create a hardlink * N.B. After this call _both_ ffhp and tfhp need an fh_put */intnfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *name, int len, struct svc_fh *tfhp){ struct dentry *ddir, *dnew, *dold; struct inode *dirp, *dest; int err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); if (err) goto out; err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP); if (err) goto out; err = nfserr_perm; if (!len) goto out; err = nfserr_exist; if (isdotent(name, len)) goto out; fh_lock(ffhp); ddir = ffhp->fh_dentry; dirp = ddir->d_inode; dnew = lookup_one_len(name, ddir, len); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; dold = tfhp->fh_dentry; dest = dold->d_inode; err = vfs_link(dold, dirp, dnew); if (!err) { if (EX_ISSYNC(ffhp->fh_export)) { nfsd_sync_dir(ddir); write_inode_now(dest, 1); } } else { if (err == -EXDEV && rqstp->rq_vers == 2) err = nfserr_acces; else err = nfserrno(err); } fh_unlock(ffhp); dput(dnew);out: return err;out_nfserr: err = nfserrno(err); goto out;}/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */intnfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct svc_fh *tfhp, char *tname, int tlen){ struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap; struct inode *fdir, *tdir; int err; err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); if (err) goto out; err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); if (err) goto out; fdentry = ffhp->fh_dentry; fdir = fdentry->d_inode; tdentry = tfhp->fh_dentry; tdir = tdentry->d_inode; err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev; if (fdir->i_sb != tdir->i_sb) goto out; err = nfserr_perm; if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) goto out; /* cannot use fh_lock as we need deadlock protective ordering * so do it by hand */ trap = lock_rename(tdentry, fdentry); ffhp->fh_locked = tfhp->fh_locked = 1; fill_pre_wcc(ffhp); fill_pre_wcc(tfhp); odentry = lookup_one_len(fname, fdentry, flen); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; err = -ENOENT; if (!odentry->d_inode) goto out_dput_old; err = -EINVAL; if (odentry == trap) goto out_dput_old; ndentry = lookup_one_len(tname, tdentry, tlen); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; err = -ENOTEMPTY; if (ndentry == trap) goto out_dput_new;#ifdef MSNFS if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && ((atomic_read(&odentry->d_count) > 1) || (atomic_read(&ndentry->d_count) > 1))) { err = nfserr_perm; } else#endif err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { nfsd_sync_dir(tdentry); nfsd_sync_dir(fdentry); } out_dput_new: dput(ndentry); out_dput_old: dput(odentry); out_nfserr: if (err) err = nfserrno(err); /* we cannot reply on fh_unlock on the two filehandles, * as that would do the wrong thing if the two directories * were the same, so again we do it by hand */ fill_post_wcc(ffhp); fill_post_wcc(tfhp); unlock_rename(tdentry, fdentry); ffhp->fh_locked = tfhp->fh_locked = 0;out: return err;}/* * Unlink a file or directory * N.B. After this call fhp needs an fh_put */intnfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, char *fname, int flen){ struct dentry *dentry, *rdentry; struct inode *dirp; int err; err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); if (err) goto out; fh_lock(fhp); dentry = fhp->fh_dentry; dirp = dentry->d_inode; rdentry = lookup_one_len(fname, dentry, flen); err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; if (!rdentry->d_inode) { dput(rdentry); err = nfserr_noent; goto out; } if (!type) type = rdentry->d_inode->i_mode & S_IFMT; if (type != S_IFDIR) { /* It's UNLINK */#ifdef MSNFS if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && (atomic_read(&rdentry->d_count) > 1)) { err = nfserr_perm; } else#endif err = vfs_unlink(dirp, rdentry); } else { /* It's RMDIR */ err = vfs_rmdir(dirp, rdentry); } dput(rdentry); if (err) goto out_nfserr; if (EX_ISSYNC(fhp->fh_export)) nfsd_sync_dir(dentry);out: return err;out_nfserr: err = nfserrno(err); goto out;}/* * Read entries from a directory. * The NFSv3/4 verifier we ignore for now. */intnfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, struct readdir_cd *cdp, encode_dent_fn func){ int err; struct file *file; loff_t offset = *offsetp; err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file); if (err) goto out; offset = vfs_llseek(file, offset, 0); if (offset < 0) { err = nfserrno((int)offset); goto out_close; } /* * Read the directory entries. This silly loop is necessary because * readdir() is not guaranteed to fill up the entire buffer, but * may choose to do less. */ do { cdp->err = nfserr_eof; /* will be cleared on successful read */ err = vfs_readdir(file, (filldir_t) func, cdp); } while (err >=0 && cdp->err == nfs_ok); if (err) err = nfserrno(err); else err = cdp->err; *offsetp = vfs_llseek(file, 0, 1); if (err == nfserr_eof || err == nfserr_toosmall) err = nfs_ok; /* can still be found in ->err */out_close: nfsd_close(file);out: return err;}/* * Get file system stats * N.B. After this call fhp needs an fh_put */intnfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat){ int err = fh_verify(rqstp, fhp, 0, MAY_NOP); if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat)) err = nfserr_io; return err;}/* * Check for a user's access permissions to this inode. */intnfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc){ struct inode *inode = dentry->d_inode; int err; if (acc == MAY_NOP) return 0;#if 0 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", acc, (acc & MAY_READ)? " read" : "", (acc & MAY_WRITE)? " write" : "", (acc & MAY_EXEC)? " exec" : "", (acc & MAY_SATTR)? " sattr" : "", (acc & MAY_TRUNC)? " trunc" : "", (acc & MAY_LOCK)? " lock" : "", (acc & MAY_OWNER_OVERRIDE)? " owneroverride" : "", inode->i_mode, IS_IMMUTABLE(inode)? " immut" : "", IS_APPEND(inode)? " append" : "", IS_RDONLY(inode)? " ro" : ""); dprintk(" owner %d/%d user %d/%d\n", inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);#endif /* Normally we reject any write/sattr etc access on a read-only file * system. But if it is IRIX doing check on write-access for a * device special file, we ignore rofs. */ if (!(acc & MAY_LOCAL_ACCESS)) if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { if (EX_RDONLY(exp) || IS_RDONLY(inode)) return nfserr_rofs; if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) return nfserr_perm; } if ((acc & MAY_TRUNC) && IS_APPEND(inode)) return nfserr_perm; if (acc & MAY_LOCK) { /* If we cannot rely on authentication in NLM requests, * just allow locks, otherwise require read permission, or * ownership */ if (exp->ex_flags & NFSEXP_NOAUTHNLM) return 0; else acc = MAY_READ | MAY_OWNER_OVERRIDE; } /* * The file owner always gets access permission for accesses that * would normally be checked at open time. This is to make * file access work even when the client has done a fchmod(fd, 0). * * However, `cp foo bar' should fail nevertheless when bar is * readonly. A sensible way to do this might be to reject all * attempts to truncate a read-only file, because a creat() call * always implies file truncation. * ... but this isn't really fair. A process may reasonably call * ftruncate on an open file descriptor on a file with perm 000. * We must trust the client to do permission checking - using "ACCESS" * with NFSv3. */ if ((acc & MAY_OWNER_OVERRIDE) && inode->i_uid == current->fsuid) return 0; err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL); /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && acc == (MAY_READ | MAY_OWNER_OVERRIDE)) err = permission(inode, MAY_EXEC, NULL); return err? nfserrno(err) : 0;}voidnfsd_racache_shutdown(void){ if (!raparm_cache) return; dprintk("nfsd: freeing readahead buffers.\n"); kfree(raparml); raparm_cache = raparml = NULL;}/* * Initialize readahead param cache */intnfsd_racache_init(int cache_size){ int i; if (raparm_cache) return 0; raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL); if (raparml != NULL) { dprintk("nfsd: allocating %d readahead buffers.\n", cache_size); memset(raparml, 0, sizeof(struct raparms) * cache_size); for (i = 0; i < cache_size - 1; i++) { raparml[i].p_next = raparml + i + 1; } raparm_cache = raparml; } else { printk(KERN_WARNING "nfsd: Could not allocate memory read-ahead cache.\n"); return -ENOMEM; } nfsdstats.ra_size = cache_size; return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?