| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 1 | /* | 
 | 2 |  *  pNFS functions to call and manage layout drivers. | 
 | 3 |  * | 
 | 4 |  *  Copyright (c) 2002 [year of first publication] | 
 | 5 |  *  The Regents of the University of Michigan | 
 | 6 |  *  All Rights Reserved | 
 | 7 |  * | 
 | 8 |  *  Dean Hildebrand <dhildebz@umich.edu> | 
 | 9 |  * | 
 | 10 |  *  Permission is granted to use, copy, create derivative works, and | 
 | 11 |  *  redistribute this software and such derivative works for any purpose, | 
 | 12 |  *  so long as the name of the University of Michigan is not used in | 
 | 13 |  *  any advertising or publicity pertaining to the use or distribution | 
 | 14 |  *  of this software without specific, written prior authorization. If | 
 | 15 |  *  the above copyright notice or any other identification of the | 
 | 16 |  *  University of Michigan is included in any copy of any portion of | 
 | 17 |  *  this software, then the disclaimer below must also be included. | 
 | 18 |  * | 
 | 19 |  *  This software is provided as is, without representation or warranty | 
 | 20 |  *  of any kind either express or implied, including without limitation | 
 | 21 |  *  the implied warranties of merchantability, fitness for a particular | 
 | 22 |  *  purpose, or noninfringement.  The Regents of the University of | 
 | 23 |  *  Michigan shall not be liable for any damages, including special, | 
 | 24 |  *  indirect, incidental, or consequential damages, with respect to any | 
 | 25 |  *  claim arising out of or in connection with the use of the software, | 
 | 26 |  *  even if it has been or is hereafter advised of the possibility of | 
 | 27 |  *  such damages. | 
 | 28 |  */ | 
 | 29 |  | 
 | 30 | #include <linux/nfs_fs.h> | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 31 | #include <linux/nfs_page.h> | 
| Paul Gortmaker | 143cb49 | 2011-07-01 14:23:34 -0400 | [diff] [blame] | 32 | #include <linux/module.h> | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 33 | #include "internal.h" | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 34 | #include "pnfs.h" | 
| Andy Adamson | 64419a9 | 2011-03-01 01:34:16 +0000 | [diff] [blame] | 35 | #include "iostat.h" | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 36 |  | 
 | 37 | #define NFSDBG_FACILITY		NFSDBG_PNFS | 
 | 38 |  | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 39 | /* Locking: | 
 | 40 |  * | 
 | 41 |  * pnfs_spinlock: | 
 | 42 |  *      protects pnfs_modules_tbl. | 
 | 43 |  */ | 
 | 44 | static DEFINE_SPINLOCK(pnfs_spinlock); | 
 | 45 |  | 
 | 46 | /* | 
 | 47 |  * pnfs_modules_tbl holds all pnfs modules | 
 | 48 |  */ | 
 | 49 | static LIST_HEAD(pnfs_modules_tbl); | 
 | 50 |  | 
 | 51 | /* Return the registered pnfs layout driver module matching given id */ | 
 | 52 | static struct pnfs_layoutdriver_type * | 
 | 53 | find_pnfs_driver_locked(u32 id) | 
 | 54 | { | 
 | 55 | 	struct pnfs_layoutdriver_type *local; | 
 | 56 |  | 
 | 57 | 	list_for_each_entry(local, &pnfs_modules_tbl, pnfs_tblid) | 
 | 58 | 		if (local->id == id) | 
 | 59 | 			goto out; | 
 | 60 | 	local = NULL; | 
 | 61 | out: | 
 | 62 | 	dprintk("%s: Searching for id %u, found %p\n", __func__, id, local); | 
 | 63 | 	return local; | 
 | 64 | } | 
 | 65 |  | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 66 | static struct pnfs_layoutdriver_type * | 
 | 67 | find_pnfs_driver(u32 id) | 
 | 68 | { | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 69 | 	struct pnfs_layoutdriver_type *local; | 
 | 70 |  | 
 | 71 | 	spin_lock(&pnfs_spinlock); | 
 | 72 | 	local = find_pnfs_driver_locked(id); | 
 | 73 | 	spin_unlock(&pnfs_spinlock); | 
 | 74 | 	return local; | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 75 | } | 
 | 76 |  | 
 | 77 | void | 
 | 78 | unset_pnfs_layoutdriver(struct nfs_server *nfss) | 
 | 79 | { | 
| Benny Halevy | 738fd0f3 | 2011-07-30 20:52:36 -0400 | [diff] [blame] | 80 | 	if (nfss->pnfs_curr_ld) { | 
 | 81 | 		if (nfss->pnfs_curr_ld->clear_layoutdriver) | 
 | 82 | 			nfss->pnfs_curr_ld->clear_layoutdriver(nfss); | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 83 | 		module_put(nfss->pnfs_curr_ld->owner); | 
| Benny Halevy | 738fd0f3 | 2011-07-30 20:52:36 -0400 | [diff] [blame] | 84 | 	} | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 85 | 	nfss->pnfs_curr_ld = NULL; | 
 | 86 | } | 
 | 87 |  | 
 | 88 | /* | 
 | 89 |  * Try to set the server's pnfs module to the pnfs layout type specified by id. | 
 | 90 |  * Currently only one pNFS layout driver per filesystem is supported. | 
 | 91 |  * | 
 | 92 |  * @id layout type. Zero (illegal layout type) indicates pNFS not in use. | 
 | 93 |  */ | 
 | 94 | void | 
| Benny Halevy | 738fd0f3 | 2011-07-30 20:52:36 -0400 | [diff] [blame] | 95 | set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh, | 
 | 96 | 		      u32 id) | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 97 | { | 
 | 98 | 	struct pnfs_layoutdriver_type *ld_type = NULL; | 
 | 99 |  | 
 | 100 | 	if (id == 0) | 
 | 101 | 		goto out_no_driver; | 
 | 102 | 	if (!(server->nfs_client->cl_exchange_flags & | 
 | 103 | 		 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) { | 
| Weston Andros Adamson | a030889 | 2012-01-26 13:32:23 -0500 | [diff] [blame] | 104 | 		printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n", | 
 | 105 | 			__func__, id, server->nfs_client->cl_exchange_flags); | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 106 | 		goto out_no_driver; | 
 | 107 | 	} | 
 | 108 | 	ld_type = find_pnfs_driver(id); | 
 | 109 | 	if (!ld_type) { | 
 | 110 | 		request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id); | 
 | 111 | 		ld_type = find_pnfs_driver(id); | 
 | 112 | 		if (!ld_type) { | 
 | 113 | 			dprintk("%s: No pNFS module found for %u.\n", | 
 | 114 | 				__func__, id); | 
 | 115 | 			goto out_no_driver; | 
 | 116 | 		} | 
 | 117 | 	} | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 118 | 	if (!try_module_get(ld_type->owner)) { | 
 | 119 | 		dprintk("%s: Could not grab reference on module\n", __func__); | 
 | 120 | 		goto out_no_driver; | 
 | 121 | 	} | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 122 | 	server->pnfs_curr_ld = ld_type; | 
| Benny Halevy | 738fd0f3 | 2011-07-30 20:52:36 -0400 | [diff] [blame] | 123 | 	if (ld_type->set_layoutdriver | 
 | 124 | 	    && ld_type->set_layoutdriver(server, mntfh)) { | 
| Weston Andros Adamson | a030889 | 2012-01-26 13:32:23 -0500 | [diff] [blame] | 125 | 		printk(KERN_ERR "NFS: %s: Error initializing pNFS layout " | 
 | 126 | 			"driver %u.\n", __func__, id); | 
| Benny Halevy | 738fd0f3 | 2011-07-30 20:52:36 -0400 | [diff] [blame] | 127 | 		module_put(ld_type->owner); | 
 | 128 | 		goto out_no_driver; | 
 | 129 | 	} | 
| Christoph Hellwig | ea8eecd | 2011-03-01 01:34:21 +0000 | [diff] [blame] | 130 |  | 
| Ricardo Labiaga | 85e174b | 2010-10-20 00:17:58 -0400 | [diff] [blame] | 131 | 	dprintk("%s: pNFS module for %u set\n", __func__, id); | 
 | 132 | 	return; | 
 | 133 |  | 
 | 134 | out_no_driver: | 
 | 135 | 	dprintk("%s: Using NFSv4 I/O\n", __func__); | 
 | 136 | 	server->pnfs_curr_ld = NULL; | 
 | 137 | } | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 138 |  | 
 | 139 | int | 
 | 140 | pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type) | 
 | 141 | { | 
 | 142 | 	int status = -EINVAL; | 
 | 143 | 	struct pnfs_layoutdriver_type *tmp; | 
 | 144 |  | 
 | 145 | 	if (ld_type->id == 0) { | 
| Weston Andros Adamson | a030889 | 2012-01-26 13:32:23 -0500 | [diff] [blame] | 146 | 		printk(KERN_ERR "NFS: %s id 0 is reserved\n", __func__); | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 147 | 		return status; | 
 | 148 | 	} | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 149 | 	if (!ld_type->alloc_lseg || !ld_type->free_lseg) { | 
| Weston Andros Adamson | a030889 | 2012-01-26 13:32:23 -0500 | [diff] [blame] | 150 | 		printk(KERN_ERR "NFS: %s Layout driver must provide " | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 151 | 		       "alloc_lseg and free_lseg.\n", __func__); | 
 | 152 | 		return status; | 
 | 153 | 	} | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 154 |  | 
 | 155 | 	spin_lock(&pnfs_spinlock); | 
 | 156 | 	tmp = find_pnfs_driver_locked(ld_type->id); | 
 | 157 | 	if (!tmp) { | 
 | 158 | 		list_add(&ld_type->pnfs_tblid, &pnfs_modules_tbl); | 
 | 159 | 		status = 0; | 
 | 160 | 		dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id, | 
 | 161 | 			ld_type->name); | 
 | 162 | 	} else { | 
| Weston Andros Adamson | a030889 | 2012-01-26 13:32:23 -0500 | [diff] [blame] | 163 | 		printk(KERN_ERR "NFS: %s Module with id %d already loaded!\n", | 
| Fred Isaman | 02c35fc | 2010-10-20 00:17:59 -0400 | [diff] [blame] | 164 | 			__func__, ld_type->id); | 
 | 165 | 	} | 
 | 166 | 	spin_unlock(&pnfs_spinlock); | 
 | 167 |  | 
 | 168 | 	return status; | 
 | 169 | } | 
 | 170 | EXPORT_SYMBOL_GPL(pnfs_register_layoutdriver); | 
 | 171 |  | 
 | 172 | void | 
 | 173 | pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type) | 
 | 174 | { | 
 | 175 | 	dprintk("%s Deregistering id:%u\n", __func__, ld_type->id); | 
 | 176 | 	spin_lock(&pnfs_spinlock); | 
 | 177 | 	list_del(&ld_type->pnfs_tblid); | 
 | 178 | 	spin_unlock(&pnfs_spinlock); | 
 | 179 | } | 
 | 180 | EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 181 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 182 | /* | 
 | 183 |  * pNFS client layout cache | 
 | 184 |  */ | 
 | 185 |  | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 186 | /* Need to hold i_lock if caller does not already hold reference */ | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 187 | void | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 188 | get_layout_hdr(struct pnfs_layout_hdr *lo) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 189 | { | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 190 | 	atomic_inc(&lo->plh_refcount); | 
 | 191 | } | 
 | 192 |  | 
