Skip to content

Commit b86faee

Browse files
committed
Merge tag 'nfs-for-4.13-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker: "Stable bugfixes: - Fix -EACCESS on commit to DS handling - Fix initialization of nfs_page_array->npages - Only invalidate dentries that are actually invalid Features: - Enable NFSoRDMA transparent state migration - Add support for lookup-by-filehandle - Add support for nfs re-exporting Other bugfixes and cleanups: - Christoph cleaned up the way we declare NFS operations - Clean up various internal structures - Various cleanups to commits - Various improvements to error handling - Set the dt_type of . and .. entries in NFS v4 - Make slot allocation more reliable - Fix fscache stat printing - Fix uninitialized variable warnings - Fix potential list overrun in nfs_atomic_open() - Fix a race in NFSoRDMA RPC reply handler - Fix return size for nfs42_proc_copy() - Fix against MAC forgery timing attacks" * tag 'nfs-for-4.13-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (68 commits) NFS: Don't run wake_up_bit() when nobody is waiting... nfs: add export operations nfs4: add NFSv4 LOOKUPP handlers nfs: add a nfs_ilookup helper nfs: replace d_add with d_splice_alias in atomic_open sunrpc: use constant time memory comparison for mac NFSv4.2 fix size storage for nfs42_proc_copy xprtrdma: Fix documenting comments in frwr_ops.c xprtrdma: Replace PAGE_MASK with offset_in_page() xprtrdma: FMR does not need list_del_init() xprtrdma: Demote "connect" log messages NFSv4.1: Use seqid returned by EXCHANGE_ID after state migration NFSv4.1: Handle EXCHGID4_FLAG_CONFIRMED_R during NFSv4.1 migration xprtrdma: Don't defer MR recovery if ro_map fails xprtrdma: Fix FRWR invalidation error recovery xprtrdma: Fix client lock-up after application signal fires xprtrdma: Rename rpcrdma_req::rl_free xprtrdma: Pass only the list of registered MRs to ro_unmap_sync xprtrdma: Pre-mark remotely invalidated MRs xprtrdma: On invalidation failure, remove MWs from rl_registered ...
2 parents 48ea2ce + b4f937c commit b86faee

35 files changed

Lines changed: 777 additions & 289 deletions

fs/nfs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o
77
CFLAGS_nfstrace.o += -I$(src)
88
nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
99
io.o direct.o pagelist.o read.o symlink.o unlink.o \
10-
write.o namespace.o mount_clnt.o nfstrace.o
10+
write.o namespace.o mount_clnt.o nfstrace.o export.o
1111
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
1212
nfs-$(CONFIG_SYSCTL) += sysctl.o
1313
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o

fs/nfs/dir.c

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ struct nfs_cache_array {
151151
struct nfs_cache_array_entry array[0];
152152
};
153153

154-
typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int);
154+
typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool);
155155
typedef struct {
156156
struct file *file;
157157
struct page *page;
@@ -165,8 +165,8 @@ typedef struct {
165165
unsigned long timestamp;
166166
unsigned long gencount;
167167
unsigned int cache_entry_index;
168-
unsigned int plus:1;
169-
unsigned int eof:1;
168+
bool plus;
169+
bool eof;
170170
} nfs_readdir_descriptor_t;
171171

172172
/*
@@ -355,7 +355,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
355355
if (error == -ENOTSUPP && desc->plus) {
356356
NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS;
357357
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
358-
desc->plus = 0;
358+
desc->plus = false;
359359
goto again;
360360
}
361361
goto error;
@@ -557,7 +557,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
557557

558558
count++;
559559

560-
if (desc->plus != 0)
560+
if (desc->plus)
561561
nfs_prime_dcache(file_dentry(desc->file), entry);
562562

563563
status = nfs_readdir_add_to_array(entry, page);
@@ -860,7 +860,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
860860
desc->ctx = ctx;
861861
desc->dir_cookie = &dir_ctx->dir_cookie;
862862
desc->decode = NFS_PROTO(inode)->decode_dirent;
863-
desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
863+
desc->plus = nfs_use_readdirplus(inode, ctx);
864864

865865
if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
866866
res = nfs_revalidate_mapping(inode, file->f_mapping);
@@ -885,8 +885,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
885885
clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
886886
nfs_zap_caches(inode);
887887
desc->page_index = 0;
888-
desc->plus = 0;
889-
desc->eof = 0;
888+
desc->plus = false;
889+
desc->eof = false;
890890
continue;
891891
}
892892
if (res < 0)
@@ -1115,11 +1115,13 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
11151115
/* Force a full look up iff the parent directory has changed */
11161116
if (!nfs_is_exclusive_create(dir, flags) &&
11171117
nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
1118-
1119-
if (nfs_lookup_verify_inode(inode, flags)) {
1118+
error = nfs_lookup_verify_inode(inode, flags);
1119+
if (error) {
11201120
if (flags & LOOKUP_RCU)
11211121
return -ECHILD;
1122-
goto out_zap_parent;
1122+
if (error == -ESTALE)
1123+
goto out_zap_parent;
1124+
goto out_error;
11231125
}
11241126
nfs_advise_use_readdirplus(dir);
11251127
goto out_valid;
@@ -1144,8 +1146,10 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
11441146
trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
11451147
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
11461148
trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
1147-
if (error)
1149+
if (error == -ESTALE || error == -ENOENT)
11481150
goto out_bad;
1151+
if (error)
1152+
goto out_error;
11491153
if (nfs_compare_fh(NFS_FH(inode), fhandle))
11501154
goto out_bad;
11511155
if ((error = nfs_refresh_inode(inode, fattr)) != 0)
@@ -1427,8 +1431,10 @@ static int nfs_finish_open(struct nfs_open_context *ctx,
14271431
err = finish_open(file, dentry, do_open, opened);
14281432
if (err)
14291433
goto out;
1430-
nfs_file_set_open_context(file, ctx);
1431-
1434+
if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
1435+
nfs_file_set_open_context(file, ctx);
1436+
else
1437+
err = -ESTALE;
14321438
out:
14331439
return err;
14341440
}
@@ -1512,7 +1518,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
15121518
d_drop(dentry);
15131519
switch (err) {
15141520
case -ENOENT:
1515-
d_add(dentry, NULL);
1521+
d_splice_alias(NULL, dentry);
15161522
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
15171523
break;
15181524
case -EISDIR:
@@ -2035,7 +2041,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
20352041
}
20362042

20372043
error = rpc_wait_for_completion_task(task);
2038-
if (error == 0)
2044+
if (error != 0) {
2045+
((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1;
2046+
/* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */
2047+
smp_wmb();
2048+
} else
20392049
error = task->tk_status;
20402050
rpc_put_task(task);
20412051
nfs_mark_for_revalidate(old_inode);

fs/nfs/export.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* Copyright (c) 2015, Primary Data, Inc. All rights reserved.
3+
*
4+
* Tao Peng <[email protected]>
5+
*/
6+
#include <linux/dcache.h>
7+
#include <linux/exportfs.h>
8+
#include <linux/nfs.h>
9+
#include <linux/nfs_fs.h>
10+
11+
#include "internal.h"
12+
#include "nfstrace.h"
13+
14+
#define NFSDBG_FACILITY NFSDBG_VFS
15+
16+
enum {
17+
FILEID_HIGH_OFF = 0, /* inode fileid high */
18+
FILEID_LOW_OFF, /* inode fileid low */
19+
FILE_I_TYPE_OFF, /* inode type */
20+
EMBED_FH_OFF /* embeded server fh */
21+
};
22+
23+
24+
static struct nfs_fh *nfs_exp_embedfh(__u32 *p)
25+
{
26+
return (struct nfs_fh *)(p + EMBED_FH_OFF);
27+
}
28+
29+
/*
30+
* Let's break subtree checking for now... otherwise we'll have to embed parent fh
31+
* but there might not be enough space.
32+
*/
33+
static int
34+
nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
35+
{
36+
struct nfs_fh *server_fh = NFS_FH(inode);
37+
struct nfs_fh *clnt_fh = nfs_exp_embedfh(p);
38+
size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
39+
int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
40+
41+
dprintk("%s: max fh len %d inode %p parent %p",
42+
__func__, *max_len, inode, parent);
43+
44+
if (*max_len < len || IS_AUTOMOUNT(inode)) {
45+
dprintk("%s: fh len %d too small, required %d\n",
46+
__func__, *max_len, len);
47+
*max_len = len;
48+
return FILEID_INVALID;
49+
}
50+
if (IS_AUTOMOUNT(inode)) {
51+
*max_len = FILEID_INVALID;
52+
goto out;
53+
}
54+
55+
p[FILEID_HIGH_OFF] = NFS_FILEID(inode) >> 32;
56+
p[FILEID_LOW_OFF] = NFS_FILEID(inode);
57+
p[FILE_I_TYPE_OFF] = inode->i_mode & S_IFMT;
58+
p[len - 1] = 0; /* Padding */
59+
nfs_copy_fh(clnt_fh, server_fh);
60+
*max_len = len;
61+
out:
62+
dprintk("%s: result fh fileid %llu mode %u size %d\n",
63+
__func__, NFS_FILEID(inode), inode->i_mode, *max_len);
64+
return *max_len;
65+
}
66+
67+
static struct dentry *
68+
nfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
69+
int fh_len, int fh_type)
70+
{
71+
struct nfs4_label *label = NULL;
72+
struct nfs_fattr *fattr = NULL;
73+
struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw);
74+
size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size;
75+
const struct nfs_rpc_ops *rpc_ops;
76+
struct dentry *dentry;
77+
struct inode *inode;
78+
int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size);
79+
u32 *p = fid->raw;
80+
int ret;
81+
82+
/* NULL translates to ESTALE */
83+
if (fh_len < len || fh_type != len)
84+
return NULL;
85+
86+
fattr = nfs_alloc_fattr();
87+
if (fattr == NULL) {
88+
dentry = ERR_PTR(-ENOMEM);
89+
goto out;
90+
}
91+
92+
fattr->fileid = ((u64)p[FILEID_HIGH_OFF] << 32) + p[FILEID_LOW_OFF];
93+
fattr->mode = p[FILE_I_TYPE_OFF];
94+
fattr->valid |= NFS_ATTR_FATTR_FILEID | NFS_ATTR_FATTR_TYPE;
95+
96+
dprintk("%s: fileid %llu mode %d\n", __func__, fattr->fileid, fattr->mode);
97+
98+
inode = nfs_ilookup(sb, fattr, server_fh);
99+
if (inode)
100+
goto out_found;
101+
102+
label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL);
103+
if (IS_ERR(label)) {
104+
dentry = ERR_CAST(label);
105+
goto out_free_fattr;
106+
}
107+
108+
rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops;
109+
ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label);
110+
if (ret) {
111+
dprintk("%s: getattr failed %d\n", __func__, ret);
112+
dentry = ERR_PTR(ret);
113+
goto out_free_label;
114+
}
115+
116+
inode = nfs_fhget(sb, server_fh, fattr, label);
117+
118+
out_found:
119+
dentry = d_obtain_alias(inode);
120+
121+
out_free_label:
122+
nfs4_label_free(label);
123+
out_free_fattr:
124+
nfs_free_fattr(fattr);
125+
out:
126+
return dentry;
127+
}
128+
129+
static struct dentry *
130+
nfs_get_parent(struct dentry *dentry)
131+
{
132+
int ret;
133+
struct inode *inode = d_inode(dentry), *pinode;
134+
struct super_block *sb = inode->i_sb;
135+
struct nfs_server *server = NFS_SB(sb);
136+
struct nfs_fattr *fattr = NULL;
137+
struct nfs4_label *label = NULL;
138+
struct dentry *parent;
139+
struct nfs_rpc_ops const *ops = server->nfs_client->rpc_ops;
140+
struct nfs_fh fh;
141+
142+
if (!ops->lookupp)
143+
return ERR_PTR(-EACCES);
144+
145+
fattr = nfs_alloc_fattr();
146+
if (fattr == NULL) {
147+
parent = ERR_PTR(-ENOMEM);
148+
goto out;
149+
}
150+
151+
label = nfs4_label_alloc(server, GFP_KERNEL);
152+
if (IS_ERR(label)) {
153+
parent = ERR_CAST(label);
154+
goto out_free_fattr;
155+
}
156+
157+
ret = ops->lookupp(inode, &fh, fattr, label);
158+
if (ret) {
159+
parent = ERR_PTR(ret);
160+
goto out_free_label;
161+
}
162+
163+
pinode = nfs_fhget(sb, &fh, fattr, label);
164+
parent = d_obtain_alias(pinode);
165+
out_free_label:
166+
nfs4_label_free(label);
167+
out_free_fattr:
168+
nfs_free_fattr(fattr);
169+
out:
170+
return parent;
171+
}
172+
173+
const struct export_operations nfs_export_ops = {
174+
.encode_fh = nfs_encode_fh,
175+
.fh_to_dentry = nfs_fh_to_dentry,
176+
.get_parent = nfs_get_parent,
177+
};

