Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pNFS: Delay getting the layout header in CB_LAYOUTRECALL handlers

Instead of grabbing the layout, we want to get the inode so that we
can reduce races between layoutget and layoutrecall when the server
does not support call referring.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

+68 -33
+68 -33
fs/nfs/callback_proc.c
··· 110 110 #if defined(CONFIG_NFS_V4_1) 111 111 112 112 /* 113 - * Lookup a layout by filehandle. 113 + * Lookup a layout inode by stateid 114 114 * 115 - * Note: gets a refcount on the layout hdr and on its respective inode. 116 - * Caller must put the layout hdr and the inode. 117 - * 118 - * TODO: keep track of all layouts (and delegations) in a hash table 119 - * hashed by filehandle. 115 + * Note: returns a refcount on the inode and superblock 120 116 */ 121 - static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, 122 - struct nfs_fh *fh) 117 + static struct inode *nfs_layout_find_inode_by_stateid(struct nfs_client *clp, 118 + const nfs4_stateid *stateid) 119 + { 120 + struct nfs_server *server; 121 + struct inode *inode; 122 + struct pnfs_layout_hdr *lo; 123 + 124 + restart: 125 + list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { 126 + list_for_each_entry(lo, &server->layouts, plh_layouts) { 127 + if (stateid != NULL && 128 + !nfs4_stateid_match_other(stateid, &lo->plh_stateid)) 129 + continue; 130 + inode = igrab(lo->plh_inode); 131 + if (!inode) 132 + continue; 133 + if (!nfs_sb_active(inode->i_sb)) { 134 + rcu_read_lock(); 135 + spin_unlock(&clp->cl_lock); 136 + iput(inode); 137 + spin_lock(&clp->cl_lock); 138 + goto restart; 139 + } 140 + return inode; 141 + } 142 + } 143 + 144 + return NULL; 145 + } 146 + 147 + /* 148 + * Lookup a layout inode by filehandle. 149 + * 150 + * Note: returns a refcount on the inode and superblock 151 + * 152 + */ 153 + static struct inode *nfs_layout_find_inode_by_fh(struct nfs_client *clp, 154 + const struct nfs_fh *fh) 123 155 { 124 156 struct nfs_server *server; 125 157 struct nfs_inode *nfsi; 126 - struct inode *ino; 158 + struct inode *inode; 127 159 struct pnfs_layout_hdr *lo; 128 160 129 161 restart: ··· 166 134 continue; 167 135 if (nfsi->layout != lo) 168 136 continue; 169 - ino = igrab(lo->plh_inode); 170 - if (!ino) 171 - break; 172 - spin_lock(&ino->i_lock); 173 - /* Is this layout in the process of being freed? */ 174 - if (nfsi->layout != lo) { 175 - spin_unlock(&ino->i_lock); 176 - iput(ino); 137 + inode = igrab(lo->plh_inode); 138 + if (!inode) 139 + continue; 140 + if (!nfs_sb_active(inode->i_sb)) { 141 + rcu_read_lock(); 142 + spin_unlock(&clp->cl_lock); 143 + iput(inode); 144 + spin_lock(&clp->cl_lock); 177 145 goto restart; 178 146 } 179 - pnfs_get_layout_hdr(lo); 180 - spin_unlock(&ino->i_lock); 181 - return lo; 147 + return inode; 182 148 } 183 149 } 184 150 185 151 return NULL; 186 152 } 187 153 188 - static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, 189 - struct nfs_fh *fh) 154 + static struct inode *nfs_layout_find_inode(struct nfs_client *clp, 155 + const struct nfs_fh *fh, 156 + const nfs4_stateid *stateid) 190 157 { 191 - struct pnfs_layout_hdr *lo; 158 + struct inode *inode; 192 159 193 160 spin_lock(&clp->cl_lock); 194 161 rcu_read_lock(); 195 - lo = get_layout_by_fh_locked(clp, fh); 162 + inode = nfs_layout_find_inode_by_stateid(clp, stateid); 163 + if (!inode) 164 + inode = nfs_layout_find_inode_by_fh(clp, fh); 196 165 rcu_read_unlock(); 197 166 spin_unlock(&clp->cl_lock); 198 167 199 - return lo; 168 + return inode; 200 169 } 201 170 202 171 /* ··· 246 213 u32 rv = NFS4ERR_NOMATCHING_LAYOUT; 247 214 LIST_HEAD(free_me_list); 248 215 249 - lo = get_layout_by_fh(clp, &args->cbl_fh); 250 - if (!lo) { 251 - trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, NULL, 252 - &args->cbl_stateid, -rv); 216 + ino = nfs_layout_find_inode(clp, &args->cbl_fh, &args->cbl_stateid); 217 + if (!ino) 253 218 goto out; 254 - } 255 219 256 - ino = lo->plh_inode; 257 220 pnfs_layoutcommit_inode(ino, false); 258 221 259 222 260 223 spin_lock(&ino->i_lock); 224 + lo = NFS_I(ino)->layout; 225 + if (!lo) { 226 + spin_unlock(&ino->i_lock); 227 + goto out; 228 + } 229 + pnfs_get_layout_hdr(lo); 261 230 rv = pnfs_check_callback_stateid(lo, &args->cbl_stateid); 262 231 if (rv != NFS_OK) 263 232 goto unlock; ··· 293 258 /* Free all lsegs that are attached to commit buckets */ 294 259 nfs_commit_inode(ino, 0); 295 260 pnfs_put_layout_hdr(lo); 261 + out: 296 262 trace_nfs4_cb_layoutrecall_file(clp, &args->cbl_fh, ino, 297 263 &args->cbl_stateid, -rv); 298 - iput(ino); 299 - out: 264 + nfs_iput_and_deactive(ino); 300 265 return rv; 301 266 } 302 267