| Benny Halevy | 636fb9c | 2011-05-22 19:51:33 +0300 | [diff] [blame] | 193 | static struct pnfs_layout_hdr * | 
 | 194 | pnfs_alloc_layout_hdr(struct inode *ino, gfp_t gfp_flags) | 
 | 195 | { | 
 | 196 | 	struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; | 
 | 197 | 	return ld->alloc_layout_hdr ? ld->alloc_layout_hdr(ino, gfp_flags) : | 
 | 198 | 		kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags); | 
 | 199 | } | 
 | 200 |  | 
 | 201 | static void | 
 | 202 | pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo) | 
 | 203 | { | 
 | 204 | 	struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld; | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 205 | 	put_rpccred(lo->plh_lc_cred); | 
| Benny Halevy | 636fb9c | 2011-05-22 19:51:33 +0300 | [diff] [blame] | 206 | 	return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo); | 
 | 207 | } | 
 | 208 |  | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 209 | static void | 
 | 210 | destroy_layout_hdr(struct pnfs_layout_hdr *lo) | 
 | 211 | { | 
 | 212 | 	dprintk("%s: freeing layout cache %p\n", __func__, lo); | 
 | 213 | 	BUG_ON(!list_empty(&lo->plh_layouts)); | 
 | 214 | 	NFS_I(lo->plh_inode)->layout = NULL; | 
| Benny Halevy | 636fb9c | 2011-05-22 19:51:33 +0300 | [diff] [blame] | 215 | 	pnfs_free_layout_hdr(lo); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 216 | } | 
 | 217 |  | 
 | 218 | static void | 
 | 219 | put_layout_hdr_locked(struct pnfs_layout_hdr *lo) | 
 | 220 | { | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 221 | 	if (atomic_dec_and_test(&lo->plh_refcount)) | 
 | 222 | 		destroy_layout_hdr(lo); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 223 | } | 
 | 224 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 225 | void | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 226 | put_layout_hdr(struct pnfs_layout_hdr *lo) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 227 | { | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 228 | 	struct inode *inode = lo->plh_inode; | 
 | 229 |  | 
 | 230 | 	if (atomic_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) { | 
 | 231 | 		destroy_layout_hdr(lo); | 
 | 232 | 		spin_unlock(&inode->i_lock); | 
 | 233 | 	} | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 234 | } | 
 | 235 |  | 
 | 236 | static void | 
 | 237 | init_lseg(struct pnfs_layout_hdr *lo, struct pnfs_layout_segment *lseg) | 
 | 238 | { | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 239 | 	INIT_LIST_HEAD(&lseg->pls_list); | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 240 | 	INIT_LIST_HEAD(&lseg->pls_lc_list); | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 241 | 	atomic_set(&lseg->pls_refcount, 1); | 
 | 242 | 	smp_mb(); | 
 | 243 | 	set_bit(NFS_LSEG_VALID, &lseg->pls_flags); | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 244 | 	lseg->pls_layout = lo; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 245 | } | 
 | 246 |  | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 247 | static void free_lseg(struct pnfs_layout_segment *lseg) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 248 | { | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 249 | 	struct inode *ino = lseg->pls_layout->plh_inode; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 250 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 251 | 	NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg); | 
| Fred Isaman | 52fabd7 | 2011-01-06 11:36:18 +0000 | [diff] [blame] | 252 | 	/* Matched by get_layout_hdr in pnfs_insert_layout */ | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 253 | 	put_layout_hdr(NFS_I(ino)->layout); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 254 | } | 
 | 255 |  | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 256 | static void | 
 | 257 | put_lseg_common(struct pnfs_layout_segment *lseg) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 258 | { | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 259 | 	struct inode *inode = lseg->pls_layout->plh_inode; | 
 | 260 |  | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 261 | 	WARN_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 262 | 	list_del_init(&lseg->pls_list); | 
 | 263 | 	if (list_empty(&lseg->pls_layout->plh_segs)) { | 
 | 264 | 		set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | 
 | 265 | 		/* Matched by initial refcount set in alloc_init_layout_hdr */ | 
 | 266 | 		put_layout_hdr_locked(lseg->pls_layout); | 
 | 267 | 	} | 
 | 268 | 	rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq); | 
 | 269 | } | 
 | 270 |  | 
| Fred Isaman | bae724e | 2011-03-01 01:34:15 +0000 | [diff] [blame] | 271 | void | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 272 | put_lseg(struct pnfs_layout_segment *lseg) | 
 | 273 | { | 
 | 274 | 	struct inode *inode; | 
 | 275 |  | 
 | 276 | 	if (!lseg) | 
 | 277 | 		return; | 
 | 278 |  | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 279 | 	dprintk("%s: lseg %p ref %d valid %d\n", __func__, lseg, | 
 | 280 | 		atomic_read(&lseg->pls_refcount), | 
 | 281 | 		test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 282 | 	inode = lseg->pls_layout->plh_inode; | 
 | 283 | 	if (atomic_dec_and_lock(&lseg->pls_refcount, &inode->i_lock)) { | 
 | 284 | 		LIST_HEAD(free_me); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 285 |  | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 286 | 		put_lseg_common(lseg); | 
 | 287 | 		list_add(&lseg->pls_list, &free_me); | 
 | 288 | 		spin_unlock(&inode->i_lock); | 
 | 289 | 		pnfs_free_lseg_list(&free_me); | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 290 | 	} | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 291 | } | 
| Fred Isaman | e0c2b38 | 2011-03-23 13:27:53 +0000 | [diff] [blame] | 292 | EXPORT_SYMBOL_GPL(put_lseg); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 293 |  | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 294 | static inline u64 | 
 | 295 | end_offset(u64 start, u64 len) | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 296 | { | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 297 | 	u64 end; | 
 | 298 |  | 
 | 299 | 	end = start + len; | 
 | 300 | 	return end >= start ? end : NFS4_MAX_UINT64; | 
 | 301 | } | 
 | 302 |  | 
 | 303 | /* last octet in a range */ | 
 | 304 | static inline u64 | 
 | 305 | last_byte_offset(u64 start, u64 len) | 
 | 306 | { | 
 | 307 | 	u64 end; | 
 | 308 |  | 
 | 309 | 	BUG_ON(!len); | 
 | 310 | 	end = start + len; | 
 | 311 | 	return end > start ? end - 1 : NFS4_MAX_UINT64; | 
 | 312 | } | 
 | 313 |  | 
 | 314 | /* | 
 | 315 |  * is l2 fully contained in l1? | 
 | 316 |  *   start1                             end1 | 
 | 317 |  *   [----------------------------------) | 
 | 318 |  *           start2           end2 | 
 | 319 |  *           [----------------) | 
 | 320 |  */ | 
 | 321 | static inline int | 
 | 322 | lo_seg_contained(struct pnfs_layout_range *l1, | 
 | 323 | 		 struct pnfs_layout_range *l2) | 
 | 324 | { | 
 | 325 | 	u64 start1 = l1->offset; | 
 | 326 | 	u64 end1 = end_offset(start1, l1->length); | 
 | 327 | 	u64 start2 = l2->offset; | 
 | 328 | 	u64 end2 = end_offset(start2, l2->length); | 
 | 329 |  | 
 | 330 | 	return (start1 <= start2) && (end1 >= end2); | 
 | 331 | } | 
 | 332 |  | 
 | 333 | /* | 
 | 334 |  * is l1 and l2 intersecting? | 
 | 335 |  *   start1                             end1 | 
 | 336 |  *   [----------------------------------) | 
 | 337 |  *                              start2           end2 | 
 | 338 |  *                              [----------------) | 
 | 339 |  */ | 
 | 340 | static inline int | 
 | 341 | lo_seg_intersecting(struct pnfs_layout_range *l1, | 
 | 342 | 		    struct pnfs_layout_range *l2) | 
 | 343 | { | 
 | 344 | 	u64 start1 = l1->offset; | 
 | 345 | 	u64 end1 = end_offset(start1, l1->length); | 
 | 346 | 	u64 start2 = l2->offset; | 
 | 347 | 	u64 end2 = end_offset(start2, l2->length); | 
 | 348 |  | 
 | 349 | 	return (end1 == NFS4_MAX_UINT64 || end1 > start2) && | 
 | 350 | 	       (end2 == NFS4_MAX_UINT64 || end2 > start1); | 
 | 351 | } | 
 | 352 |  | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 353 | static bool | 
| Benny Halevy | 778b550 | 2011-05-22 19:48:02 +0300 | [diff] [blame] | 354 | should_free_lseg(struct pnfs_layout_range *lseg_range, | 
 | 355 | 		 struct pnfs_layout_range *recall_range) | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 356 | { | 
| Benny Halevy | 778b550 | 2011-05-22 19:48:02 +0300 | [diff] [blame] | 357 | 	return (recall_range->iomode == IOMODE_ANY || | 
 | 358 | 		lseg_range->iomode == recall_range->iomode) && | 
 | 359 | 	       lo_seg_intersecting(lseg_range, recall_range); | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 360 | } | 
 | 361 |  | 
 | 362 | /* Returns 1 if lseg is removed from list, 0 otherwise */ | 
 | 363 | static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | 
 | 364 | 			     struct list_head *tmp_list) | 
 | 365 | { | 
 | 366 | 	int rv = 0; | 
 | 367 |  | 
 | 368 | 	if (test_and_clear_bit(NFS_LSEG_VALID, &lseg->pls_flags)) { | 
 | 369 | 		/* Remove the reference keeping the lseg in the | 
 | 370 | 		 * list.  It will now be removed when all | 
 | 371 | 		 * outstanding io is finished. | 
 | 372 | 		 */ | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 373 | 		dprintk("%s: lseg %p ref %d\n", __func__, lseg, | 
 | 374 | 			atomic_read(&lseg->pls_refcount)); | 
 | 375 | 		if (atomic_dec_and_test(&lseg->pls_refcount)) { | 
 | 376 | 			put_lseg_common(lseg); | 
 | 377 | 			list_add(&lseg->pls_list, tmp_list); | 
 | 378 | 			rv = 1; | 
 | 379 | 		} | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 380 | 	} | 
 | 381 | 	return rv; | 
 | 382 | } | 
 | 383 |  | 
 | 384 | /* Returns count of number of matching invalid lsegs remaining in list | 
 | 385 |  * after call. | 
 | 386 |  */ | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 387 | int | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 388 | mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | 
 | 389 | 			    struct list_head *tmp_list, | 