fs/nfs/filelayout/filelayout.c

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -126,32 +126,13 @@ static int filelayout_async_handle_error(struct rpc_task *task,
126126
{
127127
struct pnfs_layout_hdr *lo = lseg->pls_layout;
128128
struct inode *inode = lo->plh_inode;
129-
struct nfs_server *mds_server = NFS_SERVER(inode);
130129
struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
131-
struct nfs_client *mds_client = mds_server->nfs_client;
132130
struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
133131

134132
if (task->tk_status >= 0)
135133
return 0;
136134

137135
switch (task->tk_status) {
138-
/* MDS state errors */
139-
case -NFS4ERR_DELEG_REVOKED:
140-
case -NFS4ERR_ADMIN_REVOKED:
141-
case -NFS4ERR_BAD_STATEID:
142-
case -NFS4ERR_OPENMODE:
143-
if (state == NULL)
144-
break;
145-
if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
146-
goto out_bad_stateid;
147-
goto wait_on_recovery;
148-
case -NFS4ERR_EXPIRED:
149-
if (state != NULL) {
150-
if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
151-
goto out_bad_stateid;
152-
}
153-
nfs4_schedule_lease_recovery(mds_client);
154-
goto wait_on_recovery;
155136
/* DS session errors */
156137
case -NFS4ERR_BADSESSION:
157138
case -NFS4ERR_BADSLOT:
@@ -172,6 +153,7 @@ static int filelayout_async_handle_error(struct rpc_task *task,
172153
case -NFS4ERR_RETRY_UNCACHED_REP:
173154
break;
174155
/* Invalidate Layout errors */
156+
case -NFS4ERR_ACCESS:
175157
case -NFS4ERR_PNFS_NO_LAYOUT:
176158
case -ESTALE: /* mapped NFS4ERR_STALE */
177159
case -EBADHANDLE: /* mapped NFS4ERR_BADHANDLE */
@@ -202,26 +184,17 @@ static int filelayout_async_handle_error(struct rpc_task *task,
202184
task->tk_status);
203185
nfs4_mark_deviceid_unavailable(devid);
204186
pnfs_error_mark_layout_for_return(inode, lseg);
187+
pnfs_set_lo_fail(lseg);
205188
rpc_wake_up(&tbl->slot_tbl_waitq);
206189
/* fall through */
207190
default:
208-
pnfs_set_lo_fail(lseg);
209191
reset:
210192
dprintk("%s Retry through MDS. Error %d\n", __func__,
211193
task->tk_status);
212194
return -NFS4ERR_RESET_TO_MDS;
213195
}
214-
out:
215196
task->tk_status = 0;
216197
return -EAGAIN;
217-
out_bad_stateid:
218-
task->tk_status = -EIO;
219-
return 0;
220-
wait_on_recovery:
221-
rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
222-
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
223-
rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
224-
goto out;
225198
}
226199

227200
/* NFS_PROTO call done callback routines */

0 commit comments

Comments
 (0)