Commit 1466b77a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-3.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull second set of NFS client updates from Trond Myklebust:
 "This mainly contains some small readdir optimisations that had
  dependencies on Al Viro's readdir rewrite.  There is also a fix for a
  nasty deadlock which surfaced earlier in this merge window.

  Highlights include:
   - Fix an_rpc pipefs regression that causes a deadlock on mount
   - Readdir optimisations by Scott Mayhew and Jeff Layton
   - clean up the rpc_pipefs dentry operation setup"

* tag 'nfs-for-3.11-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  SUNRPC: Fix a deadlock in rpc_client_register()
  rpc_pipe: rpc_dir_inode_operations can be static
  NFS: Allow nfs_updatepage to extend a write under additional circumstances
  NFS: Make nfs_readdir revalidate less often
  NFS: Make nfs_attribute_cache_expired() non-static
  rpc_pipe: set dentry operations at d_alloc time
  nfs: set verifier on existing dentries in nfs_prime_dcache
parents 19d2f8e0 eeee2452
...@@ -450,6 +450,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) ...@@ -450,6 +450,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
dentry = d_lookup(parent, &filename); dentry = d_lookup(parent, &filename);
if (dentry != NULL) { if (dentry != NULL) {
if (nfs_same_file(dentry, entry)) { if (nfs_same_file(dentry, entry)) {
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
status = nfs_refresh_inode(dentry->d_inode, entry->fattr); status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
if (!status) if (!status)
nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label); nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label);
...@@ -817,7 +818,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -817,7 +818,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
nfs_readdir_descriptor_t my_desc, nfs_readdir_descriptor_t my_desc,
*desc = &my_desc; *desc = &my_desc;
struct nfs_open_dir_context *dir_ctx = file->private_data; struct nfs_open_dir_context *dir_ctx = file->private_data;
int res; int res = 0;
dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_parent->d_name.name, dentry->d_name.name,
...@@ -839,7 +840,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) ...@@ -839,7 +840,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
nfs_block_sillyrename(dentry); nfs_block_sillyrename(dentry);
res = nfs_revalidate_mapping(inode, file->f_mapping); if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
res = nfs_revalidate_mapping(inode, file->f_mapping);
if (res < 0) if (res < 0)
goto out; goto out;
......
...@@ -936,7 +936,7 @@ int nfs_attribute_timeout(struct inode *inode) ...@@ -936,7 +936,7 @@ int nfs_attribute_timeout(struct inode *inode)
return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
} }
static int nfs_attribute_cache_expired(struct inode *inode) int nfs_attribute_cache_expired(struct inode *inode)
{ {
if (nfs_have_delegated_attributes(inode)) if (nfs_have_delegated_attributes(inode))
return 0; return 0;
......
...@@ -888,6 +888,28 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode) ...@@ -888,6 +888,28 @@ static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
return PageUptodate(page) != 0; return PageUptodate(page) != 0;
} }
/* If we know the page is up to date, and we're not using byte range locks (or
* if we have the whole file locked for writing), it may be more efficient to
* extend the write to cover the entire page in order to avoid fragmentation
* inefficiencies.
*
* If the file is opened for synchronous writes or if we have a write delegation
* from the server then we can just skip the rest of the checks.
*/
static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
{
if (file->f_flags & O_DSYNC)
return 0;
if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
return 1;
if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL ||
(inode->i_flock->fl_start == 0 &&
inode->i_flock->fl_end == OFFSET_MAX &&
inode->i_flock->fl_type != F_RDLCK)))
return 1;
return 0;
}
/* /*
* Update and possibly write a cached page of an NFS file. * Update and possibly write a cached page of an NFS file.
* *
...@@ -908,14 +930,7 @@ int nfs_updatepage(struct file *file, struct page *page, ...@@ -908,14 +930,7 @@ int nfs_updatepage(struct file *file, struct page *page,
file->f_path.dentry->d_name.name, count, file->f_path.dentry->d_name.name, count,
(long long)(page_file_offset(page) + offset)); (long long)(page_file_offset(page) + offset));
/* If we're not using byte range locks, and we know the page if (nfs_can_extend_write(file, page, inode)) {
* is up to date, it may be more efficient to extend the write
* to cover the entire page in order to avoid fragmentation
* inefficiencies.
*/
if (nfs_write_pageuptodate(page, inode) &&
inode->i_flock == NULL &&
!(file->f_flags & O_DSYNC)) {
count = max(count + offset, nfs_page_length(page)); count = max(count + offset, nfs_page_length(page));
offset = 0; offset = 0;
} }
......
...@@ -348,6 +348,7 @@ extern int nfs_permission(struct inode *, int); ...@@ -348,6 +348,7 @@ extern int nfs_permission(struct inode *, int);
extern int nfs_open(struct inode *, struct file *); extern int nfs_open(struct inode *, struct file *);
extern int nfs_release(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *);
extern int nfs_attribute_timeout(struct inode *inode); extern int nfs_attribute_timeout(struct inode *inode);
extern int nfs_attribute_cache_expired(struct inode *inode);
extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
......
...@@ -290,7 +290,7 @@ static int rpc_client_register(const struct rpc_create_args *args, ...@@ -290,7 +290,7 @@ static int rpc_client_register(const struct rpc_create_args *args,
struct rpc_auth *auth; struct rpc_auth *auth;
struct net *net = rpc_net_ns(clnt); struct net *net = rpc_net_ns(clnt);
struct super_block *pipefs_sb; struct super_block *pipefs_sb;
int err = 0; int err;
pipefs_sb = rpc_get_sb_net(net); pipefs_sb = rpc_get_sb_net(net);
if (pipefs_sb) { if (pipefs_sb) {
...@@ -299,6 +299,10 @@ static int rpc_client_register(const struct rpc_create_args *args, ...@@ -299,6 +299,10 @@ static int rpc_client_register(const struct rpc_create_args *args,
goto out; goto out;
} }
rpc_register_client(clnt);
if (pipefs_sb)
rpc_put_sb_net(net);
auth = rpcauth_create(args->authflavor, clnt); auth = rpcauth_create(args->authflavor, clnt);
if (IS_ERR(auth)) { if (IS_ERR(auth)) {
dprintk("RPC: Couldn't create auth handle (flavor %u)\n", dprintk("RPC: Couldn't create auth handle (flavor %u)\n",
...@@ -306,16 +310,14 @@ static int rpc_client_register(const struct rpc_create_args *args, ...@@ -306,16 +310,14 @@ static int rpc_client_register(const struct rpc_create_args *args,
err = PTR_ERR(auth); err = PTR_ERR(auth);
goto err_auth; goto err_auth;
} }
return 0;
rpc_register_client(clnt); err_auth:
pipefs_sb = rpc_get_sb_net(net);
__rpc_clnt_remove_pipedir(clnt);
out: out:
if (pipefs_sb) if (pipefs_sb)
rpc_put_sb_net(net); rpc_put_sb_net(net);
return err; return err;
err_auth:
__rpc_clnt_remove_pipedir(clnt);
goto out;
} }
static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
......
...@@ -480,6 +480,23 @@ static const struct dentry_operations rpc_dentry_operations = { ...@@ -480,6 +480,23 @@ static const struct dentry_operations rpc_dentry_operations = {
.d_delete = rpc_delete_dentry, .d_delete = rpc_delete_dentry,
}; };
/*
* Lookup the data. This is trivial - if the dentry didn't already
* exist, we know it is negative.
*/
static struct dentry *
rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
d_add(dentry, NULL);
return NULL;
}
static const struct inode_operations rpc_dir_inode_operations = {
.lookup = rpc_lookup,
};
static struct inode * static struct inode *
rpc_get_inode(struct super_block *sb, umode_t mode) rpc_get_inode(struct super_block *sb, umode_t mode)
{ {
...@@ -492,7 +509,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode) ...@@ -492,7 +509,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
case S_IFDIR: case S_IFDIR:
inode->i_fop = &simple_dir_operations; inode->i_fop = &simple_dir_operations;
inode->i_op = &simple_dir_inode_operations; inode->i_op = &rpc_dir_inode_operations;
inc_nlink(inode); inc_nlink(inode);
default: default:
break; break;
...@@ -666,11 +683,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, ...@@ -666,11 +683,8 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
if (!dentry) if (!dentry)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
if (dentry->d_inode == NULL) { if (dentry->d_inode == NULL)
if (!dentry->d_op)
d_set_d_op(dentry, &rpc_dentry_operations);
return dentry; return dentry;
}
dput(dentry); dput(dentry);
return ERR_PTR(-EEXIST); return ERR_PTR(-EEXIST);
} }
...@@ -1117,6 +1131,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1117,6 +1131,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = RPCAUTH_GSSMAGIC; sb->s_magic = RPCAUTH_GSSMAGIC;
sb->s_op = &s_ops; sb->s_op = &s_ops;
sb->s_d_op = &rpc_dentry_operations;
sb->s_time_gran = 1; sb->s_time_gran = 1;
inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); inode = rpc_get_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment