Skip to content

Commit

Permalink
[PATCH] NFS: use atomic bitops to manipulate flags in nfsi->flags
Browse files Browse the repository at this point in the history
Introduce atomic bitops to manipulate the bits in the nfs_inode structure's
"flags" field.

Using bitops means we can use a generic wait_on_bit call instead of an ad hoc
locking scheme in fs/nfs/inode.c, so we can remove the "nfs_i_wait" field from
nfs_inode at the same time.

The other new flags field will continue to use bitmask and logic AND and OR.
This permits several flags to be set at the same time efficiently.  The
following patch adds a spin lock to protect these flags, and this spin lock
will later cover other fields in the nfs_inode structure, amortizing the cost
of using this type of serialization.

Test plan:
 Millions of fsx ops on SMP clients.

Signed-off-by: Chuck Lever <cel@netapp.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Chuck Lever authored and Linus Torvalds committed Aug 18, 2005
1 parent 5529680 commit 412d582
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 39 deletions.
4 changes: 2 additions & 2 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
/* We requested READDIRPLUS, but the server doesn't grok it */
if (error == -ENOTSUPP && desc->plus) {
NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
desc->plus = 0;
goto again;
}
Expand Down Expand Up @@ -545,7 +545,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
}
if (res == -ETOOSMALL && desc->plus) {
NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
nfs_zap_caches(inode);
desc->plus = 0;
desc->entry->eof = 0;
Expand Down
69 changes: 43 additions & 26 deletions fs/nfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_fop = &nfs_dir_operations;
if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)
&& fattr->size <= NFS_LIMIT_READDIRPLUS)
NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS;
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
else
Expand Down Expand Up @@ -849,26 +849,43 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
}
}

static int nfs_wait_schedule(void *word)
{
if (signal_pending(current))
return -ERESTARTSYS;
schedule();
return 0;
}

/*
* Wait for the inode to get unlocked.
* (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
*/
static int
nfs_wait_on_inode(struct inode *inode, int flag)
static int nfs_wait_on_inode(struct inode *inode)
{
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_inode *nfsi = NFS_I(inode);

sigset_t oldmask;
int error;
if (!(NFS_FLAGS(inode) & flag))
return 0;

atomic_inc(&inode->i_count);
error = nfs_wait_event(clnt, nfsi->nfs_i_wait,
!(NFS_FLAGS(inode) & flag));
rpc_clnt_sigmask(clnt, &oldmask);
error = wait_on_bit_lock(&nfsi->flags, NFS_INO_REVALIDATING,
nfs_wait_schedule, TASK_INTERRUPTIBLE);
rpc_clnt_sigunmask(clnt, &oldmask);
iput(inode);

return error;
}

static void nfs_wake_up_inode(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);

clear_bit(NFS_INO_REVALIDATING, &nfsi->flags);
smp_mb__after_clear_bit();
wake_up_bit(&nfsi->flags, NFS_INO_REVALIDATING);
}

int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
struct inode *inode = dentry->d_inode;
Expand Down Expand Up @@ -1029,18 +1046,19 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
if (NFS_STALE(inode))
goto out_nowait;

while (NFS_REVALIDATING(inode)) {
status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
if (status < 0)
goto out_nowait;
if (NFS_ATTRTIMEO(inode) == 0)
continue;
if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
continue;
status = NFS_STALE(inode) ? -ESTALE : 0;
goto out_nowait;
status = nfs_wait_on_inode(inode);
if (status < 0)
goto out;
if (NFS_STALE(inode)) {
status = -ESTALE;
/* Do we trust the cached ESTALE? */
if (NFS_ATTRTIMEO(inode) != 0) {
if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) {
/* no */
} else
goto out;
}
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;

/* Protect against RPC races by saving the change attribute */
verifier = nfs_save_change_attribute(inode);
Expand All @@ -1052,7 +1070,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
if (status == -ESTALE) {
nfs_zap_caches(inode);
if (!S_ISDIR(inode->i_mode))
NFS_FLAGS(inode) |= NFS_INO_STALE;
set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
}
goto out;
}
Expand Down Expand Up @@ -1083,9 +1101,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
inode->i_sb->s_id,
(long long)NFS_FILEID(inode));

out:
NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
wake_up(&nfsi->nfs_i_wait);
out:
nfs_wake_up_inode(inode);

out_nowait:
unlock_kernel();
return status;
Expand Down Expand Up @@ -1404,7 +1422,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
*/
nfs_invalidate_inode(inode);
out_err:
NFS_FLAGS(inode) |= NFS_INO_STALE;
set_bit(NFS_INO_STALE, &NFS_FLAGS(inode));
return -ESTALE;
}

Expand Down Expand Up @@ -1996,7 +2014,6 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
nfsi->ndirty = 0;
nfsi->ncommit = 0;
nfsi->npages = 0;
init_waitqueue_head(&nfsi->nfs_i_wait);
nfs4_init_once(nfsi);
}
}
Expand Down
19 changes: 8 additions & 11 deletions include/linux/nfs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ struct nfs_inode {
/*
* Various flags
*/
unsigned int flags;
unsigned long cache_validity;
unsigned long flags; /* atomic bit ops */
unsigned long cache_validity; /* bit mask */

/*
* read_cache_jiffies is when we started read-caching this inode,
Expand Down Expand Up @@ -175,8 +175,6 @@ struct nfs_inode {
/* Open contexts for shared mmap writes */
struct list_head open_files;

wait_queue_head_t nfs_i_wait;

#ifdef CONFIG_NFS_V4
struct nfs4_cached_acl *nfs4_acl;
/* NFSv4 state */
Expand All @@ -199,11 +197,11 @@ struct nfs_inode {
#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */

/*
* Legal values of flags field
* Bit offsets in flags field
*/
#define NFS_INO_REVALIDATING 0x0001 /* revalidating attrs */
#define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */
#define NFS_INO_STALE 0x0004 /* possible stale inode */
#define NFS_INO_REVALIDATING (0) /* revalidating attrs */
#define NFS_INO_ADVISE_RDPLUS (1) /* advise readdirplus */
#define NFS_INO_STALE (2) /* possible stale inode */

static inline struct nfs_inode *NFS_I(struct inode *inode)
{
Expand All @@ -229,8 +227,7 @@ static inline struct nfs_inode *NFS_I(struct inode *inode)
#define NFS_ATTRTIMEO_UPDATE(inode) (NFS_I(inode)->attrtimeo_timestamp)

#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
#define NFS_STALE(inode) (test_bit(NFS_INO_STALE, &NFS_FLAGS(inode)))

#define NFS_FILEID(inode) (NFS_I(inode)->fileid)

Expand All @@ -252,7 +249,7 @@ static inline int nfs_server_capable(struct inode *inode, int cap)

static inline int NFS_USE_READDIRPLUS(struct inode *inode)
{
return NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS;
return test_bit(NFS_INO_ADVISE_RDPLUS, &NFS_FLAGS(inode));
}

/**
Expand Down

0 comments on commit 412d582

Please sign in to comment.