X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfs%2Fdir.c;h=626252aec95a3c2733eb73319c8314e8ba1a2b07;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=b3a950c20eab6d060d8096e5ab58f36f26f5b520;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b3a950c20..626252aec 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -32,6 +32,8 @@ #include #include +#include "delegation.h" + #define NFS_PARANOIA 1 /* #define NFS_DEBUG_VERBOSE 1 */ @@ -49,12 +51,14 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *); +static int nfs_fsync_dir(struct file *, struct dentry *, int); struct file_operations nfs_dir_operations = { .read = generic_read_dir, .readdir = nfs_readdir, .open = nfs_opendir, .release = nfs_release, + .fsync = nfs_fsync_dir, }; struct inode_operations nfs_dir_inode_operations = { @@ -490,6 +494,15 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) return 0; } +/* + * All directory operations under NFS are synchronous, so fsync() + * is a dummy operation. + */ +int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) +{ + return 0; +} + /* * A check for whether or not the parent directory has changed. * In the case it has, we assume that the dentries are untrustworthy @@ -610,7 +623,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) verifier = nfs_save_change_attribute(dir); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); if (!error) { - if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) + if (nfs_compare_fh(NFS_FH(inode), &fhandle)) goto out_bad; if (nfs_lookup_verify_inode(inode, isopen)) goto out_zap_parent; @@ -623,7 +636,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); if (error) goto out_bad; - if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) + if (nfs_compare_fh(NFS_FH(inode), &fhandle)) goto out_bad; if ((error = nfs_refresh_inode(inode, &fattr)) != 0) goto out_bad; @@ -850,22 +863,22 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) unsigned long verifier; int openflags, ret = 0; - /* NFS only supports OPEN for regular files */ - if (inode && !S_ISREG(inode->i_mode)) - goto no_open; parent = dget_parent(dentry); dir = parent->d_inode; if (!is_atomic_open(dir, nd)) goto no_open; + /* We can't create new files in nfs_open_revalidate(), so we + * optimize away revalidation of negative dentries. + */ + if (inode == NULL) + goto out; + /* NFS only supports OPEN on regular files */ + if (!S_ISREG(inode->i_mode)) + goto no_open; openflags = nd->intent.open.flags; - if (openflags & O_CREAT) { - /* If this is a negative dentry, just drop it */ - if (!inode) - goto out; - /* If this is exclusive open, just revalidate */ - if (openflags & O_EXCL) - goto no_open; - } + /* We cannot do exclusive creation on a positive dentry */ + if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) + goto no_open; /* We can't create new files, or truncate existing ones here */ openflags &= ~(O_CREAT|O_TRUNC); @@ -887,6 +900,8 @@ out: return ret; no_open: dput(parent); + if (inode != NULL && nfs_have_delegation(inode, FMODE_READ)) + return 1; return nfs_lookup_revalidate(dentry, nd); } #endif /* CONFIG_NFSV4 */ @@ -982,12 +997,18 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, /* We may have been initialized further down */ if (dentry->d_inode) return 0; - if (fhandle->size == 0 || !(fattr->valid & NFS_ATTR_FATTR)) { + if (fhandle->size == 0) { struct inode *dir = dentry->d_parent->d_inode; error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); if (error) goto out_err; } + if (!(fattr->valid & NFS_ATTR_FATTR)) { + struct nfs_server *server = NFS_SB(dentry->d_sb); + error = server->rpc_ops->getattr(server, fhandle, fattr); + if (error < 0) + goto out_err; + } inode = nfs_fhget(dentry->d_sb, fhandle, fattr); if (inode) { d_instantiate(dentry, inode); @@ -1015,7 +1036,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, int error; int open_flags = 0; - dfprintk(VFS, "NFS: create(%s/%ld, %s)\n", dir->i_sb->s_id, + dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); attr.ia_mode = mode; @@ -1032,12 +1053,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, */ lock_kernel(); nfs_begin_data_update(dir); - dfprintk(VFS, "NFS: attr %d.%d #%d\n", attr.ia_uid, attr.ia_gid, attr.ia_xid); inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags); nfs_end_data_update(dir); if (!IS_ERR(inode)) { - dfprintk(VFS, "NFS: inode=%p %d.%d #%d\n", inode, - inode->i_uid, inode->i_gid, inode->i_xid); d_instantiate(dentry, inode); nfs_renew_times(dentry); nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); @@ -1302,19 +1320,6 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name, symname); - error = -ENAMETOOLONG; - switch (NFS_PROTO(dir)->version) { - case 2: - if (strlen(symname) > NFS2_MAXPATHLEN) - goto out; - break; - case 3: - if (strlen(symname) > NFS3_MAXPATHLEN) - goto out; - default: - break; - } - #ifdef NFS_PARANOIA if (dentry->d_inode) printk("nfs_proc_symlink: %s/%s not negative!\n", @@ -1344,8 +1349,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); d_drop(dentry); } unlock_kernel(); - -out: return error; } @@ -1501,10 +1504,56 @@ out: return error; } -int -nfs_permission(struct inode *inode, int mask, struct nameidata *nd) +int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) +{ + struct nfs_access_entry *cache = &NFS_I(inode)->cache_access; + + if (cache->cred != cred + || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) + || (NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) + return -ENOENT; + memcpy(res, cache, sizeof(*res)); + return 0; +} + +void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) +{ + struct nfs_access_entry *cache = &NFS_I(inode)->cache_access; + + if (cache->cred != set->cred) { + if (cache->cred) + put_rpccred(cache->cred); + cache->cred = get_rpccred(set->cred); + } + cache->jiffies = set->jiffies; + cache->mask = set->mask; +} + +static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) +{ + struct nfs_access_entry cache; + int status; + + status = nfs_access_get_cached(inode, cred, &cache); + if (status == 0) + goto out; + + /* Be clever: ask server to check for all possible rights */ + cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; + cache.cred = cred; + cache.jiffies = jiffies; + status = NFS_PROTO(inode)->access(inode, &cache); + if (status != 0) + return status; + nfs_access_add_cache(inode, &cache); +out: + if ((cache.mask & mask) == mask) + return 0; + return -EACCES; +} + +int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) { - struct nfs_access_cache *cache = &NFS_I(inode)->cache_access; struct rpc_cred *cred; int mode = inode->i_mode; int res; @@ -1545,24 +1594,7 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd) goto out_notsup; cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); - if (cache->cred == cred - && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) - && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) { - if (!(res = cache->err)) { - /* Is the mask a subset of an accepted mask? */ - if ((cache->mask & mask) == mask) - goto out; - } else { - /* ...or is it a superset of a rejected mask? */ - if ((cache->mask & mask) == cache->mask) - goto out; - } - } - - res = NFS_PROTO(inode)->access(inode, cred, mask); - if (!res || res == -EACCES) - goto add_cache; -out: + res = nfs_do_access(inode, cred, mask); put_rpccred(cred); unlock_kernel(); return res; @@ -1571,15 +1603,6 @@ out_notsup: res = vfs_permission(inode, mask); unlock_kernel(); return res; -add_cache: - cache->jiffies = jiffies; - if (cache->cred) - put_rpccred(cache->cred); - cache->cred = cred; - cache->mask = mask; - cache->err = res; - unlock_kernel(); - return res; } /*