| Benny Halevy | 778b550 | 2011-05-22 19:48:02 +0300 | [diff] [blame] | 390 | 			    struct pnfs_layout_range *recall_range) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 391 | { | 
 | 392 | 	struct pnfs_layout_segment *lseg, *next; | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 393 | 	int invalid = 0, removed = 0; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 394 |  | 
 | 395 | 	dprintk("%s:Begin lo %p\n", __func__, lo); | 
 | 396 |  | 
| Fred Isaman | 3851172 | 2011-02-03 18:28:50 +0000 | [diff] [blame] | 397 | 	if (list_empty(&lo->plh_segs)) { | 
 | 398 | 		if (!test_and_set_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) | 
 | 399 | 			put_layout_hdr_locked(lo); | 
 | 400 | 		return 0; | 
 | 401 | 	} | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 402 | 	list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 
| Benny Halevy | 778b550 | 2011-05-22 19:48:02 +0300 | [diff] [blame] | 403 | 		if (!recall_range || | 
 | 404 | 		    should_free_lseg(&lseg->pls_range, recall_range)) { | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 405 | 			dprintk("%s: freeing lseg %p iomode %d " | 
 | 406 | 				"offset %llu length %llu\n", __func__, | 
 | 407 | 				lseg, lseg->pls_range.iomode, lseg->pls_range.offset, | 
 | 408 | 				lseg->pls_range.length); | 
 | 409 | 			invalid++; | 
 | 410 | 			removed += mark_lseg_invalid(lseg, tmp_list); | 
 | 411 | 		} | 
 | 412 | 	dprintk("%s:Return %i\n", __func__, invalid - removed); | 
 | 413 | 	return invalid - removed; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 414 | } | 
 | 415 |  | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 416 | /* note free_me must contain lsegs from a single layout_hdr */ | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 417 | void | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 418 | pnfs_free_lseg_list(struct list_head *free_me) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 419 | { | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 420 | 	struct pnfs_layout_segment *lseg, *tmp; | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 421 | 	struct pnfs_layout_hdr *lo; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 422 |  | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 423 | 	if (list_empty(free_me)) | 
 | 424 | 		return; | 
 | 425 |  | 
 | 426 | 	lo = list_first_entry(free_me, struct pnfs_layout_segment, | 
 | 427 | 			      pls_list)->pls_layout; | 
 | 428 |  | 
 | 429 | 	if (test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags)) { | 
 | 430 | 		struct nfs_client *clp; | 
 | 431 |  | 
 | 432 | 		clp = NFS_SERVER(lo->plh_inode)->nfs_client; | 
 | 433 | 		spin_lock(&clp->cl_lock); | 
 | 434 | 		list_del_init(&lo->plh_layouts); | 
 | 435 | 		spin_unlock(&clp->cl_lock); | 
 | 436 | 	} | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 437 | 	list_for_each_entry_safe(lseg, tmp, free_me, pls_list) { | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 438 | 		list_del(&lseg->pls_list); | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 439 | 		free_lseg(lseg); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 440 | 	} | 
 | 441 | } | 
 | 442 |  | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 443 | void | 
 | 444 | pnfs_destroy_layout(struct nfs_inode *nfsi) | 
 | 445 | { | 
 | 446 | 	struct pnfs_layout_hdr *lo; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 447 | 	LIST_HEAD(tmp_list); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 448 |  | 
 | 449 | 	spin_lock(&nfsi->vfs_inode.i_lock); | 
 | 450 | 	lo = nfsi->layout; | 
 | 451 | 	if (lo) { | 
| Fred Isaman | 3851172 | 2011-02-03 18:28:50 +0000 | [diff] [blame] | 452 | 		lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ | 
| Benny Halevy | 778b550 | 2011-05-22 19:48:02 +0300 | [diff] [blame] | 453 | 		mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 454 | 	} | 
 | 455 | 	spin_unlock(&nfsi->vfs_inode.i_lock); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 456 | 	pnfs_free_lseg_list(&tmp_list); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 457 | } | 
 | 458 |  | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 459 | /* | 
 | 460 |  * Called by the state manger to remove all layouts established under an | 
 | 461 |  * expired lease. | 
 | 462 |  */ | 
 | 463 | void | 
 | 464 | pnfs_destroy_all_layouts(struct nfs_client *clp) | 
 | 465 | { | 
| Weston Andros Adamson | 6382a44 | 2011-06-01 16:44:44 -0400 | [diff] [blame] | 466 | 	struct nfs_server *server; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 467 | 	struct pnfs_layout_hdr *lo; | 
 | 468 | 	LIST_HEAD(tmp_list); | 
 | 469 |  | 
| Andy Adamson | c47abcf | 2011-06-15 17:52:40 -0400 | [diff] [blame] | 470 | 	nfs4_deviceid_mark_client_invalid(clp); | 
 | 471 | 	nfs4_deviceid_purge_client(clp); | 
 | 472 |  | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 473 | 	spin_lock(&clp->cl_lock); | 
| Weston Andros Adamson | 6382a44 | 2011-06-01 16:44:44 -0400 | [diff] [blame] | 474 | 	rcu_read_lock(); | 
 | 475 | 	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { | 
 | 476 | 		if (!list_empty(&server->layouts)) | 
 | 477 | 			list_splice_init(&server->layouts, &tmp_list); | 
 | 478 | 	} | 
 | 479 | 	rcu_read_unlock(); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 480 | 	spin_unlock(&clp->cl_lock); | 
 | 481 |  | 
 | 482 | 	while (!list_empty(&tmp_list)) { | 
 | 483 | 		lo = list_entry(tmp_list.next, struct pnfs_layout_hdr, | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 484 | 				plh_layouts); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 485 | 		dprintk("%s freeing layout for inode %lu\n", __func__, | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 486 | 			lo->plh_inode->i_ino); | 
| Andy Adamson | 2887fe4 | 2011-05-11 01:19:58 -0400 | [diff] [blame] | 487 | 		list_del_init(&lo->plh_layouts); | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 488 | 		pnfs_destroy_layout(NFS_I(lo->plh_inode)); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 489 | 	} | 
 | 490 | } | 
 | 491 |  | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 492 | /* update lo->plh_stateid with new if is more recent */ | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 493 | void | 
 | 494 | pnfs_set_layout_stateid(struct pnfs_layout_hdr *lo, const nfs4_stateid *new, | 
 | 495 | 			bool update_barrier) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 496 | { | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 497 | 	u32 oldseq, newseq; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 498 |  | 
| Trond Myklebust | 2d2f24a | 2012-03-04 18:13:57 -0500 | [diff] [blame] | 499 | 	oldseq = be32_to_cpu(lo->plh_stateid.seqid); | 
 | 500 | 	newseq = be32_to_cpu(new->seqid); | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 501 | 	if ((int)(newseq - oldseq) > 0) { | 
| Trond Myklebust | f597c53 | 2012-03-04 18:13:56 -0500 | [diff] [blame] | 502 | 		nfs4_stateid_copy(&lo->plh_stateid, new); | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 503 | 		if (update_barrier) { | 
| Trond Myklebust | 2d2f24a | 2012-03-04 18:13:57 -0500 | [diff] [blame] | 504 | 			u32 new_barrier = be32_to_cpu(new->seqid); | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 505 |  | 
 | 506 | 			if ((int)(new_barrier - lo->plh_barrier)) | 
 | 507 | 				lo->plh_barrier = new_barrier; | 
 | 508 | 		} else { | 
 | 509 | 			/* Because of wraparound, we want to keep the barrier | 
 | 510 | 			 * "close" to the current seqids.  It needs to be | 
 | 511 | 			 * within 2**31 to count as "behind", so if it | 
 | 512 | 			 * gets too near that limit, give us a litle leeway | 
 | 513 | 			 * and bring it to within 2**30. | 
 | 514 | 			 * NOTE - and yes, this is all unsigned arithmetic. | 
 | 515 | 			 */ | 
 | 516 | 			if (unlikely((newseq - lo->plh_barrier) > (3 << 29))) | 
 | 517 | 				lo->plh_barrier = newseq - (1 << 30); | 
 | 518 | 		} | 
 | 519 | 	} | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 520 | } | 
 | 521 |  | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 522 | /* lget is set to 1 if called from inside send_layoutget call chain */ | 
 | 523 | static bool | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 524 | pnfs_layoutgets_blocked(struct pnfs_layout_hdr *lo, nfs4_stateid *stateid, | 
 | 525 | 			int lget) | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 526 | { | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 527 | 	if ((stateid) && | 
| Trond Myklebust | 2d2f24a | 2012-03-04 18:13:57 -0500 | [diff] [blame] | 528 | 	    (int)(lo->plh_barrier - be32_to_cpu(stateid->seqid)) >= 0) | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 529 | 		return true; | 
| Fred Isaman | f7e8917 | 2011-01-06 11:36:32 +0000 | [diff] [blame] | 530 | 	return lo->plh_block_lgets || | 
| Fred Isaman | 3851172 | 2011-02-03 18:28:50 +0000 | [diff] [blame] | 531 | 		test_bit(NFS_LAYOUT_DESTROYED, &lo->plh_flags) || | 
| Fred Isaman | f7e8917 | 2011-01-06 11:36:32 +0000 | [diff] [blame] | 532 | 		test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags) || | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 533 | 		(list_empty(&lo->plh_segs) && | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 534 | 		 (atomic_read(&lo->plh_outstanding) > lget)); | 
 | 535 | } | 
 | 536 |  | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 537 | int | 
 | 538 | pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | 
 | 539 | 			      struct nfs4_state *open_state) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 540 | { | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 541 | 	int status = 0; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 542 |  | 
 | 543 | 	dprintk("--> %s\n", __func__); | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 544 | 	spin_lock(&lo->plh_inode->i_lock); | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 545 | 	if (pnfs_layoutgets_blocked(lo, NULL, 1)) { | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 546 | 		status = -EAGAIN; | 
 | 547 | 	} else if (list_empty(&lo->plh_segs)) { | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 548 | 		int seq; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 549 |  | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 550 | 		do { | 
 | 551 | 			seq = read_seqbegin(&open_state->seqlock); | 
| Trond Myklebust | f597c53 | 2012-03-04 18:13:56 -0500 | [diff] [blame] | 552 | 			nfs4_stateid_copy(dst, &open_state->stateid); | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 553 | 		} while (read_seqretry(&open_state->seqlock, seq)); | 
 | 554 | 	} else | 
| Trond Myklebust | f597c53 | 2012-03-04 18:13:56 -0500 | [diff] [blame] | 555 | 		nfs4_stateid_copy(dst, &lo->plh_stateid); | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 556 | 	spin_unlock(&lo->plh_inode->i_lock); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 557 | 	dprintk("<-- %s\n", __func__); | 
| Fred Isaman | fd6002e | 2011-01-06 11:36:22 +0000 | [diff] [blame] | 558 | 	return status; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 559 | } | 
 | 560 |  | 
 | 561 | /* | 
 | 562 | * Get layout from server. | 
 | 563 | *    for now, assume that whole file layouts are requested. | 
 | 564 | *    arg->offset: 0 | 
 | 565 | *    arg->length: all ones | 
 | 566 | */ | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 567 | static struct pnfs_layout_segment * | 
 | 568 | send_layoutget(struct pnfs_layout_hdr *lo, | 
 | 569 | 	   struct nfs_open_context *ctx, | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 570 | 	   struct pnfs_layout_range *range, | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 571 | 	   gfp_t gfp_flags) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 572 | { | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 573 | 	struct inode *ino = lo->plh_inode; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 574 | 	struct nfs_server *server = NFS_SERVER(ino); | 
 | 575 | 	struct nfs4_layoutget *lgp; | 
 | 576 | 	struct pnfs_layout_segment *lseg = NULL; | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 577 | 	struct page **pages = NULL; | 
 | 578 | 	int i; | 
 | 579 | 	u32 max_resp_sz, max_pages; | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 580 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 581 | 	dprintk("--> %s\n", __func__); | 
 | 582 |  | 
 | 583 | 	BUG_ON(ctx == NULL); | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 584 | 	lgp = kzalloc(sizeof(*lgp), gfp_flags); | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 585 | 	if (lgp == NULL) | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 586 | 		return NULL; | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 587 |  | 
 | 588 | 	/* allocate pages for xdr post processing */ | 
 | 589 | 	max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 
 | 590 | 	max_pages = max_resp_sz >> PAGE_SHIFT; | 
 | 591 |  | 
| Trond Myklebust | 7d9dea9 | 2012-01-20 18:57:02 -0500 | [diff] [blame] | 592 | 	pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 593 | 	if (!pages) | 
 | 594 | 		goto out_err_free; | 
 | 595 |  | 
 | 596 | 	for (i = 0; i < max_pages; i++) { | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 597 | 		pages[i] = alloc_page(gfp_flags); | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 598 | 		if (!pages[i]) | 
 | 599 | 			goto out_err_free; | 
 | 600 | 	} | 
 | 601 |  | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 602 | 	lgp->args.minlength = PAGE_CACHE_SIZE; | 
 | 603 | 	if (lgp->args.minlength > range->length) | 
 | 604 | 		lgp->args.minlength = range->length; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 605 | 	lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 606 | 	lgp->args.range = *range; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 607 | 	lgp->args.type = server->pnfs_curr_ld->id; | 
 | 608 | 	lgp->args.inode = ino; | 
 | 609 | 	lgp->args.ctx = get_nfs_open_context(ctx); | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 610 | 	lgp->args.layout.pages = pages; | 
 | 611 | 	lgp->args.layout.pglen = max_pages * PAGE_SIZE; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 612 | 	lgp->lsegpp = &lseg; | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 613 | 	lgp->gfp_flags = gfp_flags; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 614 |  | 
 | 615 | 	/* Synchronously retrieve layout information from server and | 
 | 616 | 	 * store in lseg. | 
 | 617 | 	 */ | 
 | 618 | 	nfs4_proc_layoutget(lgp); | 
 | 619 | 	if (!lseg) { | 
 | 620 | 		/* remember that LAYOUTGET failed and suspend trying */ | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 621 | 		set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 622 | 	} | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 623 |  | 
 | 624 | 	/* free xdr pages */ | 
 | 625 | 	for (i = 0; i < max_pages; i++) | 
 | 626 | 		__free_page(pages[i]); | 
 | 627 | 	kfree(pages); | 
 | 628 |  | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 629 | 	return lseg; | 
| Weston Andros Adamson | 35124a0 | 2011-03-24 16:48:21 -0400 | [diff] [blame] | 630 |  | 
 | 631 | out_err_free: | 
 | 632 | 	/* free any allocated xdr pages, lgp as it's not used */ | 
 | 633 | 	if (pages) { | 
 | 634 | 		for (i = 0; i < max_pages; i++) { | 
 | 635 | 			if (!pages[i]) | 
 | 636 | 				break; | 
 | 637 | 			__free_page(pages[i]); | 
 | 638 | 		} | 
 | 639 | 		kfree(pages); | 
 | 640 | 	} | 
 | 641 | 	kfree(lgp); | 
 | 642 | 	return NULL; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 643 | } | 
 | 644 |  | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 645 | /* Initiates a LAYOUTRETURN(FILE) */ | 
 | 646 | int | 
 | 647 | _pnfs_return_layout(struct inode *ino) | 
 | 648 | { | 
 | 649 | 	struct pnfs_layout_hdr *lo = NULL; | 
 | 650 | 	struct nfs_inode *nfsi = NFS_I(ino); | 
 | 651 | 	LIST_HEAD(tmp_list); | 
 | 652 | 	struct nfs4_layoutreturn *lrp; | 
 | 653 | 	nfs4_stateid stateid; | 
 | 654 | 	int status = 0; | 
 | 655 |  | 
 | 656 | 	dprintk("--> %s\n", __func__); | 
 | 657 |  | 
 | 658 | 	spin_lock(&ino->i_lock); | 
 | 659 | 	lo = nfsi->layout; | 
| Fred Isaman | a2e1d4f | 2011-06-13 18:54:53 -0400 | [diff] [blame] | 660 | 	if (!lo) { | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 661 | 		spin_unlock(&ino->i_lock); | 
| Fred Isaman | a2e1d4f | 2011-06-13 18:54:53 -0400 | [diff] [blame] | 662 | 		dprintk("%s: no layout to return\n", __func__); | 
 | 663 | 		return status; | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 664 | 	} | 
 | 665 | 	stateid = nfsi->layout->plh_stateid; | 
 | 666 | 	/* Reference matched in nfs4_layoutreturn_release */ | 
 | 667 | 	get_layout_hdr(lo); | 
| Fred Isaman | ea0ded7 | 2011-06-15 12:31:02 -0400 | [diff] [blame] | 668 | 	mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | 
 | 669 | 	lo->plh_block_lgets++; | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 670 | 	spin_unlock(&ino->i_lock); | 
 | 671 | 	pnfs_free_lseg_list(&tmp_list); | 
 | 672 |  | 
 | 673 | 	WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); | 
 | 674 |  | 
 | 675 | 	lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); | 
 | 676 | 	if (unlikely(lrp == NULL)) { | 
 | 677 | 		status = -ENOMEM; | 
| Fred Isaman | 9e2dfdb | 2011-06-15 14:32:02 -0400 | [diff] [blame] | 678 | 		set_bit(NFS_LAYOUT_RW_FAILED, &lo->plh_flags); | 
 | 679 | 		set_bit(NFS_LAYOUT_RO_FAILED, &lo->plh_flags); | 
| Benny Halevy | 1ed3a85 | 2011-06-15 11:39:57 -0400 | [diff] [blame] | 680 | 		put_layout_hdr(lo); | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 681 | 		goto out; | 
 | 682 | 	} | 
 | 683 |  | 
 | 684 | 	lrp->args.stateid = stateid; | 
 | 685 | 	lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id; | 
 | 686 | 	lrp->args.inode = ino; | 
