diff options
| author | Linus Torvalds <[email protected]> | 2020-04-07 13:51:39 -0700 | 
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2020-04-07 13:51:39 -0700 | 
| commit | 04de788e61a576820baf03ff8accc246ca146cb3 (patch) | |
| tree | ce7398fd61364c78b2a353729f8a92d77d02c076 /fs/nfs/flexfilelayout/flexfilelayout.c | |
| parent | f40f31cadc0ea5dcdd224c8b324add26469c2379 (diff) | |
| parent | 93ce4af774bc3d8a72ce2271d03241c96383629d (diff) | |
Merge tag 'nfs-for-5.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
 "Highlights include:
  Stable fixes:
   - Fix a page leak in nfs_destroy_unlinked_subrequests()
   - Fix use-after-free issues in nfs_pageio_add_request()
   - Fix new mount code constant_table array definitions
   - finish_automount() requires us to hold 2 refs to the mount record
  Features:
   - Improve the accuracy of telldir/seekdir by using 64-bit cookies
     when possible.
   - Allow one RDMA active connection and several zombie connections to
     prevent blocking if the remote server is unresponsive.
   - Limit the size of the NFS access cache by default
   - Reduce the number of references to credentials that are taken by
     NFS
   - pNFS files and flexfiles drivers now support per-layout segment
     COMMIT lists.
   - Enable partial-file layout segments in the pNFS/flexfiles driver.
   - Add support for CB_RECALL_ANY to the pNFS flexfiles layout type
   - pNFS/flexfiles Report NFS4ERR_DELAY and NFS4ERR_GRACE errors from
     the DS using the layouterror mechanism.
  Bugfixes and cleanups:
   - SUNRPC: Fix krb5p regressions
   - Don't specify NFS version in "UDP not supported" error
   - nfsroot: set tcp as the default transport protocol
   - pnfs: Return valid stateids in nfs_layout_find_inode_by_stateid()
   - alloc_nfs_open_context() must use the file cred when available
   - Fix locking when dereferencing the delegation cred
   - Fix memory leaks in O_DIRECT when nfs_get_lock_context() fails
   - Various clean ups of the NFS O_DIRECT commit code
   - Clean up RDMA connect/disconnect
   - Replace zero-length arrays with C99-style flexible arrays"
* tag 'nfs-for-5.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (86 commits)
  NFS: Clean up process of marking inode stale.
  SUNRPC: Don't start a timer on an already queued rpc task
  NFS/pnfs: Reference the layout cred in pnfs_prepare_layoutreturn()
  NFS/pnfs: Fix dereference of layout cred in pnfs_layoutcommit_inode()
  NFS: Beware when dereferencing the delegation cred
  NFS: Add a module parameter to set nfs_mountpoint_expiry_timeout
  NFS: finish_automount() requires us to hold 2 refs to the mount record
  NFS: Fix a few constant_table array definitions
  NFS: Try to join page groups before an O_DIRECT retransmission
  NFS: Refactor nfs_lock_and_join_requests()
  NFS: Reverse the submission order of requests in __nfs_pageio_add_request()
  NFS: Clean up nfs_lock_and_join_requests()
  NFS: Remove the redundant function nfs_pgio_has_mirroring()
  NFS: Fix memory leaks in nfs_pageio_stop_mirroring()
  NFS: Fix a request reference leak in nfs_direct_write_clear_reqs()
  NFS: Fix use-after-free issues in nfs_pageio_add_request()
  NFS: Fix races nfs_page_group_destroy() vs nfs_destroy_unlinked_subrequests()
  NFS: Fix a page leak in nfs_destroy_unlinked_subrequests()
  NFS: Remove unused FLUSH_SYNC support in nfs_initiate_pgio()
  pNFS/flexfiles: Specify the layout segment range in LAYOUTGET
  ...
