diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 76 |
1 files changed, 64 insertions, 12 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a99a8d948721..635274140b18 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3737,9 +3737,10 @@ out: | |||
3737 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) | 3737 | static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) |
3738 | { | 3738 | { |
3739 | struct nfs4_cached_acl *acl; | 3739 | struct nfs4_cached_acl *acl; |
3740 | size_t buflen = sizeof(*acl) + acl_len; | ||
3740 | 3741 | ||
3741 | if (pages && acl_len <= PAGE_SIZE) { | 3742 | if (pages && buflen <= PAGE_SIZE) { |
3742 | acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL); | 3743 | acl = kmalloc(buflen, GFP_KERNEL); |
3743 | if (acl == NULL) | 3744 | if (acl == NULL) |
3744 | goto out; | 3745 | goto out; |
3745 | acl->cached = 1; | 3746 | acl->cached = 1; |
@@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
3819 | if (ret) | 3820 | if (ret) |
3820 | goto out_free; | 3821 | goto out_free; |
3821 | 3822 | ||
3822 | acl_len = res.acl_len - res.acl_data_offset; | 3823 | acl_len = res.acl_len; |
3823 | if (acl_len > args.acl_len) | 3824 | if (acl_len > args.acl_len) |
3824 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); | 3825 | nfs4_write_cached_acl(inode, NULL, 0, acl_len); |
3825 | else | 3826 | else |
@@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) | |||
6223 | dprintk("<-- %s\n", __func__); | 6224 | dprintk("<-- %s\n", __func__); |
6224 | } | 6225 | } |
6225 | 6226 | ||
6227 | static size_t max_response_pages(struct nfs_server *server) | ||
6228 | { | ||
6229 | u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
6230 | return nfs_page_array_len(0, max_resp_sz); | ||
6231 | } | ||
6232 | |||
6233 | static void nfs4_free_pages(struct page **pages, size_t size) | ||
6234 | { | ||
6235 | int i; | ||
6236 | |||
6237 | if (!pages) | ||
6238 | return; | ||
6239 | |||
6240 | for (i = 0; i < size; i++) { | ||
6241 | if (!pages[i]) | ||
6242 | break; | ||
6243 | __free_page(pages[i]); | ||
6244 | } | ||
6245 | kfree(pages); | ||
6246 | } | ||
6247 | |||
6248 | static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags) | ||
6249 | { | ||
6250 | struct page **pages; | ||
6251 | int i; | ||
6252 | |||
6253 | pages = kcalloc(size, sizeof(struct page *), gfp_flags); | ||
6254 | if (!pages) { | ||
6255 | dprintk("%s: can't alloc array of %zu pages\n", __func__, size); | ||
6256 | return NULL; | ||
6257 | } | ||
6258 | |||
6259 | for (i = 0; i < size; i++) { | ||
6260 | pages[i] = alloc_page(gfp_flags); | ||
6261 | if (!pages[i]) { | ||
6262 | dprintk("%s: failed to allocate page\n", __func__); | ||
6263 | nfs4_free_pages(pages, size); | ||
6264 | return NULL; | ||
6265 | } | ||
6266 | } | ||
6267 | |||
6268 | return pages; | ||
6269 | } | ||
6270 | |||
6226 | static void nfs4_layoutget_release(void *calldata) | 6271 | static void nfs4_layoutget_release(void *calldata) |
6227 | { | 6272 | { |
6228 | struct nfs4_layoutget *lgp = calldata; | 6273 | struct nfs4_layoutget *lgp = calldata; |
6274 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | ||
6275 | size_t max_pages = max_response_pages(server); | ||
6229 | 6276 | ||
6230 | dprintk("--> %s\n", __func__); | 6277 | dprintk("--> %s\n", __func__); |
6278 | nfs4_free_pages(lgp->args.layout.pages, max_pages); | ||
6231 | put_nfs_open_context(lgp->args.ctx); | 6279 | put_nfs_open_context(lgp->args.ctx); |
6232 | kfree(calldata); | 6280 | kfree(calldata); |
6233 | dprintk("<-- %s\n", __func__); | 6281 | dprintk("<-- %s\n", __func__); |
@@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = { | |||
6239 | .rpc_release = nfs4_layoutget_release, | 6287 | .rpc_release = nfs4_layoutget_release, |
6240 | }; | 6288 | }; |
6241 | 6289 | ||
6242 | int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | 6290 | void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags) |
6243 | { | 6291 | { |
6244 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); | 6292 | struct nfs_server *server = NFS_SERVER(lgp->args.inode); |
6293 | size_t max_pages = max_response_pages(server); | ||
6245 | struct rpc_task *task; | 6294 | struct rpc_task *task; |
6246 | struct rpc_message msg = { | 6295 | struct rpc_message msg = { |
6247 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], | 6296 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET], |
@@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
6259 | 6308 | ||
6260 | dprintk("--> %s\n", __func__); | 6309 | dprintk("--> %s\n", __func__); |
6261 | 6310 | ||
6311 | lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags); | ||
6312 | if (!lgp->args.layout.pages) { | ||
6313 | nfs4_layoutget_release(lgp); | ||
6314 | return; | ||
6315 | } | ||
6316 | lgp->args.layout.pglen = max_pages * PAGE_SIZE; | ||
6317 | |||
6262 | lgp->res.layoutp = &lgp->args.layout; | 6318 | lgp->res.layoutp = &lgp->args.layout; |
6263 | lgp->res.seq_res.sr_slot = NULL; | 6319 | lgp->res.seq_res.sr_slot = NULL; |
6264 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); | 6320 | nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0); |
6265 | task = rpc_run_task(&task_setup_data); | 6321 | task = rpc_run_task(&task_setup_data); |
6266 | if (IS_ERR(task)) | 6322 | if (IS_ERR(task)) |
6267 | return PTR_ERR(task); | 6323 | return; |
6268 | status = nfs4_wait_for_completion_rpc_task(task); | 6324 | status = nfs4_wait_for_completion_rpc_task(task); |
6269 | if (status == 0) | 6325 | if (status == 0) |
6270 | status = task->tk_status; | 6326 | status = task->tk_status; |
@@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp) | |||
6272 | status = pnfs_layout_process(lgp); | 6328 | status = pnfs_layout_process(lgp); |
6273 | rpc_put_task(task); | 6329 | rpc_put_task(task); |
6274 | dprintk("<-- %s status=%d\n", __func__, status); | 6330 | dprintk("<-- %s status=%d\n", __func__, status); |
6275 | return status; | 6331 | return; |
6276 | } | 6332 | } |
6277 | 6333 | ||
6278 | static void | 6334 | static void |
@@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) | |||
6304 | return; | 6360 | return; |
6305 | } | 6361 | } |
6306 | spin_lock(&lo->plh_inode->i_lock); | 6362 | spin_lock(&lo->plh_inode->i_lock); |
6307 | if (task->tk_status == 0) { | 6363 | if (task->tk_status == 0 && lrp->res.lrs_present) |
6308 | if (lrp->res.lrs_present) { | 6364 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); |
6309 | pnfs_set_layout_stateid(lo, &lrp->res.stateid, true); | ||
6310 | } else | ||
6311 | BUG_ON(!list_empty(&lo->plh_segs)); | ||
6312 | } | ||
6313 | lo->plh_block_lgets--; | 6365 | lo->plh_block_lgets--; |
6314 | spin_unlock(&lo->plh_inode->i_lock); | 6366 | spin_unlock(&lo->plh_inode->i_lock); |
6315 | dprintk("<-- %s\n", __func__); | 6367 | dprintk("<-- %s\n", __func__); |