| Trond Myklebust | a56aaa0 | 2011-06-15 11:59:10 -0400 | [diff] [blame] | 687 | 	lrp->args.layout = lo; | 
| Benny Halevy | cbe8260 | 2011-05-22 19:52:37 +0300 | [diff] [blame] | 688 | 	lrp->clp = NFS_SERVER(ino)->nfs_client; | 
 | 689 |  | 
 | 690 | 	status = nfs4_proc_layoutreturn(lrp); | 
 | 691 | out: | 
 | 692 | 	dprintk("<-- %s status: %d\n", __func__, status); | 
 | 693 | 	return status; | 
 | 694 | } | 
 | 695 |  | 
| Fred Isaman | f7e8917 | 2011-01-06 11:36:32 +0000 | [diff] [blame] | 696 | bool pnfs_roc(struct inode *ino) | 
 | 697 | { | 
 | 698 | 	struct pnfs_layout_hdr *lo; | 
 | 699 | 	struct pnfs_layout_segment *lseg, *tmp; | 
 | 700 | 	LIST_HEAD(tmp_list); | 
 | 701 | 	bool found = false; | 
 | 702 |  | 
 | 703 | 	spin_lock(&ino->i_lock); | 
 | 704 | 	lo = NFS_I(ino)->layout; | 
 | 705 | 	if (!lo || !test_and_clear_bit(NFS_LAYOUT_ROC, &lo->plh_flags) || | 
 | 706 | 	    test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) | 
 | 707 | 		goto out_nolayout; | 
 | 708 | 	list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list) | 
 | 709 | 		if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { | 
 | 710 | 			mark_lseg_invalid(lseg, &tmp_list); | 
 | 711 | 			found = true; | 
 | 712 | 		} | 
 | 713 | 	if (!found) | 
 | 714 | 		goto out_nolayout; | 
 | 715 | 	lo->plh_block_lgets++; | 
 | 716 | 	get_layout_hdr(lo); /* matched in pnfs_roc_release */ | 
 | 717 | 	spin_unlock(&ino->i_lock); | 
 | 718 | 	pnfs_free_lseg_list(&tmp_list); | 
 | 719 | 	return true; | 
 | 720 |  | 
 | 721 | out_nolayout: | 
 | 722 | 	spin_unlock(&ino->i_lock); | 
 | 723 | 	return false; | 
 | 724 | } | 
 | 725 |  | 
 | 726 | void pnfs_roc_release(struct inode *ino) | 
 | 727 | { | 
 | 728 | 	struct pnfs_layout_hdr *lo; | 
 | 729 |  | 
 | 730 | 	spin_lock(&ino->i_lock); | 
 | 731 | 	lo = NFS_I(ino)->layout; | 
 | 732 | 	lo->plh_block_lgets--; | 
 | 733 | 	put_layout_hdr_locked(lo); | 
 | 734 | 	spin_unlock(&ino->i_lock); | 
 | 735 | } | 
 | 736 |  | 
 | 737 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier) | 
 | 738 | { | 
 | 739 | 	struct pnfs_layout_hdr *lo; | 
 | 740 |  | 
 | 741 | 	spin_lock(&ino->i_lock); | 
 | 742 | 	lo = NFS_I(ino)->layout; | 
 | 743 | 	if ((int)(barrier - lo->plh_barrier) > 0) | 
 | 744 | 		lo->plh_barrier = barrier; | 
 | 745 | 	spin_unlock(&ino->i_lock); | 
 | 746 | } | 
 | 747 |  | 
 | 748 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier) | 
 | 749 | { | 
 | 750 | 	struct nfs_inode *nfsi = NFS_I(ino); | 
 | 751 | 	struct pnfs_layout_segment *lseg; | 
 | 752 | 	bool found = false; | 
 | 753 |  | 
 | 754 | 	spin_lock(&ino->i_lock); | 
 | 755 | 	list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) | 
 | 756 | 		if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { | 
 | 757 | 			found = true; | 
 | 758 | 			break; | 
 | 759 | 		} | 
 | 760 | 	if (!found) { | 
 | 761 | 		struct pnfs_layout_hdr *lo = nfsi->layout; | 
| Trond Myklebust | 2d2f24a | 2012-03-04 18:13:57 -0500 | [diff] [blame] | 762 | 		u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid); | 
| Fred Isaman | f7e8917 | 2011-01-06 11:36:32 +0000 | [diff] [blame] | 763 |  | 
 | 764 | 		/* Since close does not return a layout stateid for use as | 
 | 765 | 		 * a barrier, we choose the worst-case barrier. | 
 | 766 | 		 */ | 
 | 767 | 		*barrier = current_seqid + atomic_read(&lo->plh_outstanding); | 
 | 768 | 	} | 
 | 769 | 	spin_unlock(&ino->i_lock); | 
 | 770 | 	return found; | 
 | 771 | } | 
 | 772 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 773 | /* | 
 | 774 |  * Compare two layout segments for sorting into layout cache. | 
 | 775 |  * We want to preferentially return RW over RO layouts, so ensure those | 
 | 776 |  * are seen first. | 
 | 777 |  */ | 
 | 778 | static s64 | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 779 | cmp_layout(struct pnfs_layout_range *l1, | 
 | 780 | 	   struct pnfs_layout_range *l2) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 781 | { | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 782 | 	s64 d; | 
 | 783 |  | 
 | 784 | 	/* high offset > low offset */ | 
 | 785 | 	d = l1->offset - l2->offset; | 
 | 786 | 	if (d) | 
 | 787 | 		return d; | 
 | 788 |  | 
 | 789 | 	/* short length > long length */ | 
 | 790 | 	d = l2->length - l1->length; | 
 | 791 | 	if (d) | 
 | 792 | 		return d; | 
 | 793 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 794 | 	/* read > read/write */ | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 795 | 	return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 796 | } | 
 | 797 |  | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 798 | static void | 
 | 799 | pnfs_insert_layout(struct pnfs_layout_hdr *lo, | 
 | 800 | 		   struct pnfs_layout_segment *lseg) | 
 | 801 | { | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 802 | 	struct pnfs_layout_segment *lp; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 803 |  | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 804 | 	dprintk("%s:Begin\n", __func__); | 
 | 805 |  | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 806 | 	assert_spin_locked(&lo->plh_inode->i_lock); | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 807 | 	list_for_each_entry(lp, &lo->plh_segs, pls_list) { | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 808 | 		if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 809 | 			continue; | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 810 | 		list_add_tail(&lseg->pls_list, &lp->pls_list); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 811 | 		dprintk("%s: inserted lseg %p " | 
 | 812 | 			"iomode %d offset %llu length %llu before " | 
 | 813 | 			"lp %p iomode %d offset %llu length %llu\n", | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 814 | 			__func__, lseg, lseg->pls_range.iomode, | 
 | 815 | 			lseg->pls_range.offset, lseg->pls_range.length, | 
 | 816 | 			lp, lp->pls_range.iomode, lp->pls_range.offset, | 
 | 817 | 			lp->pls_range.length); | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 818 | 		goto out; | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 819 | 	} | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 820 | 	list_add_tail(&lseg->pls_list, &lo->plh_segs); | 
 | 821 | 	dprintk("%s: inserted lseg %p " | 
 | 822 | 		"iomode %d offset %llu length %llu at tail\n", | 
 | 823 | 		__func__, lseg, lseg->pls_range.iomode, | 
 | 824 | 		lseg->pls_range.offset, lseg->pls_range.length); | 
 | 825 | out: | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 826 | 	get_layout_hdr(lo); | 
| Andy Adamson | 974cec8 | 2010-10-20 00:18:02 -0400 | [diff] [blame] | 827 |  | 
 | 828 | 	dprintk("%s:Return\n", __func__); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 829 | } | 
 | 830 |  | 
 | 831 | static struct pnfs_layout_hdr * | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 832 | alloc_init_layout_hdr(struct inode *ino, | 
 | 833 | 		      struct nfs_open_context *ctx, | 
 | 834 | 		      gfp_t gfp_flags) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 835 | { | 
 | 836 | 	struct pnfs_layout_hdr *lo; | 
 | 837 |  | 
| Benny Halevy | 636fb9c | 2011-05-22 19:51:33 +0300 | [diff] [blame] | 838 | 	lo = pnfs_alloc_layout_hdr(ino, gfp_flags); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 839 | 	if (!lo) | 
 | 840 | 		return NULL; | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 841 | 	atomic_set(&lo->plh_refcount, 1); | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 842 | 	INIT_LIST_HEAD(&lo->plh_layouts); | 
 | 843 | 	INIT_LIST_HEAD(&lo->plh_segs); | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 844 | 	INIT_LIST_HEAD(&lo->plh_bulk_recall); | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 845 | 	lo->plh_inode = ino; | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 846 | 	lo->plh_lc_cred = get_rpccred(ctx->state->owner->so_cred); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 847 | 	return lo; | 
 | 848 | } | 
 | 849 |  | 
 | 850 | static struct pnfs_layout_hdr * | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 851 | pnfs_find_alloc_layout(struct inode *ino, | 
 | 852 | 		       struct nfs_open_context *ctx, | 
 | 853 | 		       gfp_t gfp_flags) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 854 | { | 
 | 855 | 	struct nfs_inode *nfsi = NFS_I(ino); | 
 | 856 | 	struct pnfs_layout_hdr *new = NULL; | 
 | 857 |  | 
 | 858 | 	dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout); | 
 | 859 |  | 
 | 860 | 	assert_spin_locked(&ino->i_lock); | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 861 | 	if (nfsi->layout) { | 
 | 862 | 		if (test_bit(NFS_LAYOUT_DESTROYED, &nfsi->layout->plh_flags)) | 
 | 863 | 			return NULL; | 
 | 864 | 		else | 
 | 865 | 			return nfsi->layout; | 
 | 866 | 	} | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 867 | 	spin_unlock(&ino->i_lock); | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 868 | 	new = alloc_init_layout_hdr(ino, ctx, gfp_flags); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 869 | 	spin_lock(&ino->i_lock); | 
 | 870 |  | 
 | 871 | 	if (likely(nfsi->layout == NULL))	/* Won the race? */ | 
 | 872 | 		nfsi->layout = new; | 
 | 873 | 	else | 