Diffstat (limited to 'fs/nfs/flexfilelayout/flexfilelayout.c')
| -rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 229 | 
1 files changed, 93 insertions, 136 deletions
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index bb9148b83166..7d399f72ebbb 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -32,6 +32,7 @@  static unsigned short io_maxretrans; +static const struct pnfs_commit_ops ff_layout_commit_ops;  static void ff_layout_read_record_layoutstats_done(struct rpc_task *task,  		struct nfs_pgio_header *hdr);  static int ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo, @@ -48,9 +49,11 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)  	ffl = kzalloc(sizeof(*ffl), gfp_flags);  	if (ffl) { +		pnfs_init_ds_commit_info(&ffl->commit_info);  		INIT_LIST_HEAD(&ffl->error_list);  		INIT_LIST_HEAD(&ffl->mirrors);  		ffl->last_report_time = ktime_get(); +		ffl->commit_info.ops = &ff_layout_commit_ops;  		return &ffl->generic_hdr;  	} else  		return NULL; @@ -59,14 +62,14 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)  static void  ff_layout_free_layout_hdr(struct pnfs_layout_hdr *lo)  { +	struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(lo);  	struct nfs4_ff_layout_ds_err *err, *n; -	list_for_each_entry_safe(err, n, &FF_LAYOUT_FROM_HDR(lo)->error_list, -				 list) { +	list_for_each_entry_safe(err, n, &ffl->error_list, list) {  		list_del(&err->list);  		kfree(err);  	} -	kfree(FF_LAYOUT_FROM_HDR(lo)); +	kfree_rcu(ffl, generic_hdr.plh_rcu);  }  static int decode_pnfs_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) @@ -248,36 +251,10 @@ static void ff_layout_put_mirror(struct nfs4_ff_layout_mirror *mirror)  static void ff_layout_free_mirror_array(struct nfs4_ff_layout_segment *fls)  { -	int i; - -	if (fls->mirror_array) { -		for (i = 0; i < fls->mirror_array_cnt; i++) { -			/* normally mirror_ds is freed in -			 * .free_deviceid_node but we still do it here -			 * for .alloc_lseg error path */ -			ff_layout_put_mirror(fls->mirror_array[i]); -		} -		kfree(fls->mirror_array); -		fls->mirror_array = NULL; -	} -} - -static int ff_layout_check_layout(struct nfs4_layoutget_res *lgr) -{ -	int ret = 0; +	u32 i; -	dprintk("--> %s\n", __func__); - -	/* FIXME: remove this check when layout segment support is added */ -	if (lgr->range.offset != 0 || -	    lgr->range.length != NFS4_MAX_UINT64) { -		dprintk("%s Only whole file layouts supported. Use MDS i/o\n", -			__func__); -		ret = -EINVAL; -	} - -	dprintk("--> %s returns %d\n", __func__, ret); -	return ret; +	for (i = 0; i < fls->mirror_array_cnt; i++) +		ff_layout_put_mirror(fls->mirror_array[i]);  }  static void _ff_layout_free_lseg(struct nfs4_ff_layout_segment *fls) @@ -289,6 +266,23 @@ static void _ff_layout_free_lseg(struct nfs4_ff_layout_segment *fls)  }  static bool +ff_lseg_match_mirrors(struct pnfs_layout_segment *l1, +		struct pnfs_layout_segment *l2) +{ +	const struct nfs4_ff_layout_segment *fl1 = FF_LAYOUT_LSEG(l1); +	const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l1); +	u32 i; + +	if (fl1->mirror_array_cnt != fl2->mirror_array_cnt) +		return false; +	for (i = 0; i < fl1->mirror_array_cnt; i++) { +		if (fl1->mirror_array[i] != fl2->mirror_array[i]) +			return false; +	} +	return true; +} + +static bool  ff_lseg_range_is_after(const struct pnfs_layout_range *l1,  		const struct pnfs_layout_range *l2)  { @@ -323,6 +317,8 @@ ff_lseg_merge(struct pnfs_layout_segment *new,  			new->pls_range.length);  	if (new_end < old->pls_range.offset)  		return false; +	if (!ff_lseg_match_mirrors(new, old)) +		return false;  	/* Mergeable: copy info from 'old' to 'new' */  	if (new_end < old_end) @@ -400,16 +396,13 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,  		goto out_err_free;  	rc = -ENOMEM; -	fls = kzalloc(sizeof(*fls), gfp_flags); +	fls = kzalloc(struct_size(fls, mirror_array, mirror_array_cnt), +			gfp_flags);  	if (!fls)  		goto out_err_free;  	fls->mirror_array_cnt = mirror_array_cnt;  	fls->stripe_unit = stripe_unit; -	fls->mirror_array = kcalloc(fls->mirror_array_cnt, -				    sizeof(fls->mirror_array[0]), gfp_flags); -	if (fls->mirror_array == NULL) -		goto out_err_free;  	for (i = 0; i < fls->mirror_array_cnt; i++) {  		struct nfs4_ff_layout_mirror *mirror; @@ -545,9 +538,6 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,  out_sort_mirrors:  	ff_layout_sort_mirrors(fls); -	rc = ff_layout_check_layout(lgr); -	if (rc) -		goto out_err_free;  	ret = &fls->generic_hdr;  	dprintk("<-- %s (success)\n", __func__);  out_free_page: @@ -560,17 +550,6 @@ out_err_free:  	goto out_free_page;  } -static bool ff_layout_has_rw_segments(struct pnfs_layout_hdr *layout) -{ -	struct pnfs_layout_segment *lseg; - -	list_for_each_entry(lseg, &layout->plh_segs, pls_list) -		if (lseg->pls_range.iomode == IOMODE_RW) -			return true; - -	return false; -} -  static void  ff_layout_free_lseg(struct pnfs_layout_segment *lseg)  { @@ -585,23 +564,12 @@ ff_layout_free_lseg(struct pnfs_layout_segment *lseg)  		ffl = FF_LAYOUT_FROM_HDR(lseg->pls_layout);  		inode = ffl->generic_hdr.plh_inode;  		spin_lock(&inode->i_lock); -		if (!ff_layout_has_rw_segments(lseg->pls_layout)) { -			ffl->commit_info.nbuckets = 0; -			kfree(ffl->commit_info.buckets); -			ffl->commit_info.buckets = NULL; -		} +		pnfs_generic_ds_cinfo_release_lseg(&ffl->commit_info, lseg);  		spin_unlock(&inode->i_lock);  	}  	_ff_layout_free_lseg(fls);  } -/* Return 1 until we have multiple lsegs support */ -static int -ff_layout_get_lseg_count(struct nfs4_ff_layout_segment *fls) -{ -	return 1; -} -  static void  nfs4_ff_start_busy_timer(struct nfs4_ff_busy_timer *timer, ktime_t now)  { @@ -746,52 +714,6 @@ nfs4_ff_layout_stat_io_end_write(struct rpc_task *task,  	spin_unlock(&mirror->lock);  } -static int -ff_layout_alloc_commit_info(struct pnfs_layout_segment *lseg, -			    struct nfs_commit_info *cinfo, -			    gfp_t gfp_flags) -{ -	struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); -	struct pnfs_commit_bucket *buckets; -	int size; - -	if (cinfo->ds->nbuckets != 0) { -		/* This assumes there is only one RW lseg per file. -		 * To support multiple lseg per file, we need to -		 * change struct pnfs_commit_bucket to allow dynamic -		 * increasing nbuckets. -		 */ -		return 0; -	} - -	size = ff_layout_get_lseg_count(fls) * FF_LAYOUT_MIRROR_COUNT(lseg); - -	buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket), -			  gfp_flags); -	if (!buckets) -		return -ENOMEM; -	else { -		int i; - -		spin_lock(&cinfo->inode->i_lock); -		if (cinfo->ds->nbuckets != 0) -			kfree(buckets); -		else { -			cinfo->ds->buckets = buckets; -			cinfo->ds->nbuckets = size; -			for (i = 0; i < size; i++) { -				INIT_LIST_HEAD(&buckets[i].written); -				INIT_LIST_HEAD(&buckets[i].committing); -				/* mark direct verifier as unset */ -				buckets[i].direct_verf.committed = -					NFS_INVALID_STABLE_HOW; -			} -		} -		spin_unlock(&cinfo->inode->i_lock); -		return 0; -	} -} -  static void  ff_layout_mark_ds_unreachable(struct pnfs_layout_segment *lseg, int idx)  { @@ -876,8 +798,8 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,  	pnfs_put_lseg(pgio->pg_lseg);  	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,  					   nfs_req_openctx(req), -					   0, -					   NFS4_MAX_UINT64, +					   req_offset(req), +					   req->wb_bytes,  					   IOMODE_READ,  					   strict_iomode,  					   GFP_KERNEL); @@ -888,6 +810,14 @@ ff_layout_pg_get_read(struct nfs_pageio_descriptor *pgio,  }  static void +ff_layout_pg_check_layout(struct nfs_pageio_descriptor *pgio, +			  struct nfs_page *req) +{ +	pnfs_generic_pg_check_layout(pgio); +	pnfs_generic_pg_check_range(pgio, req); +} + +static void  ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,  			struct nfs_page *req)  { @@ -897,7 +827,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,  	int ds_idx;  retry: -	pnfs_generic_pg_check_layout(pgio); +	ff_layout_pg_check_layout(pgio, req);  	/* Use full layout for now */  	if (!pgio->pg_lseg) {  		ff_layout_pg_get_read(pgio, req, false); @@ -953,18 +883,16 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,  {  	struct nfs4_ff_layout_mirror *mirror;  	struct nfs_pgio_mirror *pgm; -	struct nfs_commit_info cinfo;  	struct nfs4_pnfs_ds *ds;  	int i; -	int status;  retry: -	pnfs_generic_pg_check_layout(pgio); +	ff_layout_pg_check_layout(pgio, req);  	if (!pgio->pg_lseg) {  		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,  						   nfs_req_openctx(req), -						   0, -						   NFS4_MAX_UINT64, +						   req_offset(req), +						   req->wb_bytes,  						   IOMODE_RW,  						   false,  						   GFP_NOFS); @@ -978,11 +906,6 @@ retry:  	if (pgio->pg_lseg == NULL)  		goto out_mds; -	nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq); -	status = ff_layout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS); -	if (status < 0) -		goto out_mds; -  	/* Use a direct mapping of ds_idx to pgio mirror_idx */  	if (WARN_ON_ONCE(pgio->pg_mirror_count !=  	    FF_LAYOUT_MIRROR_COUNT(pgio->pg_lseg))) @@ -1297,21 +1220,23 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,  		}  	} +	mirror = FF_LAYOUT_COMP(lseg, idx); +	err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), +				       mirror, offset, length, status, opnum, +				       GFP_NOIO); +  	switch (status) {  	case NFS4ERR_DELAY:  	case NFS4ERR_GRACE: -		return; -	default:  		break; +	case NFS4ERR_NXIO: +		ff_layout_mark_ds_unreachable(lseg, idx); +		/* Fallthrough */ +	default: +		pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, +						  lseg);  	} -	mirror = FF_LAYOUT_COMP(lseg, idx); -	err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), -				       mirror, offset, length, status, opnum, -				       GFP_NOIO); -	if (status == NFS4ERR_NXIO) -		ff_layout_mark_ds_unreachable(lseg, idx); -	pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, lseg);  	dprintk("%s: err %d op %d status %u\n", __func__, err, opnum, status);  } @@ -2012,6 +1937,33 @@ ff_layout_get_ds_info(struct inode *inode)  }  static void +ff_layout_setup_ds_info(struct pnfs_ds_commit_info *fl_cinfo, +		struct pnfs_layout_segment *lseg) +{ +	struct nfs4_ff_layout_segment *flseg = FF_LAYOUT_LSEG(lseg); +	struct inode *inode = lseg->pls_layout->plh_inode; +	struct pnfs_commit_array *array, *new; + +	new = pnfs_alloc_commit_array(flseg->mirror_array_cnt, GFP_NOIO); +	if (new) { +		spin_lock(&inode->i_lock); +		array = pnfs_add_commit_array(fl_cinfo, new, lseg); +		spin_unlock(&inode->i_lock); +		if (array != new) +			pnfs_free_commit_array(new); +	} +} + +static void +ff_layout_release_ds_info(struct pnfs_ds_commit_info *fl_cinfo, +		struct inode *inode) +{ +	spin_lock(&inode->i_lock); +	pnfs_generic_ds_cinfo_destroy(fl_cinfo); +	spin_unlock(&inode->i_lock); +} + +static void  ff_layout_free_deviceid_node(struct nfs4_deviceid_node *d)  {  	nfs4_ff_layout_free_deviceid(container_of(d, struct nfs4_ff_layout_ds, @@ -2496,6 +2448,16 @@ ff_layout_set_layoutdriver(struct nfs_server *server,  	return 0;  } +static const struct pnfs_commit_ops ff_layout_commit_ops = { +	.setup_ds_info		= ff_layout_setup_ds_info, +	.release_ds_info	= ff_layout_release_ds_info, +	.mark_request_commit	= pnfs_layout_mark_request_commit, +	.clear_request_commit	= pnfs_generic_clear_request_commit, +	.scan_commit_lists	= pnfs_generic_scan_commit_lists, +	.recover_commit_reqs	= pnfs_generic_recover_commit_reqs, +	.commit_pagelist	= ff_layout_commit_pagelist, +}; +  static struct pnfs_layoutdriver_type flexfilelayout_type = {  	.id			= LAYOUT_FLEX_FILES,  	.name			= "LAYOUT_FLEX_FILES", @@ -2512,11 +2474,6 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = {  	.pg_write_ops		= &ff_layout_pg_write_ops,  	.get_ds_info		= ff_layout_get_ds_info,  	.free_deviceid_node	= ff_layout_free_deviceid_node, -	.mark_request_commit	= pnfs_layout_mark_request_commit, -	.clear_request_commit	= pnfs_generic_clear_request_commit, -	.scan_commit_lists	= pnfs_generic_scan_commit_lists, -	.recover_commit_reqs	= pnfs_generic_recover_commit_reqs, -	.commit_pagelist	= ff_layout_commit_pagelist,  	.read_pagelist		= ff_layout_read_pagelist,  	.write_pagelist		= ff_layout_write_pagelist,  	.alloc_deviceid_node    = ff_layout_alloc_deviceid_node,  |