aboutsummaryrefslogtreecommitdiff
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c263
1 files changed, 95 insertions, 168 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e4a04d16b8b..8ec7fbd8240 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -200,9 +200,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
desc->timestamp = timestamp;
desc->timestamp_valid = 1;
SetPageUptodate(page);
- spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
- spin_unlock(&inode->i_lock);
/* Ensure consistent page alignment of the data.
* Note: assumes we have exclusive access to this mapping either
* through inode->i_mutex or some other mechanism.
@@ -214,9 +211,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
unlock_page(page);
return 0;
error:
- SetPageError(page);
unlock_page(page);
- nfs_zap_caches(inode);
desc->error = error;
return -EIO;
}
@@ -407,7 +402,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
struct file *file = desc->file;
struct nfs_entry *entry = desc->entry;
struct dentry *dentry = NULL;
- unsigned long fileid;
+ u64 fileid;
int loop_count = 0,
res;
@@ -418,7 +413,7 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
unsigned d_type = DT_UNKNOWN;
/* Note: entry->prev_cookie contains the cookie for
* retrieving the current dirent on the server */
- fileid = nfs_fileid_to_ino_t(entry->ino);
+ fileid = entry->ino;
/* Get a dentry if we have one */
if (dentry != NULL)
@@ -428,11 +423,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent,
/* Use readdirplus info */
if (dentry != NULL && dentry->d_inode != NULL) {
d_type = dt_type(dentry->d_inode);
- fileid = dentry->d_inode->i_ino;
+ fileid = NFS_FILEID(dentry->d_inode);
}
res = filldir(dirent, entry->name, entry->len,
- file->f_pos, fileid, d_type);
+ file->f_pos, nfs_compat_user_ino64(fileid),
+ d_type);
if (res < 0)
break;
file->f_pos++;
@@ -490,9 +486,6 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
page,
NFS_SERVER(inode)->dtsize,
desc->plus);
- spin_lock(&inode->i_lock);
- NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
- spin_unlock(&inode->i_lock);
desc->page = page;
desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
if (desc->error >= 0) {
@@ -558,7 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
memset(desc, 0, sizeof(*desc));
desc->file = filp;
- desc->dir_cookie = &((struct nfs_open_context *)filp->private_data)->dir_cookie;
+ desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie;
desc->decode = NFS_PROTO(inode)->decode_dirent;
desc->plus = NFS_USE_READDIRPLUS(inode);
@@ -623,7 +616,7 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int origin)
}
if (offset != filp->f_pos) {
filp->f_pos = offset;
- ((struct nfs_open_context *)filp->private_data)->dir_cookie = 0;
+ nfs_file_open_context(filp)->dir_cookie = 0;
}
out:
mutex_unlock(&filp->f_path.dentry->d_inode->i_mutex);
@@ -650,36 +643,18 @@ static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync)
*/
static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
{
- unsigned long verf;
-
if (IS_ROOT(dentry))
return 1;
- verf = dentry->d_time;
- if (nfs_caches_unstable(dir)
- || verf != NFS_I(dir)->cache_change_attribute)
+ if (!nfs_verify_change_attribute(dir, dentry->d_time))
+ return 0;
+ /* Revalidate nfsi->cache_change_attribute before we declare a match */
+ if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
+ return 0;
+ if (!nfs_verify_change_attribute(dir, dentry->d_time))
return 0;
return 1;
}
-static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
-{
- dentry->d_time = verf;
-}
-
-static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
-{
- nfs_set_verifier(dentry, verf);
-}
-
-/*
- * Whenever an NFS operation succeeds, we know that the dentry
- * is valid, so we update the revalidation timestamp.
- */
-static inline void nfs_renew_times(struct dentry * dentry)
-{
- dentry->d_time = jiffies;
-}
-
/*
* Return the intent data that applies to this particular path component
*
@@ -695,6 +670,19 @@ static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigne
}
/*
+ * Use intent information to check whether or not we're going to do
+ * an O_EXCL create using this path component.
+ */
+static int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
+{
+ if (NFS_PROTO(dir)->version == 2)
+ return 0;
+ if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
+ return 0;
+ return (nd->intent.open.flags & O_EXCL) != 0;
+}
+
+/*
* Inode and filehandle revalidation for lookups.
*
* We force revalidation in the cases where the VFS sets LOOKUP_REVAL,
@@ -717,6 +705,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
(S_ISREG(inode->i_mode) ||
S_ISDIR(inode->i_mode)))
goto out_force;
+ return 0;
}
return nfs_revalidate_inode(server, inode);
out_force:
@@ -759,7 +748,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
- unsigned long verifier;
parent = dget_parent(dentry);
lock_kernel();
@@ -767,10 +755,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = dentry->d_inode;
- /* Revalidate parent directory attribute cache */
- if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0)
- goto out_zap_parent;
-
if (!inode) {
if (nfs_neg_need_reval(dir, dentry, nd))
goto out_bad;
@@ -785,7 +769,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
}
/* Force a full look up iff the parent directory has changed */
- if (nfs_check_verifier(dir, dentry)) {
+ if (!nfs_is_exclusive_create(dir, nd) && nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode, nd))
goto out_zap_parent;
goto out_valid;
@@ -794,7 +778,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if (NFS_STALE(inode))
goto out_bad;
- verifier = nfs_save_change_attribute(dir);
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -803,8 +786,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
goto out_bad;
- nfs_renew_times(dentry);
- nfs_refresh_verifier(dentry, verifier);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
unlock_kernel();
dput(parent);
@@ -815,7 +797,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
out_zap_parent:
nfs_zap_caches(dir);
out_bad:
- NFS_CACHEINV(dir);
+ nfs_mark_for_revalidate(dir);
if (inode && S_ISDIR(inode->i_mode)) {
/* Purge readdir caches. */
nfs_zap_caches(inode);
@@ -872,8 +854,6 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
nfs_complete_unlink(dentry, inode);
unlock_kernel();
}
- /* When creating a negative dentry, we want to renew d_time */
- nfs_renew_times(dentry);
iput(inode);
}
@@ -883,30 +863,6 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
-/*
- * Use intent information to check whether or not we're going to do
- * an O_EXCL create using this path component.
- */
-static inline
-int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
-{
- if (NFS_PROTO(dir)->version == 2)
- return 0;
- if (nd == NULL || nfs_lookup_check_intent(nd, LOOKUP_CREATE) == 0)
- return 0;
- return (nd->intent.open.flags & O_EXCL) != 0;
-}
-
-static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
-{
- struct nfs_server *server = NFS_SERVER(dir);
-
- if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
- /* Revalidate fsid using the parent directory */
- return __nfs_revalidate_inode(server, dir);
- return 0;
-}
-
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *res;
@@ -945,11 +901,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error);
goto out_unlock;
}
- error = nfs_reval_fsid(dir, &fattr);
- if (error < 0) {
- res = ERR_PTR(error);
- goto out_unlock;
- }
inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr);
res = (struct dentry *)inode;
if (IS_ERR(res))
@@ -958,17 +909,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
no_entry:
res = d_materialise_unique(dentry, inode);
if (res != NULL) {
- struct dentry *parent;
if (IS_ERR(res))
goto out_unlock;
- /* Was a directory renamed! */
- parent = dget_parent(res);
- if (!IS_ROOT(parent))
- nfs_mark_for_revalidate(parent->d_inode);
- dput(parent);
dentry = res;
}
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unlock:
unlock_kernel();
@@ -1020,28 +964,16 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
}
dentry->d_op = NFS_PROTO(dir)->dentry_ops;
- /* Let vfs_create() deal with O_EXCL */
+ /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash
+ * the dentry. */
if (nd->intent.open.flags & O_EXCL) {
- d_add(dentry, NULL);
+ d_instantiate(dentry, NULL);
goto out;
}
/* Open the file on the server */
lock_kernel();
- /* Revalidate parent directory attribute cache */
- error = nfs_revalidate_inode(NFS_SERVER(dir), dir);
- if (error < 0) {
- res = ERR_PTR(error);
- unlock_kernel();
- goto out;
- }
-
- if (nd->intent.open.flags & O_CREAT) {
- nfs_begin_data_update(dir);
- res = nfs4_atomic_open(dir, dentry, nd);
- nfs_end_data_update(dir);
- } else
- res = nfs4_atomic_open(dir, dentry, nd);
+ res = nfs4_atomic_open(dir, dentry, nd);
unlock_kernel();
if (IS_ERR(res)) {
error = PTR_ERR(res);
@@ -1063,8 +995,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
}
} else if (res != NULL)
dentry = res;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out:
return res;
no_open:
@@ -1076,7 +1006,6 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct dentry *parent = NULL;
struct inode *inode = dentry->d_inode;
struct inode *dir;
- unsigned long verifier;
int openflags, ret = 0;
parent = dget_parent(dentry);
@@ -1086,8 +1015,12 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
- if (inode == NULL)
+ if (inode == NULL) {
+ if (!nfs_neg_need_reval(dir, dentry, nd))
+ ret = 1;
goto out;
+ }
+
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
goto no_open;
@@ -1104,10 +1037,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
* change attribute *before* we do the RPC call.
*/
lock_kernel();
- verifier = nfs_save_change_attribute(dir);
ret = nfs4_open_revalidate(dir, dentry, openflags, nd);
- if (!ret)
- nfs_refresh_verifier(dentry, verifier);
unlock_kernel();
out:
dput(parent);
@@ -1133,6 +1063,7 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
.len = entry->len,
};
struct inode *inode;
+ unsigned long verf = nfs_save_change_attribute(dir);
switch (name.len) {
case 2:
@@ -1143,6 +1074,14 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
if (name.name[0] == '.')
return dget(parent);
}
+
+ spin_lock(&dir->i_lock);
+ if (NFS_I(dir)->cache_validity & NFS_INO_INVALID_DATA) {
+ spin_unlock(&dir->i_lock);
+ return NULL;
+ }
+ spin_unlock(&dir->i_lock);
+
name.hash = full_name_hash(name.name, name.len);
dentry = d_lookup(parent, &name);
if (dentry != NULL) {
@@ -1183,12 +1122,8 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
dentry = alias;
}
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- return dentry;
out_renew:
- nfs_renew_times(dentry);
- nfs_refresh_verifier(dentry, nfs_save_change_attribute(dir));
+ nfs_set_verifier(dentry, verf);
return dentry;
}
@@ -1198,32 +1133,40 @@ out_renew:
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
+ struct dentry *parent = dget_parent(dentry);
+ struct inode *dir = parent->d_inode;
struct inode *inode;
int error = -EACCES;
+ d_drop(dentry);
+
/* We may have been initialized further down */
if (dentry->d_inode)
- return 0;
+ goto out;
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)
- return error;
+ goto out_error;
}
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (!(fattr->valid & NFS_ATTR_FATTR)) {
struct nfs_server *server = NFS_SB(dentry->d_sb);
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
if (error < 0)
- return error;
+ goto out_error;
}
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
error = PTR_ERR(inode);
if (IS_ERR(inode))
- return error;
- d_instantiate(dentry, inode);
- if (d_unhashed(dentry))
- d_rehash(dentry);
+ goto out_error;
+ d_add(dentry, inode);
+out:
+ dput(parent);
return 0;
+out_error:
+ nfs_mark_for_revalidate(dir);
+ dput(parent);
+ return error;
}
/*
@@ -1249,13 +1192,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
open_flags = nd->intent.open.flags;
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
- nfs_end_data_update(dir);
if (error != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1283,13 +1222,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
attr.ia_valid = ATTR_MODE;
lock_kernel();
- nfs_begin_data_update(dir);
status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
- nfs_end_data_update(dir);
if (status != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1313,13 +1248,9 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
attr.ia_mode = mode | S_IFDIR;
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
- nfs_end_data_update(dir);
if (error != 0)
goto out_err;
- nfs_renew_times(dentry);
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
unlock_kernel();
return 0;
out_err:
@@ -1336,12 +1267,10 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
lock_kernel();
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL)
clear_nlink(dentry->d_inode);
- nfs_end_data_update(dir);
unlock_kernel();
return error;
@@ -1350,9 +1279,9 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
{
static unsigned int sillycounter;
- const int i_inosize = sizeof(dir->i_ino)*2;
+ const int fileidsize = sizeof(NFS_FILEID(dentry->d_inode))*2;
const int countersize = sizeof(sillycounter)*2;
- const int slen = sizeof(".nfs") + i_inosize + countersize - 1;
+ const int slen = sizeof(".nfs")+fileidsize+countersize-1;
char silly[slen+1];
struct qstr qsilly;
struct dentry *sdentry;
@@ -1370,8 +1299,9 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto out;
- sprintf(silly, ".nfs%*.*lx",
- i_inosize, i_inosize, dentry->d_inode->i_ino);
+ sprintf(silly, ".nfs%*.*Lx",
+ fileidsize, fileidsize,
+ (unsigned long long)NFS_FILEID(dentry->d_inode));
/* Return delegation in anticipation of the rename */
nfs_inode_return_delegation(dentry->d_inode);
@@ -1398,19 +1328,14 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
qsilly.name = silly;
qsilly.len = strlen(silly);
- nfs_begin_data_update(dir);
if (dentry->d_inode) {
- nfs_begin_data_update(dentry->d_inode);
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
nfs_mark_for_revalidate(dentry->d_inode);
- nfs_end_data_update(dentry->d_inode);
} else
error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
dir, &qsilly);
- nfs_end_data_update(dir);
if (!error) {
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry);
error = nfs_async_unlink(dir, dentry);
@@ -1443,19 +1368,15 @@ static int nfs_safe_remove(struct dentry *dentry)
goto out;
}
- nfs_begin_data_update(dir);
if (inode != NULL) {
nfs_inode_return_delegation(inode);
- nfs_begin_data_update(inode);
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
/* The VFS may want to delete this inode */
if (error == 0)
drop_nlink(inode);
nfs_mark_for_revalidate(inode);
- nfs_end_data_update(inode);
} else
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
- nfs_end_data_update(dir);
out:
return error;
}
@@ -1493,7 +1414,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
spin_unlock(&dcache_lock);
error = nfs_safe_remove(dentry);
if (!error) {
- nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
} else if (need_rehash)
d_rehash(dentry);
@@ -1548,9 +1468,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
kunmap_atomic(kaddr, KM_USER0);
- nfs_begin_data_update(dir);
error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
- nfs_end_data_update(dir);
if (error != 0) {
dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
dir->i_sb->s_id, dir->i_ino,
@@ -1590,15 +1508,12 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
dentry->d_parent->d_name.name, dentry->d_name.name);
lock_kernel();
- nfs_begin_data_update(dir);
- nfs_begin_data_update(inode);
+ d_drop(dentry);
error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
if (error == 0) {
atomic_inc(&inode->i_count);
- d_instantiate(dentry, inode);
+ d_add(dentry, inode);
}
- nfs_end_data_update(inode);
- nfs_end_data_update(dir);
unlock_kernel();
return error;
}
@@ -1701,22 +1616,16 @@ go_ahead:
d_delete(new_dentry);
}
- nfs_begin_data_update(old_dir);
- nfs_begin_data_update(new_dir);
- nfs_begin_data_update(old_inode);
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
new_dir, &new_dentry->d_name);
nfs_mark_for_revalidate(old_inode);
- nfs_end_data_update(old_inode);
- nfs_end_data_update(new_dir);
- nfs_end_data_update(old_dir);
out:
if (rehash)
d_rehash(rehash);
if (!error) {
d_move(old_dentry, new_dentry);
- nfs_renew_times(new_dentry);
- nfs_refresh_verifier(new_dentry, nfs_save_change_attribute(new_dir));
+ nfs_set_verifier(new_dentry,
+ nfs_save_change_attribute(new_dir));
}
/* new dentry created? */
@@ -1842,7 +1751,7 @@ static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, st
return NULL;
}
-int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
+static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_access_entry *cache;
@@ -1854,7 +1763,7 @@ int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs
cache = nfs_access_search_rbtree(inode, cred);
if (cache == NULL)
goto out;
- if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)))
+ if (!time_in_range(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo))
goto out_stale;
res->jiffies = cache->jiffies;
res->cred = cache->cred;
@@ -1909,7 +1818,7 @@ found:
nfs_access_free_entry(entry);
}
-void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
+static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
{
struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
if (cache == NULL)
@@ -1957,6 +1866,24 @@ out:
return -EACCES;
}
+static int nfs_open_permission_mask(int openflags)
+{
+ int mask = 0;
+
+ if (openflags & FMODE_READ)
+ mask |= MAY_READ;
+ if (openflags & FMODE_WRITE)
+ mask |= MAY_WRITE;
+ if (openflags & FMODE_EXEC)
+ mask |= MAY_EXEC;
+ return mask;
+}
+
+int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags)
+{
+ return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags));
+}
+
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct rpc_cred *cred;