| Benny Halevy | 636fb9c | 2011-05-22 19:51:33 +0300 | [diff] [blame] | 874 | 		pnfs_free_layout_hdr(new); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 875 | 	return nfsi->layout; | 
 | 876 | } | 
 | 877 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 878 | /* | 
 | 879 |  * iomode matching rules: | 
 | 880 |  * iomode	lseg	match | 
 | 881 |  * -----	-----	----- | 
 | 882 |  * ANY		READ	true | 
 | 883 |  * ANY		RW	true | 
 | 884 |  * RW		READ	false | 
 | 885 |  * RW		RW	true | 
 | 886 |  * READ		READ	true | 
 | 887 |  * READ		RW	true | 
 | 888 |  */ | 
 | 889 | static int | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 890 | is_matching_lseg(struct pnfs_layout_range *ls_range, | 
 | 891 | 		 struct pnfs_layout_range *range) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 892 | { | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 893 | 	struct pnfs_layout_range range1; | 
 | 894 |  | 
 | 895 | 	if ((range->iomode == IOMODE_RW && | 
 | 896 | 	     ls_range->iomode != IOMODE_RW) || | 
 | 897 | 	    !lo_seg_intersecting(ls_range, range)) | 
 | 898 | 		return 0; | 
 | 899 |  | 
 | 900 | 	/* range1 covers only the first byte in the range */ | 
 | 901 | 	range1 = *range; | 
 | 902 | 	range1.length = 1; | 
 | 903 | 	return lo_seg_contained(ls_range, &range1); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 904 | } | 
 | 905 |  | 
 | 906 | /* | 
 | 907 |  * lookup range in layout | 
 | 908 |  */ | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 909 | static struct pnfs_layout_segment * | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 910 | pnfs_find_lseg(struct pnfs_layout_hdr *lo, | 
 | 911 | 		struct pnfs_layout_range *range) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 912 | { | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 913 | 	struct pnfs_layout_segment *lseg, *ret = NULL; | 
 | 914 |  | 
 | 915 | 	dprintk("%s:Begin\n", __func__); | 
 | 916 |  | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 917 | 	assert_spin_locked(&lo->plh_inode->i_lock); | 
 | 918 | 	list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 919 | 		if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 920 | 		    is_matching_lseg(&lseg->pls_range, range)) { | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 921 | 			ret = get_lseg(lseg); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 922 | 			break; | 
 | 923 | 		} | 
| Benny Halevy | d771e3a | 2011-06-14 16:30:16 -0400 | [diff] [blame] | 924 | 		if (lseg->pls_range.offset > range->offset) | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 925 | 			break; | 
 | 926 | 	} | 
 | 927 |  | 
 | 928 | 	dprintk("%s:Return lseg %p ref %d\n", | 
| Fred Isaman | 4541d16 | 2011-01-06 11:36:23 +0000 | [diff] [blame] | 929 | 		__func__, ret, ret ? atomic_read(&ret->pls_refcount) : 0); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 930 | 	return ret; | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 931 | } | 
 | 932 |  | 
 | 933 | /* | 
 | 934 |  * Layout segment is retreived from the server if not cached. | 
 | 935 |  * The appropriate layout segment is referenced and returned to the caller. | 
 | 936 |  */ | 
| Andy Adamson | 7c24d94 | 2011-06-13 18:22:38 -0400 | [diff] [blame] | 937 | struct pnfs_layout_segment * | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 938 | pnfs_update_layout(struct inode *ino, | 
 | 939 | 		   struct nfs_open_context *ctx, | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 940 | 		   loff_t pos, | 
 | 941 | 		   u64 count, | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 942 | 		   enum pnfs_iomode iomode, | 
 | 943 | 		   gfp_t gfp_flags) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 944 | { | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 945 | 	struct pnfs_layout_range arg = { | 
 | 946 | 		.iomode = iomode, | 
 | 947 | 		.offset = pos, | 
 | 948 | 		.length = count, | 
 | 949 | 	}; | 
| Benny Halevy | 707ed5f | 2011-05-22 19:47:46 +0300 | [diff] [blame] | 950 | 	unsigned pg_offset; | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 951 | 	struct nfs_inode *nfsi = NFS_I(ino); | 
| Weston Andros Adamson | 6382a44 | 2011-06-01 16:44:44 -0400 | [diff] [blame] | 952 | 	struct nfs_server *server = NFS_SERVER(ino); | 
 | 953 | 	struct nfs_client *clp = server->nfs_client; | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 954 | 	struct pnfs_layout_hdr *lo; | 
 | 955 | 	struct pnfs_layout_segment *lseg = NULL; | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 956 | 	bool first = false; | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 957 |  | 
 | 958 | 	if (!pnfs_enabled_sb(NFS_SERVER(ino))) | 
 | 959 | 		return NULL; | 
 | 960 | 	spin_lock(&ino->i_lock); | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 961 | 	lo = pnfs_find_alloc_layout(ino, ctx, gfp_flags); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 962 | 	if (lo == NULL) { | 
 | 963 | 		dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__); | 
 | 964 | 		goto out_unlock; | 
 | 965 | 	} | 
 | 966 |  | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 967 | 	/* Do we even need to bother with this? */ | 
| Trond Myklebust | a59c30a | 2012-03-01 11:17:47 -0500 | [diff] [blame] | 968 | 	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 969 | 		dprintk("%s matches recall, use MDS\n", __func__); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 970 | 		goto out_unlock; | 
 | 971 | 	} | 
 | 972 |  | 
 | 973 | 	/* if LAYOUTGET already failed once we don't try again */ | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 974 | 	if (test_bit(lo_fail_bit(iomode), &nfsi->layout->plh_flags)) | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 975 | 		goto out_unlock; | 
 | 976 |  | 
| Andy Adamson | 568e8c4 | 2011-03-01 01:34:22 +0000 | [diff] [blame] | 977 | 	/* Check to see if the layout for the given range already exists */ | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 978 | 	lseg = pnfs_find_lseg(lo, &arg); | 
| Andy Adamson | 568e8c4 | 2011-03-01 01:34:22 +0000 | [diff] [blame] | 979 | 	if (lseg) | 
 | 980 | 		goto out_unlock; | 
 | 981 |  | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 982 | 	if (pnfs_layoutgets_blocked(lo, NULL, 0)) | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 983 | 		goto out_unlock; | 
 | 984 | 	atomic_inc(&lo->plh_outstanding); | 
 | 985 |  | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 986 | 	get_layout_hdr(lo); | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 987 | 	if (list_empty(&lo->plh_segs)) | 
 | 988 | 		first = true; | 
 | 989 | 	spin_unlock(&ino->i_lock); | 
 | 990 | 	if (first) { | 
| Fred Isaman | 2130ff6 | 2011-01-06 11:36:26 +0000 | [diff] [blame] | 991 | 		/* The lo must be on the clp list if there is any | 
 | 992 | 		 * chance of a CB_LAYOUTRECALL(FILE) coming in. | 
 | 993 | 		 */ | 
 | 994 | 		spin_lock(&clp->cl_lock); | 
 | 995 | 		BUG_ON(!list_empty(&lo->plh_layouts)); | 
| Weston Andros Adamson | 6382a44 | 2011-06-01 16:44:44 -0400 | [diff] [blame] | 996 | 		list_add_tail(&lo->plh_layouts, &server->layouts); | 
| Fred Isaman | 2130ff6 | 2011-01-06 11:36:26 +0000 | [diff] [blame] | 997 | 		spin_unlock(&clp->cl_lock); | 
 | 998 | 	} | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 999 |  | 
| Benny Halevy | 707ed5f | 2011-05-22 19:47:46 +0300 | [diff] [blame] | 1000 | 	pg_offset = arg.offset & ~PAGE_CACHE_MASK; | 
 | 1001 | 	if (pg_offset) { | 
 | 1002 | 		arg.offset -= pg_offset; | 
 | 1003 | 		arg.length += pg_offset; | 
 | 1004 | 	} | 
| Andy Adamson | 7c24d94 | 2011-06-13 18:22:38 -0400 | [diff] [blame] | 1005 | 	if (arg.length != NFS4_MAX_UINT64) | 
 | 1006 | 		arg.length = PAGE_CACHE_ALIGN(arg.length); | 
| Benny Halevy | 707ed5f | 2011-05-22 19:47:46 +0300 | [diff] [blame] | 1007 |  | 
| Benny Halevy | fb3296e | 2011-05-22 19:47:26 +0300 | [diff] [blame] | 1008 | 	lseg = send_layoutget(lo, ctx, &arg, gfp_flags); | 
| Fred Isaman | f49f9ba | 2011-02-03 18:28:52 +0000 | [diff] [blame] | 1009 | 	if (!lseg && first) { | 
 | 1010 | 		spin_lock(&clp->cl_lock); | 
 | 1011 | 		list_del_init(&lo->plh_layouts); | 
 | 1012 | 		spin_unlock(&clp->cl_lock); | 
| Fred Isaman | 2130ff6 | 2011-01-06 11:36:26 +0000 | [diff] [blame] | 1013 | 	} | 
| Fred Isaman | cf7d63f | 2011-01-06 11:36:25 +0000 | [diff] [blame] | 1014 | 	atomic_dec(&lo->plh_outstanding); | 
| Fred Isaman | cc6e534 | 2011-01-06 11:36:28 +0000 | [diff] [blame] | 1015 | 	put_layout_hdr(lo); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 1016 | out: | 
 | 1017 | 	dprintk("%s end, state 0x%lx lseg %p\n", __func__, | 
| Andy Adamson | bf9c138 | 2011-03-01 01:34:07 +0000 | [diff] [blame] | 1018 | 		nfsi->layout ? nfsi->layout->plh_flags : -1, lseg); | 
| Benny Halevy | e5e9401 | 2010-10-20 00:18:01 -0400 | [diff] [blame] | 1019 | 	return lseg; | 
 | 1020 | out_unlock: | 
 | 1021 | 	spin_unlock(&ino->i_lock); | 
 | 1022 | 	goto out; | 
 | 1023 | } | 
