mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn
Note that clearing NFS_INO_LAYOUTCOMMIT is tricky, since it requires you to also clear the NFS_LSEG_LAYOUTCOMMIT bits from the layout segments. The only two sites that need to do this are the ones that call pnfs_return_layout() without first doing a layout commit. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Acked-by: Benny Halevy <bhalevy@tonian.com> Cc: stable@vger.kernel.org
This commit is contained in:
		
							parent
							
								
									a073dbff35
								
							
						
					
					
						commit
						2495680434
					
				
					 2 changed files with 27 additions and 9 deletions
				
			
		|  | @ -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); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  | @ -1458,7 +1479,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 +1633,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)) | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Trond Myklebust
						Trond Myklebust