diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 17:24:05 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 17:24:05 -0700 |
commit | 6a6be470c3071559970c5659354484d4f664050e (patch) | |
tree | d4b335e863e426acad96fe5e4bce2e3e064abc32 /fs | |
parent | 98c89cdd3a292af3451e47a2a33132f5183861b0 (diff) | |
parent | 126e216a8730532dfb685205309275f87e3d133e (diff) |
Merge branch 'nfs-for-2.6.35' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'nfs-for-2.6.35' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (78 commits)
SUNRPC: Don't spam gssd with upcall requests when the kerberos key expired
SUNRPC: Reorder the struct rpc_task fields
SUNRPC: Remove the 'tk_magic' debugging field
SUNRPC: Move the task->tk_bytes_sent and tk_rtt to struct rpc_rqst
NFS: Don't call iput() in nfs_access_cache_shrinker
NFS: Clean up nfs_access_zap_cache()
NFS: Don't run nfs_access_cache_shrinker() when the mask is GFP_NOFS
SUNRPC: Ensure rpcauth_prune_expired() respects the nr_to_scan parameter
SUNRPC: Ensure memory shrinker doesn't waste time in rpcauth_prune_expired()
SUNRPC: Dont run rpcauth_cache_shrinker() when gfp_mask is GFP_NOFS
NFS: Read requests can use GFP_KERNEL.
NFS: Clean up nfs_create_request()
NFS: Don't use GFP_KERNEL in rpcsec_gss downcalls
NFSv4: Don't use GFP_KERNEL allocations in state recovery
SUNRPC: Fix xs_setup_bc_tcp()
SUNRPC: Replace jiffies-based metrics with ktime-based metrics
ktime: introduce ktime_to_ms()
SUNRPC: RPC metrics and RTT estimator should use same RTT value
NFS: Calldata for nfs4_renew_done()
NFS: Squelch compiler warning in nfs_add_server_stats()
...
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/client.c | 55 | ||||
-rw-r--r-- | fs/nfs/delegation.c | 2 | ||||
-rw-r--r-- | fs/nfs/dir.c | 143 | ||||
-rw-r--r-- | fs/nfs/file.c | 15 | ||||
-rw-r--r-- | fs/nfs/fscache.c | 3 | ||||
-rw-r--r-- | fs/nfs/getroot.c | 191 | ||||
-rw-r--r-- | fs/nfs/inode.c | 58 | ||||
-rw-r--r-- | fs/nfs/internal.h | 4 | ||||
-rw-r--r-- | fs/nfs/iostat.h | 6 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 20 | ||||
-rw-r--r-- | fs/nfs/nfs3acl.c | 23 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 128 | ||||
-rw-r--r-- | fs/nfs/nfs3xdr.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 12 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 172 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 36 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 22 | ||||
-rw-r--r-- | fs/nfs/nfsroot.c | 14 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 14 | ||||
-rw-r--r-- | fs/nfs/proc.c | 144 | ||||
-rw-r--r-- | fs/nfs/read.c | 4 | ||||
-rw-r--r-- | fs/nfs/super.c | 147 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 4 |
24 files changed, 732 insertions, 495 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index acc9c4943b8..7ec9b34a59f 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -934,7 +934,6 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str } fsinfo.fattr = fattr; - nfs_fattr_init(fattr); error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); if (error < 0) goto out_error; @@ -1047,13 +1046,18 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, struct nfs_fh *mntfh) { struct nfs_server *server; - struct nfs_fattr fattr; + struct nfs_fattr *fattr; int error; server = nfs_alloc_server(); if (!server) return ERR_PTR(-ENOMEM); + error = -ENOMEM; + fattr = nfs_alloc_fattr(); + if (fattr == NULL) + goto error; + /* Get a client representation */ error = nfs_init_server(server, data); if (error < 0) @@ -1064,7 +1068,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); /* Probe the root fh to retrieve its FSID */ - error = nfs_probe_fsinfo(server, mntfh, &fattr); + error = nfs_probe_fsinfo(server, mntfh, fattr); if (error < 0) goto error; if (server->nfs_client->rpc_ops->version == 3) { @@ -1077,14 +1081,14 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, server->namelen = NFS2_MAXNAMLEN; } - if (!(fattr.valid & NFS_ATTR_FATTR)) { - error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); + if (!(fattr->valid & NFS_ATTR_FATTR)) { + error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); if (error < 0) { dprintk("nfs_create_server: getattr error = %d\n", -error); goto error; } } - memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); + memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); dprintk("Server FSID: %llx:%llx\n", (unsigned long long) server->fsid.major, @@ -1096,9 +1100,11 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, spin_unlock(&nfs_client_lock); server->mount_time = jiffies; + nfs_free_fattr(fattr); return server; error: + nfs_free_fattr(fattr); nfs_free_server(server); return ERR_PTR(error); } @@ -1340,7 +1346,7 @@ error: struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, struct nfs_fh *mntfh) { - struct nfs_fattr fattr; + struct nfs_fattr *fattr; struct nfs_server *server; int error; @@ -1350,6 +1356,11 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, if (!server) return ERR_PTR(-ENOMEM); + error = -ENOMEM; + fattr = nfs_alloc_fattr(); + if (fattr == NULL) + goto error; + /* set up the general RPC client */ error = nfs4_init_server(server, data); if (error < 0) @@ -1364,7 +1375,7 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, goto error; /* Probe the root fh to retrieve its FSID */ - error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); + error = nfs4_get_rootfh(server, mntfh); if (error < 0) goto error; @@ -1375,7 +1386,7 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, nfs4_session_set_rwsize(server); - error = nfs_probe_fsinfo(server, mntfh, &fattr); + error = nfs_probe_fsinfo(server, mntfh, fattr); if (error < 0) goto error; @@ -1389,9 +1400,11 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, server->mount_time = jiffies; dprintk("<-- nfs4_create_server() = %p\n", server); + nfs_free_fattr(fattr); return server; error: + nfs_free_fattr(fattr); nfs_free_server(server); dprintk("<-- nfs4_create_server() = error %d\n", error); return ERR_PTR(error); @@ -1405,7 +1418,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, { struct nfs_client *parent_client; struct nfs_server *server, *parent_server; - struct nfs_fattr fattr; + struct nfs_fattr *fattr; int error; dprintk("--> nfs4_create_referral_server()\n"); @@ -1414,6 +1427,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, if (!server) return ERR_PTR(-ENOMEM); + error = -ENOMEM; + fattr = nfs_alloc_fattr(); + if (fattr == NULL) + goto error; + parent_server = NFS_SB(data->sb); parent_client = parent_server->nfs_client; @@ -1443,12 +1461,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); /* Probe the root fh to retrieve its FSID and filehandle */ - error = nfs4_path_walk(server, mntfh, data->mnt_path); + error = nfs4_get_rootfh(server, mntfh); if (error < 0) goto error; /* probe the filesystem info for this server filesystem */ - error = nfs_probe_fsinfo(server, mntfh, &fattr); + error = nfs_probe_fsinfo(server, mntfh, fattr); if (error < 0) goto error; @@ -1466,10 +1484,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, server->mount_time = jiffies; + nfs_free_fattr(fattr); dprintk("<-- nfs_create_referral_server() = %p\n", server); return server; error: + nfs_free_fattr(fattr); nfs_free_server(server); dprintk("<-- nfs4_create_referral_server() = error %d\n", error); return ERR_PTR(error); @@ -1485,7 +1505,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, struct nfs_fattr *fattr) { struct nfs_server *server; - struct nfs_fattr fattr_fsinfo; + struct nfs_fattr *fattr_fsinfo; int error; dprintk("--> nfs_clone_server(,%llx:%llx,)\n", @@ -1496,6 +1516,11 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, if (!server) return ERR_PTR(-ENOMEM); + error = -ENOMEM; + fattr_fsinfo = nfs_alloc_fattr(); + if (fattr_fsinfo == NULL) + goto out_free_server; + /* Copy data from the source */ server->nfs_client = source->nfs_client; atomic_inc(&server->nfs_client->cl_count); @@ -1512,7 +1537,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, nfs_init_server_aclclient(server); /* probe the filesystem info for this server filesystem */ - error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); + error = nfs_probe_fsinfo(server, fh, fattr_fsinfo); if (error < 0) goto out_free_server; @@ -1534,10 +1559,12 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, server->mount_time = jiffies; + nfs_free_fattr(fattr_fsinfo); dprintk("<-- nfs_clone_server() = %p\n", server); return server; out_free_server: + nfs_free_fattr(fattr_fsinfo); nfs_free_server(server); dprintk("<-- nfs_clone_server() = error %d\n", error); return ERR_PTR(error); diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ea61d26e787..30163454397 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -213,7 +213,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct struct nfs_delegation *freeme = NULL; int status = 0; - delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); + delegation = kmalloc(sizeof(*delegation), GFP_NOFS); if (delegation == NULL) return -ENOMEM; memcpy(delegation->stateid.data, res->delegation.data, diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a7bb5c694aa..ee9a179ebdf 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -530,9 +530,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) nfs_readdir_descriptor_t my_desc, *desc = &my_desc; struct nfs_entry my_entry; - struct nfs_fh fh; - struct nfs_fattr fattr; - long res; + int res = -ENOMEM; dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", dentry->d_parent->d_name.name, dentry->d_name.name, @@ -554,9 +552,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) my_entry.cookie = my_entry.prev_cookie = 0; my_entry.eof = 0; - my_entry.fh = &fh; - my_entry.fattr = &fattr; - nfs_fattr_init(&fattr); + my_entry.fh = nfs_alloc_fhandle(); + my_entry.fattr = nfs_alloc_fattr(); + if (my_entry.fh == NULL || my_entry.fattr == NULL) + goto out_alloc_failed; + desc->entry = &my_entry; nfs_block_sillyrename(dentry); @@ -598,7 +598,10 @@ out: nfs_unblock_sillyrename(dentry); if (res > 0) res = 0; - dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n", +out_alloc_failed: + nfs_free_fattr(my_entry.fattr); + nfs_free_fhandle(my_entry.fh); + dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", dentry->d_parent->d_name.name, dentry->d_name.name, res); return res; @@ -776,9 +779,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) struct inode *dir; struct inode *inode; struct dentry *parent; + struct nfs_fh *fhandle = NULL; + struct nfs_fattr *fattr = NULL; int error; - struct nfs_fh fhandle; - struct nfs_fattr fattr; parent = dget_parent(dentry); dir = parent->d_inode; @@ -811,14 +814,22 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) if (NFS_STALE(inode)) goto out_bad; - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); + error = -ENOMEM; + fhandle = nfs_alloc_fhandle(); + fattr = nfs_alloc_fattr(); + if (fhandle == NULL || fattr == NULL) + goto out_error; + + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); if (error) goto out_bad; - if (nfs_compare_fh(NFS_FH(inode), &fhandle)) + if (nfs_compare_fh(NFS_FH(inode), fhandle)) goto out_bad; - if ((error = nfs_refresh_inode(inode, &fattr)) != 0) + if ((error = nfs_refresh_inode(inode, fattr)) != 0) goto out_bad; + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); out_set_verifier: nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_valid: @@ -842,11 +853,21 @@ out_zap_parent: shrink_dcache_parent(dentry); } d_drop(dentry); + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); dput(parent); dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", __func__, dentry->d_parent->d_name.name, dentry->d_name.name); return 0; +out_error: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); + dput(parent); + dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", + __func__, dentry->d_parent->d_name.name, + dentry->d_name.name, error); + return error; } /* @@ -911,9 +932,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru struct dentry *res; struct dentry *parent; struct inode *inode = NULL; + struct nfs_fh *fhandle = NULL; + struct nfs_fattr *fattr = NULL; int error; - struct nfs_fh fhandle; - struct nfs_fattr fattr; dfprintk(VFS, "NFS: lookup(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -923,7 +944,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru if (dentry->d_name.len > NFS_SERVER(dir)->namelen) goto out; - res = ERR_PTR(-ENOMEM); dentry->d_op = NFS_PROTO(dir)->dentry_ops; /* @@ -936,17 +956,23 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru goto out; } + res = ERR_PTR(-ENOMEM); + fhandle = nfs_alloc_fhandle(); + fattr = nfs_alloc_fattr(); + if (fhandle == NULL || fattr == NULL) + goto out; + parent = dentry->d_parent; /* Protect against concurrent sillydeletes */ nfs_block_sillyrename(parent); - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); + error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); if (error == -ENOENT) goto no_entry; if (error < 0) { res = ERR_PTR(error); goto out_unblock_sillyrename; } - inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); + inode = nfs_fhget(dentry->d_sb, fhandle, fattr); res = (struct dentry *)inode; if (IS_ERR(res)) goto out_unblock_sillyrename; @@ -962,6 +988,8 @@ no_entry: out_unblock_sillyrename: nfs_unblock_sillyrename(parent); out: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); return res; } @@ -1669,28 +1697,33 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) smp_mb__after_atomic_dec(); } +static void nfs_access_free_list(struct list_head *head) +{ + struct nfs_access_entry *cache; + + while (!list_empty(head)) { + cache = list_entry(head->next, struct nfs_access_entry, lru); + list_del(&cache->lru); + nfs_access_free_entry(cache); + } +} + int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) { LIST_HEAD(head); struct nfs_inode *nfsi; struct nfs_access_entry *cache; -restart: + if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) + return (nr_to_scan == 0) ? 0 : -1; + spin_lock(&nfs_access_lru_lock); list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { - struct rw_semaphore *s_umount; struct inode *inode; if (nr_to_scan-- == 0) break; - s_umount = &nfsi->vfs_inode.i_sb->s_umount; - if (!down_read_trylock(s_umount)) - continue; - inode = igrab(&nfsi->vfs_inode); - if (inode == NULL) { - up_read(s_umount); - continue; - } + inode = &nfsi->vfs_inode; spin_lock(&inode->i_lock); if (list_empty(&nfsi->access_cache_entry_lru)) goto remove_lru_entry; @@ -1704,61 +1737,47 @@ restart: else { remove_lru_entry: list_del_init(&nfsi->access_cache_inode_lru); + smp_mb__before_clear_bit(); clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); + smp_mb__after_clear_bit(); } - spin_unlock(&inode->i_lock); - spin_unlock(&nfs_access_lru_lock); - iput(inode); - up_read(s_umount); - goto restart; } spin_unlock(&nfs_access_lru_lock); - while (!list_empty(&head)) { - cache = list_entry(head.next, struct nfs_access_entry, lru); - list_del(&cache->lru); - nfs_access_free_entry(cache); - } + nfs_access_free_list(&head); return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; } -static void __nfs_access_zap_cache(struct inode *inode) +static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) { - struct nfs_inode *nfsi = NFS_I(inode); struct rb_root *root_node = &nfsi->access_cache; - struct rb_node *n, *dispose = NULL; + struct rb_node *n; struct nfs_access_entry *entry; /* Unhook entries from the cache */ while ((n = rb_first(root_node)) != NULL) { entry = rb_entry(n, struct nfs_access_entry, rb_node); rb_erase(n, root_node); - list_del(&entry->lru); - n->rb_left = dispose; - dispose = n; + list_move(&entry->lru, head); } nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; - spin_unlock(&inode->i_lock); - - /* Now kill them all! */ - while (dispose != NULL) { - n = dispose; - dispose = n->rb_left; - nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); - } } void nfs_access_zap_cache(struct inode *inode) { + LIST_HEAD(head); + + if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) + return; /* Remove from global LRU init */ - if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { - spin_lock(&nfs_access_lru_lock); + spin_lock(&nfs_access_lru_lock); + if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) list_del_init(&NFS_I(inode)->access_cache_inode_lru); - spin_unlock(&nfs_access_lru_lock); - } spin_lock(&inode->i_lock); - /* This will release the spinlock */ - __nfs_access_zap_cache(inode); + __nfs_access_zap_cache(NFS_I(inode), &head); + spin_unlock(&inode->i_lock); + spin_unlock(&nfs_access_lru_lock); + nfs_access_free_list(&head); } static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) @@ -1809,8 +1828,8 @@ out_stale: nfs_access_free_entry(cache); return -ENOENT; out_zap: - /* This will release the spinlock */ - __nfs_access_zap_cache(inode); + spin_unlock(&inode->i_lock); + nfs_access_zap_cache(inode); return -ENOENT; } @@ -1865,9 +1884,11 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s smp_mb__after_atomic_inc(); /* Add inode to global LRU list */ - if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { + if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { spin_lock(&nfs_access_lru_lock); - list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); + if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) + list_add_tail(&NFS_I(inode)->access_cache_inode_lru, + &nfs_access_lru_list); spin_unlock(&nfs_access_lru_lock); } } diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8d965bddb87..cac96bcc91e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -161,14 +161,17 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) struct nfs_server *server = NFS_SERVER(inode); struct nfs_inode *nfsi = NFS_I(inode); - if (server->flags & NFS_MOUNT_NOAC) - goto force_reval; + if (nfs_have_delegated_attributes(inode)) + goto out_noreval; + if (filp->f_flags & O_DIRECT) goto force_reval; - if (nfsi->npages != 0) - return 0; - if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) - return 0; + if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) + goto force_reval; + if (nfs_attribute_timeout(inode)) + goto force_reval; +out_noreval: + return 0; force_reval: return __nfs_revalidate_inode(server, inode); } diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index a6b16ed9322..ce153a6b3ae 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c @@ -467,7 +467,8 @@ int __nfs_readpages_from_fscache(struct nfs_open_context *ctx, struct list_head *pages, unsigned *nr_pages) { - int ret, npages = *nr_pages; + unsigned npages = *nr_pages; + int ret; dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", NFS_I(inode)->fscache, npages, inode); diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index b35d2a61606..7428f7d6273 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -78,159 +78,94 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) { struct nfs_server *server = NFS_SB(sb); struct nfs_fsinfo fsinfo; - struct nfs_fattr fattr; - struct dentry *mntroot; + struct dentry *ret; struct inode *inode; int error; /* get the actual root for this mount */ - fsinfo.fattr = &fattr; + fsinfo.fattr = nfs_alloc_fattr(); + if (fsinfo.fattr == NULL) + return ERR_PTR(-ENOMEM); error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); if (error < 0) { dprintk("nfs_get_root: getattr error = %d\n", -error); - return ERR_PTR(error); + ret = ERR_PTR(error); + goto out; } inode = nfs_fhget(sb, mntfh, fsinfo.fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed\n"); - return ERR_CAST(inode); + ret = ERR_CAST(inode); + goto out; } error = nfs_superblock_set_dummy_root(sb, inode); - if (error != 0) - return ERR_PTR(error); + if (error != 0) { + ret = ERR_PTR(error); + goto out; + } /* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root */ - mntroot = d_obtain_alias(inode); - if (IS_ERR(mntroot)) { + ret = d_obtain_alias(inode); + if (IS_ERR(ret)) { dprintk("nfs_get_root: get root dentry failed\n"); - return mntroot; + goto out; } - security_d_instantiate(mntroot, inode); - - if (!mntroot->d_op) - mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; + security_d_instantiate(ret, inode); - return mntroot; + if (ret->d_op == NULL) + ret->d_op = server->nfs_client->rpc_ops->dentry_ops; +out: + nfs_free_fattr(fsinfo.fattr); + return ret; } #ifdef CONFIG_NFS_V4 -/* - * Do a simple pathwalk from the root FH of the server to the nominated target - * of the mountpoint - * - give error on symlinks - * - give error on ".." occurring in the path - * - follow traversals - */ -int nfs4_path_walk(struct nfs_server *server, - struct nfs_fh *mntfh, - const char *path) +int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) { struct nfs_fsinfo fsinfo; - struct nfs_fattr fattr; - struct nfs_fh lastfh; - struct qstr name; - int ret; + int ret = -ENOMEM; - dprintk("--> nfs4_path_walk(,,%s)\n", path); + dprintk("--> nfs4_get_rootfh()\n"); - fsinfo.fattr = &fattr; - nfs_fattr_init(&fattr); - - /* Eat leading slashes */ - while (*path == '/') - path++; + fsinfo.fattr = nfs_alloc_fattr(); + if (fsinfo.fattr == NULL) + goto out; /* Start by getting the root filehandle from the server */ ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); if (ret < 0) { - dprintk("nfs4_get_root: getroot error = %d\n", -ret); - return ret; + dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); + goto out; } - if (!S_ISDIR(fattr.mode)) { - printk(KERN_ERR "nfs4_get_root:" + if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_MODE) + || !S_ISDIR(fsinfo.fattr->mode)) { + printk(KERN_ERR "nfs4_get_rootfh:" " getroot encountered non-directory\n"); - return -ENOTDIR; + ret = -ENOTDIR; + goto out; } - /* FIXME: It is quite valid for the server to return a referral here */ - if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { - printk(KERN_ERR "nfs4_get_root:" + if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { + printk(KERN_ERR "nfs4_get_rootfh:" " getroot obtained referral\n"); - return -EREMOTE; - } - -next_component: - dprintk("Next: %s\n", path); - - /* extract the next bit of the path */ - if (!*path) - goto path_walk_complete; - - name.name = path; - while (*path && *path != '/') - path++; - name.len = path - (const char *) name.name; - - if (name.len > NFS4_MAXNAMLEN) - return -ENAMETOOLONG; - -eat_dot_dir: - while (*path == '/') - path++; - - if (path[0] == '.' && (path[1] == '/' || !path[1])) { - path += 2; - goto eat_dot_dir; - } - - /* FIXME: Why shouldn't the user be able to use ".." in the path? */ - if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) - ) { - printk(KERN_ERR "nfs4_get_root:" - " Mount path contains reference to \"..\"\n"); - return -EINVAL; + ret = -EREMOTE; + goto out; } - /* lookup the next FH in the sequence */ - memcpy(&lastfh, mntfh, sizeof(lastfh)); - - dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); - - ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, - mntfh, &fattr); - if (ret < 0) { - dprintk("nfs4_get_root: getroot error = %d\n", -ret); - return ret; - } - - if (!S_ISDIR(fattr.mode)) { - printk(KERN_ERR "nfs4_get_root:" - " lookupfh encountered non-directory\n"); - return -ENOTDIR; - } - - /* FIXME: Referrals are quite valid here too */ - if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { - printk(KERN_ERR "nfs4_get_root:" - " lookupfh obtained referral\n"); - return -EREMOTE; - } - - goto next_component; - -path_walk_complete: - memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); - dprintk("<-- nfs4_path_walk() = 0\n"); - return 0; + memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); +out: + nfs_free_fattr(fsinfo.fattr); + dprintk("<-- nfs4_get_rootfh() = %d\n", ret); + return ret; } /* @@ -239,8 +174,8 @@ path_walk_complete: struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) { struct nfs_server *server = NFS_SB(sb); - struct nfs_fattr fattr; - struct dentry *mntroot; + struct nfs_fattr *fattr = NULL; + struct dentry *ret; struct inode *inode; int error; @@ -254,40 +189,50 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) return ERR_PTR(error); } + fattr = nfs_alloc_fattr(); + if (fattr == NULL) + return ERR_PTR(-ENOMEM);; + /* get the actual root for this mount */ - error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); + error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); if (error < 0) { dprintk("nfs_get_root: getattr error = %d\n", -error); - return ERR_PTR(error); + ret = ERR_PTR(error); + goto out; } - inode = nfs_fhget(sb, mntfh, &fattr); + inode = nfs_fhget(sb, mntfh, fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed\n"); - return ERR_CAST(inode); + ret = ERR_CAST(inode); + goto out; } error = nfs_superblock_set_dummy_root(sb, inode); - if (error != 0) - return ERR_PTR(error); + if (error != 0) { + ret = ERR_PTR(error); + goto out; + } /* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root */ - mntroot = d_obtain_alias(inode); - if (IS_ERR(mntroot)) { + ret = d_obtain_alias(inode); + if (IS_ERR(ret)) { dprintk("nfs_get_root: get root dentry failed\n"); - return mntroot; + goto out; } - security_d_instantiate(mntroot, inode); + security_d_instantiate(ret, inode); - if (!mntroot->d_op) - mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; + if (ret->d_op == NULL) + ret->d_op = server->nfs_client->rpc_ops->dentry_ops; +out: + nfs_free_fattr(fattr); dprintk("<-- nfs4_get_root()\n"); - return mntroot; + return ret; } #endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 50a56edca0b..099b3518fee 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -393,8 +393,8 @@ int nfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - struct nfs_fattr fattr; - int error; + struct nfs_fattr *fattr; + int error = -ENOMEM; nfs_inc_stats(inode, NFSIOS_VFSSETATTR); @@ -417,14 +417,20 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) filemap_write_and_wait(inode->i_mapping); nfs_wb_all(inode); } + + fattr = nfs_alloc_fattr(); + if (fattr == NULL) + goto out; /* * Return any delegations if we're going to change ACLs */ if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) nfs_inode_return_delegation(inode); - error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); + error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); if (error == 0) - nfs_refresh_inode(inode, &fattr); + nfs_refresh_inode(inode, fattr); + nfs_free_fattr(fattr); +out: return error; } @@ -682,7 +688,7 @@ int __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { int status = -ESTALE; - struct nfs_fattr fattr; + struct nfs_fattr *fattr = NULL; struct nfs_inode *nfsi = NFS_I(inode); dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", @@ -693,8 +699,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) if (NFS_STA |