| Andy Adamson | 7c24d94 | 2011-06-13 18:22:38 -0400 | [diff] [blame] | 1024 | EXPORT_SYMBOL_GPL(pnfs_update_layout); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1025 |  | 
 | 1026 | int | 
 | 1027 | pnfs_layout_process(struct nfs4_layoutget *lgp) | 
 | 1028 | { | 
 | 1029 | 	struct pnfs_layout_hdr *lo = NFS_I(lgp->args.inode)->layout; | 
 | 1030 | 	struct nfs4_layoutget_res *res = &lgp->res; | 
 | 1031 | 	struct pnfs_layout_segment *lseg; | 
| Fred Isaman | b7edfaa | 2011-01-06 11:36:21 +0000 | [diff] [blame] | 1032 | 	struct inode *ino = lo->plh_inode; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1033 | 	int status = 0; | 
 | 1034 |  | 
 | 1035 | 	/* Inject layout blob into I/O device driver */ | 
| Trond Myklebust | a75b9df | 2011-05-11 18:00:51 -0400 | [diff] [blame] | 1036 | 	lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1037 | 	if (!lseg || IS_ERR(lseg)) { | 
 | 1038 | 		if (!lseg) | 
 | 1039 | 			status = -ENOMEM; | 
 | 1040 | 		else | 
 | 1041 | 			status = PTR_ERR(lseg); | 
 | 1042 | 		dprintk("%s: Could not allocate layout: error %d\n", | 
 | 1043 | 		       __func__, status); | 
 | 1044 | 		goto out; | 
 | 1045 | 	} | 
 | 1046 |  | 
 | 1047 | 	spin_lock(&ino->i_lock); | 
| Trond Myklebust | a59c30a | 2012-03-01 11:17:47 -0500 | [diff] [blame] | 1048 | 	if (test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) { | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 1049 | 		dprintk("%s forget reply due to recall\n", __func__); | 
 | 1050 | 		goto out_forget_reply; | 
 | 1051 | 	} | 
 | 1052 |  | 
 | 1053 | 	if (pnfs_layoutgets_blocked(lo, &res->stateid, 1)) { | 
 | 1054 | 		dprintk("%s forget reply due to state\n", __func__); | 
 | 1055 | 		goto out_forget_reply; | 
 | 1056 | 	} | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1057 | 	init_lseg(lo, lseg); | 
| Fred Isaman | 566052c | 2011-01-06 11:36:20 +0000 | [diff] [blame] | 1058 | 	lseg->pls_range = res->range; | 
| Fred Isaman | d684d2a | 2011-03-01 01:34:13 +0000 | [diff] [blame] | 1059 | 	*lgp->lsegpp = get_lseg(lseg); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1060 | 	pnfs_insert_layout(lo, lseg); | 
 | 1061 |  | 
| Fred Isaman | f7e8917 | 2011-01-06 11:36:32 +0000 | [diff] [blame] | 1062 | 	if (res->return_on_close) { | 
 | 1063 | 		set_bit(NFS_LSEG_ROC, &lseg->pls_flags); | 
 | 1064 | 		set_bit(NFS_LAYOUT_ROC, &lo->plh_flags); | 
 | 1065 | 	} | 
 | 1066 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1067 | 	/* Done processing layoutget. Set the layout stateid */ | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 1068 | 	pnfs_set_layout_stateid(lo, &res->stateid, false); | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1069 | 	spin_unlock(&ino->i_lock); | 
 | 1070 | out: | 
 | 1071 | 	return status; | 
| Fred Isaman | 43f1b3d | 2011-01-06 11:36:30 +0000 | [diff] [blame] | 1072 |  | 
 | 1073 | out_forget_reply: | 
 | 1074 | 	spin_unlock(&ino->i_lock); | 
 | 1075 | 	lseg->pls_layout = lo; | 
 | 1076 | 	NFS_SERVER(ino)->pnfs_curr_ld->free_lseg(lseg); | 
 | 1077 | 	goto out; | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1078 | } | 
 | 1079 |  | 
| Trond Myklebust | d8007d4 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1080 | void | 
 | 1081 | pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) | 
 | 1082 | { | 
 | 1083 | 	BUG_ON(pgio->pg_lseg != NULL); | 
 | 1084 |  | 
 | 1085 | 	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 
 | 1086 | 					   req->wb_context, | 
 | 1087 | 					   req_offset(req), | 
 | 1088 | 					   req->wb_bytes, | 
 | 1089 | 					   IOMODE_READ, | 
 | 1090 | 					   GFP_KERNEL); | 
| Trond Myklebust | e885de1 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1091 | 	/* If no lseg, fall back to read through mds */ | 
 | 1092 | 	if (pgio->pg_lseg == NULL) | 
| Trond Myklebust | 1f94535 | 2011-07-13 15:59:57 -0400 | [diff] [blame] | 1093 | 		nfs_pageio_reset_read_mds(pgio); | 
| Trond Myklebust | e885de1 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1094 |  | 
| Trond Myklebust | d8007d4 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1095 | } | 
 | 1096 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read); | 
 | 1097 |  | 
 | 1098 | void | 
 | 1099 | pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) | 
 | 1100 | { | 
 | 1101 | 	BUG_ON(pgio->pg_lseg != NULL); | 
 | 1102 |  | 
 | 1103 | 	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 
 | 1104 | 					   req->wb_context, | 
 | 1105 | 					   req_offset(req), | 
 | 1106 | 					   req->wb_bytes, | 
 | 1107 | 					   IOMODE_RW, | 
 | 1108 | 					   GFP_NOFS); | 
| Trond Myklebust | e885de1 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1109 | 	/* If no lseg, fall back to write through mds */ | 
 | 1110 | 	if (pgio->pg_lseg == NULL) | 
| Trond Myklebust | 1f94535 | 2011-07-13 15:59:57 -0400 | [diff] [blame] | 1111 | 		nfs_pageio_reset_write_mds(pgio); | 
| Trond Myklebust | d8007d4 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1112 | } | 
 | 1113 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write); | 
 | 1114 |  | 
| Benny Halevy | 18ad0a9 | 2011-05-25 21:03:56 +0300 | [diff] [blame] | 1115 | bool | 
| Trond Myklebust | 1751c36 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1116 | pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) | 
 | 1117 | { | 
 | 1118 | 	struct nfs_server *server = NFS_SERVER(inode); | 
 | 1119 | 	struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; | 
 | 1120 |  | 
 | 1121 | 	if (ld == NULL) | 
 | 1122 | 		return false; | 
 | 1123 | 	nfs_pageio_init(pgio, inode, ld->pg_read_ops, server->rsize, 0); | 
 | 1124 | 	return true; | 
 | 1125 | } | 
 | 1126 |  | 
 | 1127 | bool | 
 | 1128 | pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags) | 
 | 1129 | { | 
 | 1130 | 	struct nfs_server *server = NFS_SERVER(inode); | 
 | 1131 | 	struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; | 
 | 1132 |  | 
 | 1133 | 	if (ld == NULL) | 
 | 1134 | 		return false; | 
 | 1135 | 	nfs_pageio_init(pgio, inode, ld->pg_write_ops, server->wsize, ioflags); | 
 | 1136 | 	return true; | 
 | 1137 | } | 
 | 1138 |  | 
 | 1139 | bool | 
| Benny Halevy | dfed206 | 2011-05-25 20:25:22 +0300 | [diff] [blame] | 1140 | pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | 
 | 1141 | 		     struct nfs_page *req) | 
| Fred Isaman | bae724e | 2011-03-01 01:34:15 +0000 | [diff] [blame] | 1142 | { | 
| Trond Myklebust | d8007d4 | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1143 | 	if (pgio->pg_lseg == NULL) | 
 | 1144 | 		return nfs_generic_pg_test(pgio, prev, req); | 
| Benny Halevy | 89a58e3 | 2011-05-25 20:54:40 +0300 | [diff] [blame] | 1145 |  | 
| Trond Myklebust | 19982ba | 2011-06-10 13:30:23 -0400 | [diff] [blame] | 1146 | 	/* | 
 | 1147 | 	 * Test if a nfs_page is fully contained in the pnfs_layout_range. | 
 | 1148 | 	 * Note that this test makes several assumptions: | 
 | 1149 | 	 * - that the previous nfs_page in the struct nfs_pageio_descriptor | 
 | 1150 | 	 *   is known to lie within the range. | 
 | 1151 | 	 *   - that the nfs_page being tested is known to be contiguous with the | 
 | 1152 | 	 *   previous nfs_page. | 
 | 1153 | 	 *   - Layout ranges are page aligned, so we only have to test the | 
 | 1154 | 	 *   start offset of the request. | 
 | 1155 | 	 * | 
 | 1156 | 	 * Please also note that 'end_offset' is actually the offset of the | 
 | 1157 | 	 * first byte that lies outside the pnfs_layout_range. FIXME? | 
 | 1158 | 	 * | 
 | 1159 | 	 */ | 
 | 1160 | 	return req_offset(req) < end_offset(pgio->pg_lseg->pls_range.offset, | 
 | 1161 | 					 pgio->pg_lseg->pls_range.length); | 
| Fred Isaman | bae724e | 2011-03-01 01:34:15 +0000 | [diff] [blame] | 1162 | } | 
| Benny Halevy | 89a58e3 | 2011-05-25 20:54:40 +0300 | [diff] [blame] | 1163 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); | 
| Fred Isaman | bae724e | 2011-03-01 01:34:15 +0000 | [diff] [blame] | 1164 |  | 
| Trond Myklebust | e2fecb2 | 2012-01-06 08:57:46 -0500 | [diff] [blame] | 1165 | static int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head) | 
 | 1166 | { | 
 | 1167 | 	struct nfs_pageio_descriptor pgio; | 
 | 1168 | 	LIST_HEAD(failed); | 
 | 1169 |  | 
 | 1170 | 	/* Resend all requests through the MDS */ | 
 | 1171 | 	nfs_pageio_init_write_mds(&pgio, inode, FLUSH_STABLE); | 
 | 1172 | 	while (!list_empty(head)) { | 
 | 1173 | 		struct nfs_page *req = nfs_list_entry(head->next); | 
 | 1174 |  | 
 | 1175 | 		nfs_list_remove_request(req); | 
 | 1176 | 		if (!nfs_pageio_add_request(&pgio, req)) | 
 | 1177 | 			nfs_list_add_request(req, &failed); | 
 | 1178 | 	} | 
 | 1179 | 	nfs_pageio_complete(&pgio); | 
 | 1180 |  | 
 | 1181 | 	if (!list_empty(&failed)) { | 
 | 1182 | 		/* For some reason our attempt to resend pages. Mark the | 
 | 1183 | 		 * overall send request as having failed, and let | 
 | 1184 | 		 * nfs_writeback_release_full deal with the error. | 
 | 1185 | 		 */ | 
 | 1186 | 		list_move(&failed, head); | 
 | 1187 | 		return -EIO; | 
 | 1188 | 	} | 
 | 1189 | 	return 0; | 
 | 1190 | } | 
 | 1191 |  | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1192 | /* | 
 | 1193 |  * Called by non rpc-based layout drivers | 
 | 1194 |  */ | 
