diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/blocklayout/blocklayoutdm.c | 4 | ||||
| -rw-r--r-- | fs/nfs/idmap.c | 13 | ||||
| -rw-r--r-- | fs/nfs/nfs4filelayout.c | 1 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 16 | ||||
| -rw-r--r-- | fs/nfs/pnfs.c | 81 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 6 | ||||
| -rw-r--r-- | fs/nfs/super.c | 4 | 
7 files changed, 92 insertions, 33 deletions
diff --git a/fs/nfs/blocklayout/blocklayoutdm.c b/fs/nfs/blocklayout/blocklayoutdm.c index 737d839bc17..6fc7b5cae92 100644 --- a/fs/nfs/blocklayout/blocklayoutdm.c +++ b/fs/nfs/blocklayout/blocklayoutdm.c @@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev)  	bl_pipe_msg.bl_wq = &nn->bl_wq;  	memset(msg, 0, sizeof(*msg)); -	msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS); +	msg->len = sizeof(bl_msg) + bl_msg.totallen; +	msg->data = kzalloc(msg->len, GFP_NOFS);  	if (!msg->data)  		goto out; @@ -66,7 +67,6 @@ static void dev_remove(struct net *net, dev_t dev)  	memcpy(msg->data, &bl_msg, sizeof(bl_msg));  	dataptr = (uint8_t *) msg->data;  	memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request)); -	msg->len = sizeof(bl_msg) + bl_msg.totallen;  	add_wait_queue(&nn->bl_wq, &wq);  	if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) { diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index dc0f98dfa71..c516da5873f 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -726,9 +726,9 @@ out1:  	return ret;  } -static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data) +static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)  { -	return key_instantiate_and_link(key, data, strlen(data) + 1, +	return key_instantiate_and_link(key, data, datalen,  					id_resolver_cache->thread_keyring,  					authkey);  } @@ -738,6 +738,7 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,  		struct key *key, struct key *authkey)  {  	char id_str[NFS_UINT_MAXLEN]; +	size_t len;  	int ret = -ENOKEY;  	/* ret = -ENOKEY */ @@ -747,13 +748,15 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,  	case IDMAP_CONV_NAMETOID:  		if (strcmp(upcall->im_name, im->im_name) != 0)  			break; -		sprintf(id_str, "%d", im->im_id); -		ret = nfs_idmap_instantiate(key, authkey, id_str); +		/* Note: here we store the NUL terminator too */ +		len = sprintf(id_str, "%d", im->im_id) + 1; +		ret = nfs_idmap_instantiate(key, authkey, id_str, len);  		break;  	case IDMAP_CONV_IDTONAME:  		if (upcall->im_id != im->im_id)  			break; -		ret = nfs_idmap_instantiate(key, authkey, im->im_name); +		len = strlen(im->im_name); +		ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);  		break;  	default:  		ret = -EINVAL; diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 49eeb044c10..4fb234d3aef 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo)  {  	if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))  		return; -	clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);  	pnfs_return_layout(inode);  } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b2671cb0f90..26431cf62dd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,  	int status;  	if (pnfs_ld_layoutret_on_setattr(inode)) -		pnfs_return_layout(inode); +		pnfs_commit_and_return_layout(inode);  	nfs_fattr_init(fattr); @@ -6416,22 +6416,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)  static void nfs4_layoutcommit_release(void *calldata)  {  	struct nfs4_layoutcommit_data *data = calldata; -	struct pnfs_layout_segment *lseg, *tmp; -	unsigned long *bitlock = &NFS_I(data->args.inode)->flags;  	pnfs_cleanup_layoutcommit(data); -	/* Matched by references in pnfs_set_layoutcommit */ -	list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) { -		list_del_init(&lseg->pls_lc_list); -		if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, -				       &lseg->pls_flags)) -			pnfs_put_lseg(lseg); -	} - -	clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); -	smp_mb__after_clear_bit(); -	wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); -  	put_rpccred(data->cred);  	kfree(data);  } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 48ac5aad625..4bdffe0ba02 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range,  	       lo_seg_intersecting(lseg_range, recall_range);  } +static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, +		struct list_head *tmp_list) +{ +	if (!atomic_dec_and_test(&lseg->pls_refcount)) +		return false; +	pnfs_layout_remove_lseg(lseg->pls_layout, lseg); +	list_add(&lseg->pls_list, tmp_list); +	return true; +} +  /* Returns 1 if lseg is removed from list, 0 otherwise */  static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,  			     struct list_head *tmp_list) @@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,  		 */  		dprintk("%s: lseg %p ref %d\n", __func__, lseg,  			atomic_read(&lseg->pls_refcount)); -		if (atomic_dec_and_test(&lseg->pls_refcount)) { -			pnfs_layout_remove_lseg(lseg->pls_layout, lseg); -			list_add(&lseg->pls_list, tmp_list); +		if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))  			rv = 1; -		}  	}  	return rv;  } @@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,  	return lseg;  } +static void pnfs_clear_layoutcommit(struct inode *inode, +		struct list_head *head) +{ +	struct nfs_inode *nfsi = NFS_I(inode); +	struct pnfs_layout_segment *lseg, *tmp; + +	if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) +		return; +	list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { +		if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) +			continue; +		pnfs_lseg_dec_and_remove_zero(lseg, head); +	} +} +  /*   * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr   * when the layout segment list is empty. @@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino)  	/* Reference matched in nfs4_layoutreturn_release */  	pnfs_get_layout_hdr(lo);  	empty = list_empty(&lo->plh_segs); +	pnfs_clear_layoutcommit(ino, &tmp_list);  	pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);  	/* Don't send a LAYOUTRETURN if list was initially empty */  	if (empty) { @@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino)  	spin_unlock(&ino->i_lock);  	pnfs_free_lseg_list(&tmp_list); -	WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); -  	lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);  	if (unlikely(lrp == NULL)) {  		status = -ENOMEM; @@ -845,6 +866,33 @@ out:  }  EXPORT_SYMBOL_GPL(_pnfs_return_layout); +int +pnfs_commit_and_return_layout(struct inode *inode) +{ +	struct pnfs_layout_hdr *lo; +	int ret; + +	spin_lock(&inode->i_lock); +	lo = NFS_I(inode)->layout; +	if (lo == NULL) { +		spin_unlock(&inode->i_lock); +		return 0; +	} +	pnfs_get_layout_hdr(lo); +	/* Block new layoutgets and read/write to ds */ +	lo->plh_block_lgets++; +	spin_unlock(&inode->i_lock); +	filemap_fdatawait(inode->i_mapping); +	ret = pnfs_layoutcommit_inode(inode, true); +	if (ret == 0) +		ret = _pnfs_return_layout(inode); +	spin_lock(&inode->i_lock); +	lo->plh_block_lgets--; +	spin_unlock(&inode->i_lock); +	pnfs_put_layout_hdr(lo); +	return ret; +} +  bool pnfs_roc(struct inode *ino)  {  	struct pnfs_layout_hdr *lo; @@ -1458,7 +1506,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)  	dprintk("pnfs write error = %d\n", hdr->pnfs_error);  	if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &  	    PNFS_LAYOUTRET_ON_ERROR) { -		clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);  		pnfs_return_layout(hdr->inode);  	}  	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) @@ -1613,7 +1660,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)  	dprintk("pnfs read error = %d\n", hdr->pnfs_error);  	if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &  	    PNFS_LAYOUTRET_ON_ERROR) { -		clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);  		pnfs_return_layout(hdr->inode);  	}  	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) @@ -1746,11 +1792,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)  	list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {  		if (lseg->pls_range.iomode == IOMODE_RW && -		    test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) +		    test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))  			list_add(&lseg->pls_lc_list, listp);  	}  } +static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp) +{ +	struct pnfs_layout_segment *lseg, *tmp; +	unsigned long *bitlock = &NFS_I(inode)->flags; + +	/* Matched by references in pnfs_set_layoutcommit */ +	list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) { +		list_del_init(&lseg->pls_lc_list); +		pnfs_put_lseg(lseg); +	} + +	clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock); +	smp_mb__after_clear_bit(); +	wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING); +} +  void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)  {  	pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode); @@ -1795,6 +1857,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)  	if (nfss->pnfs_curr_ld->cleanup_layoutcommit)  		nfss->pnfs_curr_ld->cleanup_layoutcommit(data); +	pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list);  }  /* diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 94ba8041774..f5f8a470a64 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata);  void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);  int pnfs_layoutcommit_inode(struct inode *inode, bool sync);  int _pnfs_return_layout(struct inode *); +int pnfs_commit_and_return_layout(struct inode *);  void pnfs_ld_write_done(struct nfs_write_data *);  void pnfs_ld_read_done(struct nfs_read_data *);  struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, @@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino)  	return 0;  } +static inline int pnfs_commit_and_return_layout(struct inode *inode) +{ +	return 0; +} +  static inline bool  pnfs_ld_layoutret_on_setattr(struct inode *inode)  { diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 17b32b72245..2f8a29db0f1 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -294,6 +294,7 @@ struct file_system_type nfs_fs_type = {  	.kill_sb	= nfs_kill_super,  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,  }; +MODULE_ALIAS_FS("nfs");  EXPORT_SYMBOL_GPL(nfs_fs_type);  struct file_system_type nfs_xdev_fs_type = { @@ -333,6 +334,8 @@ struct file_system_type nfs4_fs_type = {  	.kill_sb	= nfs_kill_super,  	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,  }; +MODULE_ALIAS_FS("nfs4"); +MODULE_ALIAS("nfs4");  EXPORT_SYMBOL_GPL(nfs4_fs_type);  static int __init register_nfs4_fs(void) @@ -2717,6 +2720,5 @@ module_param(send_implementation_id, ushort, 0644);  MODULE_PARM_DESC(send_implementation_id,  		"Send implementation ID with NFSv4.1 exchange_id");  MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string"); -MODULE_ALIAS("nfs4");  #endif /* CONFIG_NFS_V4 */  |