diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-18 15:52:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-18 15:52:08 -0400 |
commit | ead13aee235fa1619d85f2ab5cfb9308a19f8da3 (patch) | |
tree | f4f51cda0437d194219e1bfe450c01f4e006a30c /fs | |
parent | 929254d8da55a046fe792e79a220f83df761305d (diff) | |
parent | b8fb9c30f25e45dab5d2cd310ab6913b6861d00f (diff) |
Merge tag 'nfs-for-3.18-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
Stable fixes:
- fix an uninitialised pointer Oops in the writeback error path
- fix a bogus warning (and early exit from the loop) in nfs_generic_pgio()
Features:
- Add NFSv4.2 SEEK feature and client support for lseek(SEEK_HOLE/SEEK_DATA)
Other fixes:
- pnfs: replace broken pnfs_put_lseg_async
- Remove dead prototype for nfs4_insert_deviceid_node"
* tag 'nfs-for-3.18-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
NFS: Fix a bogus warning in nfs_generic_pgio
NFS: Fix an uninitialised pointer Oops in the writeback error path
NFSv4.1/pnfs: replace broken pnfs_put_lseg_async
NFSv4: Remove dead prototype for nfs4_insert_deviceid_node()
NFS: Implement SEEK
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/Makefile | 1 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 2 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs42.h | 14 | ||||
-rw-r--r-- | fs/nfs/nfs42proc.c | 69 | ||||
-rw-r--r-- | fs/nfs/nfs42xdr.c | 98 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4file.c | 25 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 7 | ||||
-rw-r--r-- | fs/nfs/pagelist.c | 10 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 33 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 7 |
13 files changed, 255 insertions, 20 deletions
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 4782e0840dcc..04cb830fa09f 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile | |||
@@ -28,6 +28,7 @@ nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o | |||
28 | nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o | 28 | nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o |
29 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o | 29 | nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o |
30 | nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o | 30 | nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o |
31 | nfsv4-$(CONFIG_NFS_V4_2) += nfs42proc.o | ||
31 | 32 | ||
32 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/ | 33 | obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/ |
33 | obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ | 34 | obj-$(CONFIG_PNFS_OBJLAYOUT) += objlayout/ |
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index abc5056999d6..46fab1cb455a 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -1031,7 +1031,7 @@ filelayout_clear_request_commit(struct nfs_page *req, | |||
1031 | } | 1031 | } |
1032 | out: | 1032 | out: |
1033 | nfs_request_remove_commit_list(req, cinfo); | 1033 | nfs_request_remove_commit_list(req, cinfo); |
1034 | pnfs_put_lseg_async(freeme); | 1034 | pnfs_put_lseg_locked(freeme); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | static void | 1037 | static void |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 141c9f4a40de..6388a59f2add 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -718,6 +718,7 @@ struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) | |||
718 | kfree(new); | 718 | kfree(new); |
719 | return res; | 719 | return res; |
720 | } | 720 | } |
721 | EXPORT_SYMBOL_GPL(nfs_get_lock_context); | ||
721 | 722 | ||
722 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | 723 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) |
723 | { | 724 | { |
@@ -730,6 +731,7 @@ void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | |||
730 | spin_unlock(&inode->i_lock); | 731 | spin_unlock(&inode->i_lock); |
731 | kfree(l_ctx); | 732 | kfree(l_ctx); |
732 | } | 733 | } |
734 | EXPORT_SYMBOL_GPL(nfs_put_lock_context); | ||
733 | 735 | ||
734 | /** | 736 | /** |
735 | * nfs_close_context - Common close_context() routine NFSv2/v3 | 737 | * nfs_close_context - Common close_context() routine NFSv2/v3 |
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h new file mode 100644 index 000000000000..d10333a197bf --- /dev/null +++ b/fs/nfs/nfs42.h | |||
@@ -0,0 +1,14 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> | ||
3 | */ | ||
4 | |||
5 | #ifndef __LINUX_FS_NFS_NFS4_2_H | ||
6 | #define __LINUX_FS_NFS_NFS4_2_H | ||
7 | |||
8 | /* nfs4.2proc.c */ | ||
9 | loff_t nfs42_proc_llseek(struct file *, loff_t, int); | ||
10 | |||
11 | /* nfs4.2xdr.h */ | ||
12 | extern struct rpc_procinfo nfs4_2_procedures[]; | ||
13 | |||
14 | #endif /* __LINUX_FS_NFS_NFS4_2_H */ | ||
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c new file mode 100644 index 000000000000..0886f1db5917 --- /dev/null +++ b/fs/nfs/nfs42proc.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> | ||
3 | */ | ||
4 | #include <linux/fs.h> | ||
5 | #include <linux/sunrpc/sched.h> | ||
6 | #include <linux/nfs.h> | ||
7 | #include <linux/nfs3.h> | ||
8 | #include <linux/nfs4.h> | ||
9 | #include <linux/nfs_xdr.h> | ||
10 | #include <linux/nfs_fs.h> | ||
11 | #include "nfs4_fs.h" | ||
12 | #include "nfs42.h" | ||
13 | |||
14 | static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file, | ||
15 | fmode_t fmode) | ||
16 | { | ||
17 | struct nfs_open_context *open; | ||
18 | struct nfs_lock_context *lock; | ||
19 | int ret; | ||
20 | |||
21 | open = get_nfs_open_context(nfs_file_open_context(file)); | ||
22 | lock = nfs_get_lock_context(open); | ||
23 | if (IS_ERR(lock)) { | ||
24 | put_nfs_open_context(open); | ||
25 | return PTR_ERR(lock); | ||
26 | } | ||
27 | |||
28 | ret = nfs4_set_rw_stateid(dst, open, lock, fmode); | ||
29 | |||
30 | nfs_put_lock_context(lock); | ||
31 | put_nfs_open_context(open); | ||
32 | return ret; | ||
33 | } | ||
34 | |||
35 | loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence) | ||
36 | { | ||
37 | struct inode *inode = file_inode(filep); | ||
38 | struct nfs42_seek_args args = { | ||
39 | .sa_fh = NFS_FH(inode), | ||
40 | .sa_offset = offset, | ||
41 | .sa_what = (whence == SEEK_HOLE) ? | ||
42 | NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA, | ||
43 | }; | ||
44 | struct nfs42_seek_res res; | ||
45 | struct rpc_message msg = { | ||
46 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK], | ||
47 | .rpc_argp = &args, | ||
48 | .rpc_resp = &res, | ||
49 | }; | ||
50 | struct nfs_server *server = NFS_SERVER(inode); | ||
51 | int status; | ||
52 | |||
53 | if (!(server->caps & NFS_CAP_SEEK)) | ||
54 | return -ENOTSUPP; | ||
55 | |||
56 | status = nfs42_set_rw_stateid(&args.sa_stateid, filep, FMODE_READ); | ||
57 | if (status) | ||
58 | return status; | ||
59 | |||
60 | nfs_wb_all(inode); | ||
61 | status = nfs4_call_sync(server->client, server, &msg, | ||
62 | &args.seq_args, &res.seq_res, 0); | ||
63 | if (status == -ENOTSUPP) | ||
64 | server->caps &= ~NFS_CAP_SEEK; | ||
65 | if (status) | ||
66 | return status; | ||
67 | |||
68 | return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes); | ||
69 | } | ||
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c new file mode 100644 index 000000000000..c90469b604b8 --- /dev/null +++ b/fs/nfs/nfs42xdr.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com> | ||
3 | */ | ||
4 | #ifndef __LINUX_FS_NFS_NFS4_2XDR_H | ||
5 | #define __LINUX_FS_NFS_NFS4_2XDR_H | ||
6 | |||
7 | #define encode_seek_maxsz (op_encode_hdr_maxsz + \ | ||
8 | encode_stateid_maxsz + \ | ||
9 | 2 /* offset */ + \ | ||
10 | 1 /* whence */) | ||
11 | #define decode_seek_maxsz (op_decode_hdr_maxsz + \ | ||
12 | 1 /* eof */ + \ | ||
13 | 1 /* whence */ + \ | ||
14 | 2 /* offset */ + \ | ||
15 | 2 /* length */) | ||
16 | |||
17 | #define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \ | ||
18 | encode_putfh_maxsz + \ | ||
19 | encode_seek_maxsz) | ||
20 | #define NFS4_dec_seek_sz (compound_decode_hdr_maxsz + \ | ||
21 | decode_putfh_maxsz + \ | ||
22 | decode_seek_maxsz) | ||
23 | |||
24 | |||
25 | static void encode_seek(struct xdr_stream *xdr, | ||
26 | struct nfs42_seek_args *args, | ||
27 | struct compound_hdr *hdr) | ||
28 | { | ||
29 | encode_op_hdr(xdr, OP_SEEK, decode_seek_maxsz, hdr); | ||
30 | encode_nfs4_stateid(xdr, &args->sa_stateid); | ||
31 | encode_uint64(xdr, args->sa_offset); | ||
32 | encode_uint32(xdr, args->sa_what); | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * Encode SEEK request | ||
37 | */ | ||
38 | static void nfs4_xdr_enc_seek(struct rpc_rqst *req, | ||
39 | struct xdr_stream *xdr, | ||
40 | struct nfs42_seek_args *args) | ||
41 | { | ||
42 | struct compound_hdr hdr = { | ||
43 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
44 | }; | ||
45 | |||
46 | encode_compound_hdr(xdr, req, &hdr); | ||
47 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
48 | encode_putfh(xdr, args->sa_fh, &hdr); | ||
49 | encode_seek(xdr, args, &hdr); | ||
50 | encode_nops(&hdr); | ||
51 | } | ||
52 | |||
53 | static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res) | ||
54 | { | ||
55 | int status; | ||
56 | __be32 *p; | ||
57 | |||
58 | status = decode_op_hdr(xdr, OP_SEEK); | ||
59 | if (status) | ||
60 | return status; | ||
61 | |||
62 | p = xdr_inline_decode(xdr, 4 + 8); | ||
63 | if (unlikely(!p)) | ||
64 | goto out_overflow; | ||
65 | |||
66 | res->sr_eof = be32_to_cpup(p++); | ||
67 | p = xdr_decode_hyper(p, &res->sr_offset); | ||
68 | return 0; | ||
69 | |||
70 | out_overflow: | ||
71 | print_overflow_msg(__func__, xdr); | ||
72 | return -EIO; | ||
73 | } | ||
74 | |||
75 | /* | ||
76 | * Decode SEEK request | ||
77 | */ | ||
78 | static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp, | ||
79 | struct xdr_stream *xdr, | ||
80 | struct nfs42_seek_res *res) | ||
81 | { | ||
82 | struct compound_hdr hdr; | ||
83 | int status; | ||
84 | |||
85 | status = decode_compound_hdr(xdr, &hdr); | ||
86 | if (status) | ||
87 | goto out; | ||
88 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
89 | if (status) | ||
90 | goto out; | ||
91 | status = decode_putfh(xdr); | ||
92 | if (status) | ||
93 | goto out; | ||
94 | status = decode_seek(xdr, res); | ||
95 | out: | ||
96 | return status; | ||
97 | } | ||
98 | #endif /* __LINUX_FS_NFS_NFS4_2XDR_H */ | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a8b855ab4e22..be6cac37ea10 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -226,6 +226,9 @@ int nfs4_replace_transport(struct nfs_server *server, | |||
226 | const struct nfs4_fs_locations *locations); | 226 | const struct nfs4_fs_locations *locations); |
227 | 227 | ||
228 | /* nfs4proc.c */ | 228 | /* nfs4proc.c */ |
229 | extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *, | ||
230 | struct rpc_message *, struct nfs4_sequence_args *, | ||
231 | struct nfs4_sequence_res *, int); | ||
229 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); | 232 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
230 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); | 233 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); |
231 | extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool); | 234 | extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool); |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 3e987ad9ae25..c51fb4db9bfe 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -8,6 +8,10 @@ | |||
8 | #include "fscache.h" | 8 | #include "fscache.h" |
9 | #include "pnfs.h" | 9 | #include "pnfs.h" |
10 | 10 | ||
11 | #ifdef CONFIG_NFS_V4_2 | ||
12 | #include "nfs42.h" | ||
13 | #endif | ||
14 | |||
11 | #define NFSDBG_FACILITY NFSDBG_FILE | 15 | #define NFSDBG_FACILITY NFSDBG_FILE |
12 | 16 | ||
13 | static int | 17 | static int |
@@ -115,8 +119,29 @@ nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
115 | return ret; | 119 | return ret; |
116 | } | 120 | } |
117 | 121 | ||
122 | #ifdef CONFIG_NFS_V4_2 | ||
123 | static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) | ||
124 | { | ||
125 | loff_t ret; | ||
126 | |||
127 | switch (whence) { | ||
128 | case SEEK_HOLE: | ||
129 | case SEEK_DATA: | ||
130 | ret = nfs42_proc_llseek(filep, offset, whence); | ||
131 | if (ret != -ENOTSUPP) | ||
132 | return ret; | ||
133 | default: | ||
134 | return nfs_file_llseek(filep, offset, whence); | ||
135 | } | ||
136 | } | ||
137 | #endif /* CONFIG_NFS_V4_2 */ | ||
138 | |||
118 | const struct file_operations nfs4_file_operations = { | 139 | const struct file_operations nfs4_file_operations = { |
140 | #ifdef CONFIG_NFS_V4_2 | ||
141 | .llseek = nfs4_file_llseek, | ||
142 | #else | ||
119 | .llseek = nfs_file_llseek, | 143 | .llseek = nfs_file_llseek, |
144 | #endif | ||
120 | .read = new_sync_read, | 145 | .read = new_sync_read, |
121 | .write = new_sync_write, | 146 | .write = new_sync_write, |
122 | .read_iter = nfs_file_read, | 147 | .read_iter = nfs_file_read, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5aa55c132aa2..405bd95c1f58 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -885,7 +885,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, | |||
885 | return ret; | 885 | return ret; |
886 | } | 886 | } |
887 | 887 | ||
888 | static | ||
889 | int nfs4_call_sync(struct rpc_clnt *clnt, | 888 | int nfs4_call_sync(struct rpc_clnt *clnt, |
890 | struct nfs_server *server, | 889 | struct nfs_server *server, |
891 | struct rpc_message *msg, | 890 | struct rpc_message *msg, |
@@ -8409,7 +8408,8 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
8409 | | NFS_CAP_CHANGE_ATTR | 8408 | | NFS_CAP_CHANGE_ATTR |
8410 | | NFS_CAP_POSIX_LOCK | 8409 | | NFS_CAP_POSIX_LOCK |
8411 | | NFS_CAP_STATEID_NFSV41 | 8410 | | NFS_CAP_STATEID_NFSV41 |
8412 | | NFS_CAP_ATOMIC_OPEN_V1, | 8411 | | NFS_CAP_ATOMIC_OPEN_V1 |
8412 | | NFS_CAP_SEEK, | ||
8413 | .init_client = nfs41_init_client, | 8413 | .init_client = nfs41_init_client, |
8414 | .shutdown_client = nfs41_shutdown_client, | 8414 | .shutdown_client = nfs41_shutdown_client, |
8415 | .match_stateid = nfs41_match_stateid, | 8415 | .match_stateid = nfs41_match_stateid, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 005d03c5d274..206c08a60c7f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -7321,6 +7321,10 @@ nfs4_stat_to_errno(int stat) | |||
7321 | return -stat; | 7321 | return -stat; |
7322 | } | 7322 | } |
7323 | 7323 | ||
7324 | #ifdef CONFIG_NFS_V4_2 | ||
7325 | #include "nfs42xdr.c" | ||
7326 | #endif /* CONFIG_NFS_V4_2 */ | ||
7327 | |||
7324 | #define PROC(proc, argtype, restype) \ | 7328 | #define PROC(proc, argtype, restype) \ |
7325 | [NFSPROC4_CLNT_##proc] = { \ | 7329 | [NFSPROC4_CLNT_##proc] = { \ |
7326 | .p_proc = NFSPROC4_COMPOUND, \ | 7330 | .p_proc = NFSPROC4_COMPOUND, \ |
@@ -7388,6 +7392,9 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
7388 | enc_bind_conn_to_session, dec_bind_conn_to_session), | 7392 | enc_bind_conn_to_session, dec_bind_conn_to_session), |
7389 | PROC(DESTROY_CLIENTID, enc_destroy_clientid, dec_destroy_clientid), | 7393 | PROC(DESTROY_CLIENTID, enc_destroy_clientid, dec_destroy_clientid), |
7390 | #endif /* CONFIG_NFS_V4_1 */ | 7394 | #endif /* CONFIG_NFS_V4_1 */ |
7395 | #ifdef CONFIG_NFS_V4_2 | ||
7396 | PROC(SEEK, enc_seek, dec_seek), | ||
7397 | #endif /* CONFIG_NFS_V4_2 */ | ||
7391 | }; | 7398 | }; |
7392 | 7399 | ||
7393 | const struct rpc_version nfs_version4 = { | 7400 | const struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 94e16ec88312..ed0db61f8543 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -526,7 +526,8 @@ EXPORT_SYMBOL_GPL(nfs_pgio_header_free); | |||
526 | */ | 526 | */ |
527 | void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) | 527 | void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) |
528 | { | 528 | { |
529 | put_nfs_open_context(hdr->args.context); | 529 | if (hdr->args.context) |
530 | put_nfs_open_context(hdr->args.context); | ||
530 | if (hdr->page_array.pagevec != hdr->page_array.page_array) | 531 | if (hdr->page_array.pagevec != hdr->page_array.page_array) |
531 | kfree(hdr->page_array.pagevec); | 532 | kfree(hdr->page_array.pagevec); |
532 | } | 533 | } |
@@ -751,12 +752,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
751 | nfs_list_remove_request(req); | 752 | nfs_list_remove_request(req); |
752 | nfs_list_add_request(req, &hdr->pages); | 753 | nfs_list_add_request(req, &hdr->pages); |
753 | 754 | ||
754 | if (WARN_ON_ONCE(pageused >= pagecount)) | ||
755 | return nfs_pgio_error(desc, hdr); | ||
756 | |||
757 | if (!last_page || last_page != req->wb_page) { | 755 | if (!last_page || last_page != req->wb_page) { |
758 | *pages++ = last_page = req->wb_page; | ||
759 | pageused++; | 756 | pageused++; |
757 | if (pageused > pagecount) | ||
758 | break; | ||
759 | *pages++ = last_page = req->wb_page; | ||
760 | } | 760 | } |
761 | } | 761 | } |
762 | if (WARN_ON_ONCE(pageused != pagecount)) | 762 | if (WARN_ON_ONCE(pageused != pagecount)) |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 76de7f568119..0a5dda4d85c2 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -361,22 +361,43 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
361 | } | 361 | } |
362 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); | 362 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); |
363 | 363 | ||
364 | static void pnfs_put_lseg_async_work(struct work_struct *work) | 364 | static void pnfs_free_lseg_async_work(struct work_struct *work) |
365 | { | 365 | { |
366 | struct pnfs_layout_segment *lseg; | 366 | struct pnfs_layout_segment *lseg; |
367 | struct pnfs_layout_hdr *lo; | ||
367 | 368 | ||
368 | lseg = container_of(work, struct pnfs_layout_segment, pls_work); | 369 | lseg = container_of(work, struct pnfs_layout_segment, pls_work); |
370 | lo = lseg->pls_layout; | ||
369 | 371 | ||
370 | pnfs_put_lseg(lseg); | 372 | pnfs_free_lseg(lseg); |
373 | pnfs_put_layout_hdr(lo); | ||
371 | } | 374 | } |
372 | 375 | ||
373 | void | 376 | static void pnfs_free_lseg_async(struct pnfs_layout_segment *lseg) |
374 | pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) | ||
375 | { | 377 | { |
376 | INIT_WORK(&lseg->pls_work, pnfs_put_lseg_async_work); | 378 | INIT_WORK(&lseg->pls_work, pnfs_free_lseg_async_work); |
377 | schedule_work(&lseg->pls_work); | 379 | schedule_work(&lseg->pls_work); |
378 | } | 380 | } |
379 | EXPORT_SYMBOL_GPL(pnfs_put_lseg_async); | 381 | |
382 | void | ||
383 | pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg) | ||
384 | { | ||
385 | if (!lseg) | ||
386 | return; | ||
387 | |||
388 | assert_spin_locked(&lseg->pls_layout->plh_inode->i_lock); | ||
389 | |||
390 | dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, | ||
391 | atomic_read(&lseg->pls_refcount), | ||
392 | test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | ||
393 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | ||
394 | struct pnfs_layout_hdr *lo = lseg->pls_layout; | ||
395 | pnfs_get_layout_hdr(lo); | ||
396 | pnfs_layout_remove_lseg(lo, lseg); | ||
397 | pnfs_free_lseg_async(lseg); | ||
398 | } | ||
399 | } | ||
400 | EXPORT_SYMBOL_GPL(pnfs_put_lseg_locked); | ||
380 | 401 | ||
381 | static u64 | 402 | static u64 |
382 | end_offset(u64 start, u64 len) | 403 | end_offset(u64 start, u64 len) |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 693ce42ec683..9ae5b765b073 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -190,7 +190,7 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | |||
190 | /* pnfs.c */ | 190 | /* pnfs.c */ |
191 | void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); | 191 | void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); |
192 | void pnfs_put_lseg(struct pnfs_layout_segment *lseg); | 192 | void pnfs_put_lseg(struct pnfs_layout_segment *lseg); |
193 | void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg); | 193 | void pnfs_put_lseg_locked(struct pnfs_layout_segment *lseg); |
194 | 194 | ||
195 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); | 195 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); |
196 | void unset_pnfs_layoutdriver(struct nfs_server *); | 196 | void unset_pnfs_layoutdriver(struct nfs_server *); |
@@ -270,7 +270,6 @@ nfs4_find_get_deviceid(struct nfs_server *server, | |||
270 | void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); | 270 | void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); |
271 | void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, struct nfs_server *, | 271 | void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, struct nfs_server *, |
272 | const struct nfs4_deviceid *); | 272 | const struct nfs4_deviceid *); |
273 | struct nfs4_deviceid_node *nfs4_insert_deviceid_node(struct nfs4_deviceid_node *); | ||
274 | bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); | 273 | bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *); |
275 | void nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node); | 274 | void nfs4_mark_deviceid_unavailable(struct nfs4_deviceid_node *node); |
276 | bool nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node); | 275 | bool nfs4_test_deviceid_unavailable(struct nfs4_deviceid_node *node); |
@@ -446,10 +445,6 @@ static inline void pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
446 | { | 445 | { |
447 | } | 446 | } |
448 | 447 | ||
449 | static inline void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) | ||
450 | { | ||
451 | } | ||
452 | |||
453 | static inline int pnfs_return_layout(struct inode *ino) | 448 | static inline int pnfs_return_layout(struct inode *ino) |
454 | { | 449 | { |
455 | return 0; | 450 | return 0; |