| Peng Tao | 8ce160c | 2011-09-22 21:50:14 -0400 | [diff] [blame] | 1195 | void pnfs_ld_write_done(struct nfs_write_data *data) | 
| Fred Isaman | 94ad1c8 | 2011-03-01 01:34:14 +0000 | [diff] [blame] | 1196 | { | 
| Peng Tao | 8ce160c | 2011-09-22 21:50:14 -0400 | [diff] [blame] | 1197 | 	if (likely(!data->pnfs_error)) { | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1198 | 		pnfs_set_layoutcommit(data); | 
 | 1199 | 		data->mds_ops->rpc_call_done(&data->task, data); | 
| Peng Tao | 8ce160c | 2011-09-22 21:50:14 -0400 | [diff] [blame] | 1200 | 	} else { | 
| Peng Tao | 8ce160c | 2011-09-22 21:50:14 -0400 | [diff] [blame] | 1201 | 		dprintk("pnfs write error = %d\n", data->pnfs_error); | 
| Boaz Harrosh | fe0fe83 | 2012-01-06 09:31:20 +0200 | [diff] [blame] | 1202 | 		if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & | 
 | 1203 | 						PNFS_LAYOUTRET_ON_ERROR) { | 
 | 1204 | 			/* Don't lo_commit on error, Server will needs to | 
 | 1205 | 			 * preform a file recovery. | 
 | 1206 | 			 */ | 
 | 1207 | 			clear_bit(NFS_INO_LAYOUTCOMMIT, | 
 | 1208 | 				  &NFS_I(data->inode)->flags); | 
 | 1209 | 			pnfs_return_layout(data->inode); | 
 | 1210 | 		} | 
| Trond Myklebust | e2fecb2 | 2012-01-06 08:57:46 -0500 | [diff] [blame] | 1211 | 		data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); | 
| Fred Isaman | 44b8379 | 2011-03-03 15:13:44 +0000 | [diff] [blame] | 1212 | 	} | 
| Trond Myklebust | 8dd3775 | 2012-03-15 17:16:40 -0400 | [diff] [blame] | 1213 | 	put_lseg(data->lseg); | 
| Peng Tao | 8ce160c | 2011-09-22 21:50:14 -0400 | [diff] [blame] | 1214 | 	data->mds_ops->rpc_release(data); | 
| Fred Isaman | 44b8379 | 2011-03-03 15:13:44 +0000 | [diff] [blame] | 1215 | } | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1216 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | 
| Fred Isaman | 44b8379 | 2011-03-03 15:13:44 +0000 | [diff] [blame] | 1217 |  | 
| Trond Myklebust | dce8129 | 2011-07-13 15:59:19 -0400 | [diff] [blame] | 1218 | static void | 
 | 1219 | pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, | 
 | 1220 | 		struct nfs_write_data *data) | 
 | 1221 | { | 
 | 1222 | 	list_splice_tail_init(&data->pages, &desc->pg_list); | 
 | 1223 | 	if (data->req && list_empty(&data->req->wb_list)) | 
 | 1224 | 		nfs_list_add_request(data->req, &desc->pg_list); | 
 | 1225 | 	nfs_pageio_reset_write_mds(desc); | 
 | 1226 | 	desc->pg_recoalesce = 1; | 
| Trond Myklebust | 8dd3775 | 2012-03-15 17:16:40 -0400 | [diff] [blame] | 1227 | 	put_lseg(data->lseg); | 
| Trond Myklebust | dce8129 | 2011-07-13 15:59:19 -0400 | [diff] [blame] | 1228 | 	nfs_writedata_release(data); | 
 | 1229 | } | 
 | 1230 |  | 
 | 1231 | static enum pnfs_try_status | 
| Andy Adamson | 0382b74 | 2011-03-03 15:13:45 +0000 | [diff] [blame] | 1232 | pnfs_try_to_write_data(struct nfs_write_data *wdata, | 
| Trond Myklebust | dce8129 | 2011-07-13 15:59:19 -0400 | [diff] [blame] | 1233 | 			const struct rpc_call_ops *call_ops, | 
 | 1234 | 			struct pnfs_layout_segment *lseg, | 
 | 1235 | 			int how) | 
| Andy Adamson | 0382b74 | 2011-03-03 15:13:45 +0000 | [diff] [blame] | 1236 | { | 
 | 1237 | 	struct inode *inode = wdata->inode; | 
 | 1238 | 	enum pnfs_try_status trypnfs; | 
 | 1239 | 	struct nfs_server *nfss = NFS_SERVER(inode); | 
 | 1240 |  | 
 | 1241 | 	wdata->mds_ops = call_ops; | 
| Trond Myklebust | dce8129 | 2011-07-13 15:59:19 -0400 | [diff] [blame] | 1242 | 	wdata->lseg = get_lseg(lseg); | 
| Andy Adamson | 0382b74 | 2011-03-03 15:13:45 +0000 | [diff] [blame] | 1243 |  | 
 | 1244 | 	dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, | 
 | 1245 | 		inode->i_ino, wdata->args.count, wdata->args.offset, how); | 
 | 1246 |  | 
 | 1247 | 	trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); | 
 | 1248 | 	if (trypnfs == PNFS_NOT_ATTEMPTED) { | 
 | 1249 | 		put_lseg(wdata->lseg); | 
 | 1250 | 		wdata->lseg = NULL; | 
 | 1251 | 	} else | 
 | 1252 | 		nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); | 
 | 1253 |  | 
 | 1254 | 	dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 
 | 1255 | 	return trypnfs; | 
 | 1256 | } | 
 | 1257 |  | 
| Trond Myklebust | dce8129 | 2011-07-13 15:59:19 -0400 | [diff] [blame] | 1258 | static void | 
 | 1259 | pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how) | 
 | 1260 | { | 
 | 1261 | 	struct nfs_write_data *data; | 
 | 1262 | 	const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; | 
 | 1263 | 	struct pnfs_layout_segment *lseg = desc->pg_lseg; | 
 | 1264 |  | 
 | 1265 | 	desc->pg_lseg = NULL; | 
 | 1266 | 	while (!list_empty(head)) { | 
 | 1267 | 		enum pnfs_try_status trypnfs; | 
 | 1268 |  | 
 | 1269 | 		data = list_entry(head->next, struct nfs_write_data, list); | 
 | 1270 | 		list_del_init(&data->list); | 
 | 1271 |  | 
 | 1272 | 		trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); | 
 | 1273 | 		if (trypnfs == PNFS_NOT_ATTEMPTED) | 
 | 1274 | 			pnfs_write_through_mds(desc, data); | 
 | 1275 | 	} | 
 | 1276 | 	put_lseg(lseg); | 
 | 1277 | } | 
 | 1278 |  | 
 | 1279 | int | 
 | 1280 | pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) | 
 | 1281 | { | 
 | 1282 | 	LIST_HEAD(head); | 
 | 1283 | 	int ret; | 
 | 1284 |  | 
 | 1285 | 	ret = nfs_generic_flush(desc, &head); | 
 | 1286 | 	if (ret != 0) { | 
 | 1287 | 		put_lseg(desc->pg_lseg); | 
 | 1288 | 		desc->pg_lseg = NULL; | 
 | 1289 | 		return ret; | 
 | 1290 | 	} | 
 | 1291 | 	pnfs_do_multiple_writes(desc, &head, desc->pg_ioflags); | 
 | 1292 | 	return 0; | 
 | 1293 | } | 
 | 1294 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); | 
 | 1295 |  | 
| Trond Myklebust | 62e4a76 | 2011-11-10 14:30:37 -0500 | [diff] [blame] | 1296 | static void pnfs_ld_handle_read_error(struct nfs_read_data *data) | 
 | 1297 | { | 
 | 1298 | 	struct nfs_pageio_descriptor pgio; | 
 | 1299 |  | 
 | 1300 | 	put_lseg(data->lseg); | 
 | 1301 | 	data->lseg = NULL; | 
 | 1302 | 	dprintk("pnfs write error = %d\n", data->pnfs_error); | 
| Boaz Harrosh | fe0fe83 | 2012-01-06 09:31:20 +0200 | [diff] [blame] | 1303 | 	if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & | 
 | 1304 | 						PNFS_LAYOUTRET_ON_ERROR) | 
 | 1305 | 		pnfs_return_layout(data->inode); | 
| Trond Myklebust | 62e4a76 | 2011-11-10 14:30:37 -0500 | [diff] [blame] | 1306 |  | 
 | 1307 | 	nfs_pageio_init_read_mds(&pgio, data->inode); | 
 | 1308 |  | 
 | 1309 | 	while (!list_empty(&data->pages)) { | 
 | 1310 | 		struct nfs_page *req = nfs_list_entry(data->pages.next); | 
 | 1311 |  | 
 | 1312 | 		nfs_list_remove_request(req); | 
 | 1313 | 		nfs_pageio_add_request(&pgio, req); | 
 | 1314 | 	} | 
 | 1315 | 	nfs_pageio_complete(&pgio); | 
 | 1316 | } | 
 | 1317 |  | 
| Andy Adamson | b1f69b7 | 2010-10-20 00:18:03 -0400 | [diff] [blame] | 1318 | /* | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1319 |  * Called by non rpc-based layout drivers | 
 | 1320 |  */ | 
| Peng Tao | 9b7eecd | 2011-09-22 21:50:15 -0400 | [diff] [blame] | 1321 | void pnfs_ld_read_done(struct nfs_read_data *data) | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1322 | { | 
| Peng Tao | 9b7eecd | 2011-09-22 21:50:15 -0400 | [diff] [blame] | 1323 | 	if (likely(!data->pnfs_error)) { | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1324 | 		__nfs4_read_done_cb(data); | 
 | 1325 | 		data->mds_ops->rpc_call_done(&data->task, data); | 
| Trond Myklebust | 62e4a76 | 2011-11-10 14:30:37 -0500 | [diff] [blame] | 1326 | 	} else | 
 | 1327 | 		pnfs_ld_handle_read_error(data); | 
| Trond Myklebust | 8dd3775 | 2012-03-15 17:16:40 -0400 | [diff] [blame] | 1328 | 	put_lseg(data->lseg); | 
| Peng Tao | 9b7eecd | 2011-09-22 21:50:15 -0400 | [diff] [blame] | 1329 | 	data->mds_ops->rpc_release(data); | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1330 | } | 
 | 1331 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | 
 | 1332 |  | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 1333 | static void | 
 | 1334 | pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, | 
 | 1335 | 		struct nfs_read_data *data) | 
 | 1336 | { | 
 | 1337 | 	list_splice_tail_init(&data->pages, &desc->pg_list); | 
 | 1338 | 	if (data->req && list_empty(&data->req->wb_list)) | 
 | 1339 | 		nfs_list_add_request(data->req, &desc->pg_list); | 
 | 1340 | 	nfs_pageio_reset_read_mds(desc); | 
 | 1341 | 	desc->pg_recoalesce = 1; | 
 | 1342 | 	nfs_readdata_release(data); | 
 | 1343 | } | 
 | 1344 |  | 
| Benny Halevy | d20581a | 2011-05-22 19:52:03 +0300 | [diff] [blame] | 1345 | /* | 
| Andy Adamson | 64419a9 | 2011-03-01 01:34:16 +0000 | [diff] [blame] | 1346 |  * Call the appropriate parallel I/O subsystem read function. | 
 | 1347 |  */ | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 1348 | static enum pnfs_try_status | 
| Andy Adamson | 64419a9 | 2011-03-01 01:34:16 +0000 | [diff] [blame] | 1349 | pnfs_try_to_read_data(struct nfs_read_data *rdata, | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 1350 | 		       const struct rpc_call_ops *call_ops, | 
 | 1351 | 		       struct pnfs_layout_segment *lseg) | 
| Andy Adamson | 64419a9 | 2011-03-01 01:34:16 +0000 | [diff] [blame] | 1352 | { | 
 | 1353 | 	struct inode *inode = rdata->inode; | 
 | 1354 | 	struct nfs_server *nfss = NFS_SERVER(inode); | 
 | 1355 | 	enum pnfs_try_status trypnfs; | 
 | 1356 |  | 
 | 1357 | 	rdata->mds_ops = call_ops; | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 1358 | 	rdata->lseg = get_lseg(lseg); | 
| Andy Adamson | 64419a9 | 2011-03-01 01:34:16 +0000 | [diff] [blame] | 1359 |  | 
 | 1360 | 	dprintk("%s: Reading ino:%lu %u@%llu\n", | 
 | 1361 | 		__func__, inode->i_ino, rdata->args.count, rdata->args.offset); | 
 | 1362 |  | 
 | 1363 | 	trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); | 
 | 1364 | 	if (trypnfs == PNFS_NOT_ATTEMPTED) { | 
 | 1365 | 		put_lseg(rdata->lseg); | 
 | 1366 | 		rdata->lseg = NULL; | 
 | 1367 | 	} else { | 
 | 1368 | 		nfs_inc_stats(inode, NFSIOS_PNFS_READ); | 
 | 1369 | 	} | 
 | 1370 | 	dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 
 | 1371 | 	return trypnfs; | 
 | 1372 | } | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1373 |  | 
| Trond Myklebust | 493292d | 2011-07-13 15:58:28 -0400 | [diff] [blame] | 1374 | static void | 
 | 1375 | pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head) | 
 | 1376 | { | 
 | 1377 | 	struct nfs_read_data *data; | 
 | 1378 | 	const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; | 
 | 1379 | 	struct pnfs_layout_segment *lseg = desc->pg_lseg; | 
 | 1380 |  | 
 | 1381 | 	desc->pg_lseg = NULL; | 
 | 1382 | 	while (!list_empty(head)) { | 
 | 1383 | 		enum pnfs_try_status trypnfs; | 
 | 1384 |  | 
 | 1385 | 		data = list_entry(head->next, struct nfs_read_data, list); | 
 | 1386 | 		list_del_init(&data->list); | 
 | 1387 |  | 
 | 1388 | 		trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); | 
 | 1389 | 		if (trypnfs == PNFS_NOT_ATTEMPTED) | 
 | 1390 | 			pnfs_read_through_mds(desc, data); | 
 | 1391 | 	} | 
 | 1392 | 	put_lseg(lseg); | 
 | 1393 | } | 
 | 1394 |  | 
 | 1395 | int | 
 | 1396 | pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) | 
 | 1397 | { | 
 | 1398 | 	LIST_HEAD(head); | 
 | 1399 | 	int ret; | 
 | 1400 |  | 
 | 1401 | 	ret = nfs_generic_pagein(desc, &head); | 
 | 1402 | 	if (ret != 0) { | 
 | 1403 | 		put_lseg(desc->pg_lseg); | 
 | 1404 | 		desc->pg_lseg = NULL; | 
 | 1405 | 		return ret; | 
 | 1406 | 	} | 
 | 1407 | 	pnfs_do_multiple_reads(desc, &head); | 
 | 1408 | 	return 0; | 
 | 1409 | } | 
 | 1410 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); | 
 | 1411 |  | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1412 | /* | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1413 |  * There can be multiple RW segments. | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1414 |  */ | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1415 | static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp) | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1416 | { | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1417 | 	struct pnfs_layout_segment *lseg; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1418 |  | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1419 | 	list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { | 
 | 1420 | 		if (lseg->pls_range.iomode == IOMODE_RW && | 
 | 1421 | 		    test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) | 
 | 1422 | 			list_add(&lseg->pls_lc_list, listp); | 
 | 1423 | 	} | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1424 | } | 
 | 1425 |  | 
| Peng Tao | 1b0ae06 | 2011-09-22 21:50:12 -0400 | [diff] [blame] | 1426 | void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) | 
 | 1427 | { | 
 | 1428 | 	if (lseg->pls_range.iomode == IOMODE_RW) { | 
 | 1429 | 		dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__); | 
 | 1430 | 		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); | 
 | 1431 | 	} else { | 
 | 1432 | 		dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__); | 
 | 1433 | 		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); | 
 | 1434 | 	} | 
 | 1435 | } | 
 | 1436 | EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); | 
 | 1437 |  | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1438 | void | 
 | 1439 | pnfs_set_layoutcommit(struct nfs_write_data *wdata) | 
 | 1440 | { | 
 | 1441 | 	struct nfs_inode *nfsi = NFS_I(wdata->inode); | 
| Vitaliy Gusev | 4b8ee2b | 2011-05-20 01:34:46 +0400 | [diff] [blame] | 1442 | 	loff_t end_pos = wdata->mds_offset + wdata->res.count; | 
| Weston Andros Adamson | 79a48a1 | 2011-04-13 10:53:51 -0400 | [diff] [blame] | 1443 | 	bool mark_as_dirty = false; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1444 |  | 
 | 1445 | 	spin_lock(&nfsi->vfs_inode.i_lock); | 
 | 1446 | 	if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | 
| Weston Andros Adamson | 79a48a1 | 2011-04-13 10:53:51 -0400 | [diff] [blame] | 1447 | 		mark_as_dirty = true; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1448 | 		dprintk("%s: Set layoutcommit for inode %lu ", | 
 | 1449 | 			__func__, wdata->inode->i_ino); | 
 | 1450 | 	} | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1451 | 	if (!test_and_set_bit(NFS_LSEG_LAYOUTCOMMIT, &wdata->lseg->pls_flags)) { | 
 | 1452 | 		/* references matched in nfs4_layoutcommit_release */ | 
 | 1453 | 		get_lseg(wdata->lseg); | 
 | 1454 | 	} | 
| Peng Tao | acff5880 | 2011-07-30 20:52:31 -0400 | [diff] [blame] | 1455 | 	if (end_pos > nfsi->layout->plh_lwb) | 
 | 1456 | 		nfsi->layout->plh_lwb = end_pos; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1457 | 	spin_unlock(&nfsi->vfs_inode.i_lock); | 
| Peng Tao | acff5880 | 2011-07-30 20:52:31 -0400 | [diff] [blame] | 1458 | 	dprintk("%s: lseg %p end_pos %llu\n", | 
 | 1459 | 		__func__, wdata->lseg, nfsi->layout->plh_lwb); | 
| Weston Andros Adamson | 79a48a1 | 2011-04-13 10:53:51 -0400 | [diff] [blame] | 1460 |  | 
 | 1461 | 	/* if pnfs_layoutcommit_inode() runs between inode locks, the next one | 
 | 1462 | 	 * will be a noop because NFS_INO_LAYOUTCOMMIT will not be set */ | 
 | 1463 | 	if (mark_as_dirty) | 
 | 1464 | 		mark_inode_dirty_sync(wdata->inode); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1465 | } | 
 | 1466 | EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); | 
 | 1467 |  | 
| Andy Adamson | db29c08 | 2011-07-30 20:52:38 -0400 | [diff] [blame] | 1468 | void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data) | 
 | 1469 | { | 
 | 1470 | 	struct nfs_server *nfss = NFS_SERVER(data->args.inode); | 
 | 1471 |  | 
 | 1472 | 	if (nfss->pnfs_curr_ld->cleanup_layoutcommit) | 
 | 1473 | 		nfss->pnfs_curr_ld->cleanup_layoutcommit(data); | 
 | 1474 | } | 
 | 1475 |  | 
| Andy Adamson | de4b15c | 2011-03-12 02:58:09 -0500 | [diff] [blame] | 1476 | /* | 
 | 1477 |  * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and | 
 | 1478 |  * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough | 
 | 1479 |  * data to disk to allow the server to recover the data if it crashes. | 
 | 1480 |  * LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag | 
 | 1481 |  * is off, and a COMMIT is sent to a data server, or | 
 | 1482 |  * if WRITEs to a data server return NFS_DATA_SYNC. | 
 | 1483 |  */ | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1484 | int | 
| Andy Adamson | ef31153 | 2011-03-12 02:58:10 -0500 | [diff] [blame] | 1485 | pnfs_layoutcommit_inode(struct inode *inode, bool sync) | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1486 | { | 
 | 1487 | 	struct nfs4_layoutcommit_data *data; | 
 | 1488 | 	struct nfs_inode *nfsi = NFS_I(inode); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1489 | 	loff_t end_pos; | 
 | 1490 | 	int status = 0; | 
 | 1491 |  | 
 | 1492 | 	dprintk("--> %s inode %lu\n", __func__, inode->i_ino); | 
 | 1493 |  | 
| Andy Adamson | de4b15c | 2011-03-12 02:58:09 -0500 | [diff] [blame] | 1494 | 	if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) | 
 | 1495 | 		return 0; | 
 | 1496 |  | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1497 | 	/* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ | 
 | 1498 | 	data = kzalloc(sizeof(*data), GFP_NOFS); | 
| Andy Adamson | de4b15c | 2011-03-12 02:58:09 -0500 | [diff] [blame] | 1499 | 	if (!data) { | 
| Andy Adamson | de4b15c | 2011-03-12 02:58:09 -0500 | [diff] [blame] | 1500 | 		status = -ENOMEM; | 
 | 1501 | 		goto out; | 
 | 1502 | 	} | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1503 |  | 
| Peng Tao | 92407e7 | 2011-10-23 20:21:17 -0700 | [diff] [blame] | 1504 | 	if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) | 
 | 1505 | 		goto out_free; | 
 | 1506 |  | 
 | 1507 | 	if (test_and_set_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags)) { | 
 | 1508 | 		if (!sync) { | 
 | 1509 | 			status = -EAGAIN; | 
 | 1510 | 			goto out_free; | 
 | 1511 | 		} | 
 | 1512 | 		status = wait_on_bit_lock(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING, | 
 | 1513 | 					nfs_wait_bit_killable, TASK_KILLABLE); | 
 | 1514 | 		if (status) | 
 | 1515 | 			goto out_free; | 
 | 1516 | 	} | 
 | 1517 |  | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1518 | 	INIT_LIST_HEAD(&data->lseg_list); | 
| Andy Adamson | de4b15c | 2011-03-12 02:58:09 -0500 | [diff] [blame] | 1519 | 	spin_lock(&inode->i_lock); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1520 | 	if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | 
| Peng Tao | 92407e7 | 2011-10-23 20:21:17 -0700 | [diff] [blame] | 1521 | 		clear_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1522 | 		spin_unlock(&inode->i_lock); | 
| Peng Tao | 92407e7 | 2011-10-23 20:21:17 -0700 | [diff] [blame] | 1523 | 		wake_up_bit(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING); | 
 | 1524 | 		goto out_free; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1525 | 	} | 
| Peng Tao | a9bae56 | 2011-07-30 20:52:33 -0400 | [diff] [blame] | 1526 |  | 
 | 1527 | 	pnfs_list_write_lseg(inode, &data->lseg_list); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1528 |  | 
| Peng Tao | acff5880 | 2011-07-30 20:52:31 -0400 | [diff] [blame] | 1529 | 	end_pos = nfsi->layout->plh_lwb; | 
| Peng Tao | acff5880 | 2011-07-30 20:52:31 -0400 | [diff] [blame] | 1530 | 	nfsi->layout->plh_lwb = 0; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1531 |  | 
| Trond Myklebust | f597c53 | 2012-03-04 18:13:56 -0500 | [diff] [blame] | 1532 | 	nfs4_stateid_copy(&data->args.stateid, &nfsi->layout->plh_stateid); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1533 | 	spin_unlock(&inode->i_lock); | 
 | 1534 |  | 
 | 1535 | 	data->args.inode = inode; | 
| Peng Tao | 9fa4075 | 2011-07-30 20:52:32 -0400 | [diff] [blame] | 1536 | 	data->cred = get_rpccred(nfsi->layout->plh_lc_cred); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1537 | 	nfs_fattr_init(&data->fattr); | 
 | 1538 | 	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; | 
 | 1539 | 	data->res.fattr = &data->fattr; | 
 | 1540 | 	data->args.lastbytewritten = end_pos - 1; | 
 | 1541 | 	data->res.server = NFS_SERVER(inode); | 
 | 1542 |  | 
 | 1543 | 	status = nfs4_proc_layoutcommit(data, sync); | 
 | 1544 | out: | 
| Peng Tao | 92407e7 | 2011-10-23 20:21:17 -0700 | [diff] [blame] | 1545 | 	if (status) | 
 | 1546 | 		mark_inode_dirty_sync(inode); | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1547 | 	dprintk("<-- %s status %d\n", __func__, status); | 
 | 1548 | 	return status; | 
| Peng Tao | 92407e7 | 2011-10-23 20:21:17 -0700 | [diff] [blame] | 1549 | out_free: | 
 | 1550 | 	kfree(data); | 
 | 1551 | 	goto out; | 
| Andy Adamson | 863a3c6 | 2011-03-23 13:27:54 +0000 | [diff] [blame] | 1552 | } |