Merge branch 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6

* 'nfs-for-2.6.39' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (28 commits)
Cleanup XDR parsing for LAYOUTGET, GETDEVICEINFO
NFSv4.1 convert layoutcommit sync to boolean
NFSv4.1 pnfs_layoutcommit_inode fixes
NFS: Determine initial mount security
NFS: use secinfo when crossing mountpoints
NFS: Add secinfo procedure
NFS: lookup supports alternate client
NFS: convert call_sync() to a function
NFSv4.1 remove temp code that prevented ds commits
NFSv4.1: layoutcommit
NFSv4.1: filelayout driver specific code for COMMIT
NFSv4.1: remove GETATTR from ds commits
NFSv4.1: add generic layer hooks for pnfs COMMIT
NFSv4.1: alloc and free commit_buckets
NFSv4.1: shift filelayout_free_lseg
NFSv4.1: pull out code from nfs_commit_release
NFSv4.1: pull error handling out of nfs_commit_list
NFSv4.1: add callback to nfs4_commit_done
NFSv4.1: rearrange nfs_commit_rpcsetup
NFSv4.1: don't send COMMIT to ds for data sync writes
...

+1736 -264
+78 -11
fs/nfs/dir.c
··· 44 44 /* #define NFS_DEBUG_VERBOSE 1 */ 45 45 46 46 static int nfs_opendir(struct inode *, struct file *); 47 + static int nfs_closedir(struct inode *, struct file *); 47 48 static int nfs_readdir(struct file *, void *, filldir_t); 48 49 static struct dentry *nfs_lookup(struct inode *, struct dentry *, struct nameidata *); 49 50 static int nfs_create(struct inode *, struct dentry *, int, struct nameidata *); ··· 65 64 .read = generic_read_dir, 66 65 .readdir = nfs_readdir, 67 66 .open = nfs_opendir, 68 - .release = nfs_release, 67 + .release = nfs_closedir, 69 68 .fsync = nfs_fsync_dir, 70 69 }; 71 70 ··· 134 133 135 134 #endif /* CONFIG_NFS_V4 */ 136 135 136 + static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct rpc_cred *cred) 137 + { 138 + struct nfs_open_dir_context *ctx; 139 + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 140 + if (ctx != NULL) { 141 + ctx->duped = 0; 142 + ctx->dir_cookie = 0; 143 + ctx->dup_cookie = 0; 144 + ctx->cred = get_rpccred(cred); 145 + } else 146 + ctx = ERR_PTR(-ENOMEM); 147 + return ctx; 148 + } 149 + 150 + static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx) 151 + { 152 + put_rpccred(ctx->cred); 153 + kfree(ctx); 154 + } 155 + 137 156 /* 138 157 * Open file 139 158 */ 140 159 static int 141 160 nfs_opendir(struct inode *inode, struct file *filp) 142 161 { 143 - int res; 162 + int res = 0; 163 + struct nfs_open_dir_context *ctx; 164 + struct rpc_cred *cred; 144 165 145 166 dfprintk(FILE, "NFS: open dir(%s/%s)\n", 146 167 filp->f_path.dentry->d_parent->d_name.name, ··· 170 147 171 148 nfs_inc_stats(inode, NFSIOS_VFSOPEN); 172 149 173 - /* Call generic open code in order to cache credentials */ 174 - res = nfs_open(inode, filp); 150 + cred = rpc_lookup_cred(); 151 + if (IS_ERR(cred)) 152 + return PTR_ERR(cred); 153 + ctx = alloc_nfs_open_dir_context(cred); 154 + if (IS_ERR(ctx)) { 155 + res = PTR_ERR(ctx); 156 + goto out; 157 + } 158 + filp->private_data = ctx; 175 159 if (filp->f_path.dentry == filp->f_path.mnt->mnt_root) { 176 160 /* This is a mountpoint, so d_revalidate will never 177 161 * have been called, so we need to refresh the ··· 186 156 */ 187 157 __nfs_revalidate_inode(NFS_SERVER(inode), inode); 188 158 } 159 + out: 160 + put_rpccred(cred); 189 161 return res; 162 + } 163 + 164 + static int 165 + nfs_closedir(struct inode *inode, struct file *filp) 166 + { 167 + put_nfs_open_dir_context(filp->private_data); 168 + return 0; 190 169 } 191 170 192 171 struct nfs_cache_array_entry { ··· 323 284 { 324 285 loff_t diff = desc->file->f_pos - desc->current_index; 325 286 unsigned int index; 287 + struct nfs_open_dir_context *ctx = desc->file->private_data; 326 288 327 289 if (diff < 0) 328 290 goto out_eof; 329 291 if (diff >= array->size) { 330 292 if (array->eof_index >= 0) 331 293 goto out_eof; 332 - desc->current_index += array->size; 333 294 return -EAGAIN; 334 295 } 335 296 336 297 index = (unsigned int)diff; 337 298 *desc->dir_cookie = array->array[index].cookie; 338 299 desc->cache_entry_index = index; 300 + ctx->duped = 0; 339 301 return 0; 340 302 out_eof: 341 303 desc->eof = 1; ··· 347 307 int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) 348 308 { 349 309 int i; 310 + loff_t new_pos; 350 311 int status = -EAGAIN; 312 + struct nfs_open_dir_context *ctx = desc->file->private_data; 351 313 352 314 for (i = 0; i < array->size; i++) { 353 315 if (array->array[i].cookie == *desc->dir_cookie) { 316 + new_pos = desc->current_index + i; 317 + if (new_pos < desc->file->f_pos) { 318 + ctx->dup_cookie = *desc->dir_cookie; 319 + ctx->duped = 1; 320 + } 321 + desc->file->f_pos = new_pos; 354 322 desc->cache_entry_index = i; 355 323 return 0; 356 324 } ··· 390 342 391 343 if (status == -EAGAIN) { 392 344 desc->last_cookie = array->last_cookie; 345 + desc->current_index += array->size; 393 346 desc->page_index++; 394 347 } 395 348 nfs_readdir_release_array(desc->page); ··· 403 354 int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, 404 355 struct nfs_entry *entry, struct file *file, struct inode *inode) 405 356 { 406 - struct rpc_cred *cred = nfs_file_cred(file); 357 + struct nfs_open_dir_context *ctx = file->private_data; 358 + struct rpc_cred *cred = ctx->cred; 407 359 unsigned long timestamp, gencount; 408 360 int error; 409 361 ··· 743 693 int i = 0; 744 694 int res = 0; 745 695 struct nfs_cache_array *array = NULL; 696 + struct nfs_open_dir_context *ctx = file->private_data; 697 + 698 + if (ctx->duped != 0 && ctx->dup_cookie == *desc->dir_cookie) { 699 + if (printk_ratelimit()) { 700 + pr_notice("NFS: directory %s/%s contains a readdir loop. " 701 + "Please contact your server vendor. " 702 + "Offending cookie: %llu\n", 703 + file->f_dentry->d_parent->d_name.name, 704 + file->f_dentry->d_name.name, 705 + *desc->dir_cookie); 706 + } 707 + res = -ELOOP; 708 + goto out; 709 + } 746 710 747 711 array = nfs_readdir_get_array(desc->page); 748 712 if (IS_ERR(array)) { ··· 849 785 struct inode *inode = dentry->d_inode; 850 786 nfs_readdir_descriptor_t my_desc, 851 787 *desc = &my_desc; 788 + struct nfs_open_dir_context *dir_ctx = filp->private_data; 852 789 int res; 853 790 854 791 dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", ··· 866 801 memset(desc, 0, sizeof(*desc)); 867 802 868 803 desc->file = filp; 869 - desc->dir_cookie = &nfs_file_open_context(filp)->dir_cookie; 804 + desc->dir_cookie = &dir_ctx->dir_cookie; 870 805 desc->decode = NFS_PROTO(inode)->decode_dirent; 871 806 desc->plus = NFS_USE_READDIRPLUS(inode); 872 807 ··· 918 853 { 919 854 struct dentry *dentry = filp->f_path.dentry; 920 855 struct inode *inode = dentry->d_inode; 856 + struct nfs_open_dir_context *dir_ctx = filp->private_data; 921 857 922 858 dfprintk(FILE, "NFS: llseek dir(%s/%s, %lld, %d)\n", 923 859 dentry->d_parent->d_name.name, ··· 938 872 } 939 873 if (offset != filp->f_pos) { 940 874 filp->f_pos = offset; 941 - nfs_file_open_context(filp)->dir_cookie = 0; 875 + dir_ctx->dir_cookie = 0; 876 + dir_ctx->duped = 0; 942 877 } 943 878 out: 944 879 mutex_unlock(&inode->i_mutex); ··· 1135 1068 if (fhandle == NULL || fattr == NULL) 1136 1069 goto out_error; 1137 1070 1138 - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); 1071 + error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); 1139 1072 if (error) 1140 1073 goto out_bad; 1141 1074 if (nfs_compare_fh(NFS_FH(inode), fhandle)) ··· 1291 1224 parent = dentry->d_parent; 1292 1225 /* Protect against concurrent sillydeletes */ 1293 1226 nfs_block_sillyrename(parent); 1294 - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); 1227 + error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); 1295 1228 if (error == -ENOENT) 1296 1229 goto no_entry; 1297 1230 if (error < 0) { ··· 1629 1562 if (dentry->d_inode) 1630 1563 goto out; 1631 1564 if (fhandle->size == 0) { 1632 - error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); 1565 + error = NFS_PROTO(dir)->lookup(NFS_SERVER(dir)->client, dir, &dentry->d_name, fhandle, fattr); 1633 1566 if (error) 1634 1567 goto out_error; 1635 1568 }
+3
fs/nfs/file.c
··· 326 326 ret = xchg(&ctx->error, 0); 327 327 if (!ret && status < 0) 328 328 ret = status; 329 + if (!ret && !datasync) 330 + /* application has asked for meta-data sync */ 331 + ret = pnfs_layoutcommit_inode(inode, true); 329 332 return ret; 330 333 } 331 334
+4
fs/nfs/getroot.c
··· 222 222 goto out; 223 223 } 224 224 225 + if (fattr->valid & NFS_ATTR_FATTR_FSID && 226 + !nfs_fsid_equal(&server->fsid, &fattr->fsid)) 227 + memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); 228 + 225 229 inode = nfs_fhget(sb, mntfh, fattr); 226 230 if (IS_ERR(inode)) { 227 231 dprintk("nfs_get_root: get root inode failed\n");
+6 -4
fs/nfs/inode.c
··· 254 254 struct inode *inode = ERR_PTR(-ENOENT); 255 255 unsigned long hash; 256 256 257 - if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) 257 + nfs_attr_check_mountpoint(sb, fattr); 258 + 259 + if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0 && (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0) 258 260 goto out_no_inode; 259 261 if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0) 260 262 goto out_no_inode; ··· 300 298 if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) 301 299 set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); 302 300 /* Deal with crossing mountpoints */ 303 - if ((fattr->valid & NFS_ATTR_FATTR_FSID) 304 - && !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) { 301 + if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT || 302 + fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { 305 303 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 306 304 inode->i_op = &nfs_referral_inode_operations; 307 305 else ··· 641 639 ctx->mode = f_mode; 642 640 ctx->flags = 0; 643 641 ctx->error = 0; 644 - ctx->dir_cookie = 0; 645 642 nfs_init_lock_context(&ctx->lock_context); 646 643 ctx->lock_context.open_context = ctx; 647 644 INIT_LIST_HEAD(&ctx->list); ··· 1472 1471 nfsi->delegation_state = 0; 1473 1472 init_rwsem(&nfsi->rwsem); 1474 1473 nfsi->layout = NULL; 1474 + atomic_set(&nfsi->commits_outstanding, 0); 1475 1475 #endif 1476 1476 } 1477 1477
+25 -2
fs/nfs/internal.h
··· 39 39 return 0; 40 40 } 41 41 42 + static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr) 43 + { 44 + if (!nfs_fsid_equal(&NFS_SB(parent)->fsid, &fattr->fsid)) 45 + fattr->valid |= NFS_ATTR_FATTR_MOUNTPOINT; 46 + } 47 + 42 48 struct nfs_clone_mount { 43 49 const struct super_block *sb; 44 50 const struct dentry *dentry; ··· 220 214 /* nfs4proc.c */ 221 215 #ifdef CONFIG_NFS_V4 222 216 extern struct rpc_procinfo nfs4_procedures[]; 217 + void nfs_fixup_secinfo_attributes(struct nfs_fattr *, struct nfs_fh *); 223 218 #endif 224 219 225 220 extern int nfs4_init_ds_session(struct nfs_client *clp); ··· 283 276 extern void nfs_read_prepare(struct rpc_task *task, void *calldata); 284 277 285 278 /* write.c */ 279 + extern void nfs_commit_free(struct nfs_write_data *p); 286 280 extern int nfs_initiate_write(struct nfs_write_data *data, 287 281 struct rpc_clnt *clnt, 288 282 const struct rpc_call_ops *call_ops, 289 283 int how); 290 284 extern void nfs_write_prepare(struct rpc_task *task, void *calldata); 285 + extern int nfs_initiate_commit(struct nfs_write_data *data, 286 + struct rpc_clnt *clnt, 287 + const struct rpc_call_ops *call_ops, 288 + int how); 289 + extern void nfs_init_commit(struct nfs_write_data *data, 290 + struct list_head *head, 291 + struct pnfs_layout_segment *lseg); 292 + void nfs_retry_commit(struct list_head *page_list, 293 + struct pnfs_layout_segment *lseg); 294 + void nfs_commit_clear_lock(struct nfs_inode *nfsi); 295 + void nfs_commitdata_release(void *data); 296 + void nfs_commit_release_pages(struct nfs_write_data *data); 297 + 291 298 #ifdef CONFIG_MIGRATION 292 299 extern int nfs_migrate_page(struct address_space *, 293 300 struct page *, struct page *); ··· 317 296 rpc_authflavor_t authflavour, 318 297 int noresvport); 319 298 extern void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data); 320 - extern int _nfs4_call_sync(struct nfs_server *server, 299 + extern int _nfs4_call_sync(struct rpc_clnt *clnt, 300 + struct nfs_server *server, 321 301 struct rpc_message *msg, 322 302 struct nfs4_sequence_args *args, 323 303 struct nfs4_sequence_res *res, 324 304 int cache_reply); 325 - extern int _nfs4_call_sync_session(struct nfs_server *server, 305 + extern int _nfs4_call_sync_session(struct rpc_clnt *clnt, 306 + struct nfs_server *server, 326 307 struct rpc_message *msg, 327 308 struct nfs4_sequence_args *args, 328 309 struct nfs4_sequence_res *res,
+111 -4
fs/nfs/namespace.c
··· 15 15 #include <linux/string.h> 16 16 #include <linux/sunrpc/clnt.h> 17 17 #include <linux/vfs.h> 18 + #include <linux/sunrpc/gss_api.h> 18 19 #include "internal.h" 19 20 20 21 #define NFSDBG_FACILITY NFSDBG_VFS ··· 28 27 29 28 static struct vfsmount *nfs_do_submount(struct dentry *dentry, 30 29 struct nfs_fh *fh, 31 - struct nfs_fattr *fattr); 30 + struct nfs_fattr *fattr, 31 + rpc_authflavor_t authflavor); 32 32 33 33 /* 34 34 * nfs_path - reconstruct the path given an arbitrary dentry ··· 118 116 return ERR_PTR(-ENAMETOOLONG); 119 117 } 120 118 119 + #ifdef CONFIG_NFS_V4 120 + static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors, struct inode *inode) 121 + { 122 + struct gss_api_mech *mech; 123 + struct xdr_netobj oid; 124 + int i; 125 + rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX; 126 + 127 + for (i = 0; i < flavors->num_flavors; i++) { 128 + struct nfs4_secinfo_flavor *flavor; 129 + flavor = &flavors->flavors[i]; 130 + 131 + if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { 132 + pseudoflavor = flavor->flavor; 133 + break; 134 + } else if (flavor->flavor == RPC_AUTH_GSS) { 135 + oid.len = flavor->gss.sec_oid4.len; 136 + oid.data = flavor->gss.sec_oid4.data; 137 + mech = gss_mech_get_by_OID(&oid); 138 + if (!mech) 139 + continue; 140 + pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service); 141 + gss_mech_put(mech); 142 + break; 143 + } 144 + } 145 + 146 + return pseudoflavor; 147 + } 148 + 149 + static rpc_authflavor_t nfs_negotiate_security(const struct dentry *parent, const struct dentry *dentry) 150 + { 151 + int status = 0; 152 + struct page *page; 153 + struct nfs4_secinfo_flavors *flavors; 154 + int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); 155 + rpc_authflavor_t flavor = RPC_AUTH_UNIX; 156 + 157 + secinfo = NFS_PROTO(parent->d_inode)->secinfo; 158 + if (secinfo != NULL) { 159 + page = alloc_page(GFP_KERNEL); 160 + if (!page) { 161 + status = -ENOMEM; 162 + goto out; 163 + } 164 + flavors = page_address(page); 165 + status = secinfo(parent->d_inode, &dentry->d_name, flavors); 166 + flavor = nfs_find_best_sec(flavors, dentry->d_inode); 167 + put_page(page); 168 + } 169 + 170 + return flavor; 171 + 172 + out: 173 + status = -ENOMEM; 174 + return status; 175 + } 176 + 177 + static rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server, struct dentry *parent, 178 + struct dentry *dentry, struct path *path, 179 + struct nfs_fh *fh, struct nfs_fattr *fattr) 180 + { 181 + rpc_authflavor_t flavor; 182 + struct rpc_clnt *clone; 183 + struct rpc_auth *auth; 184 + int err; 185 + 186 + flavor = nfs_negotiate_security(parent, path->dentry); 187 + if (flavor < 0) 188 + goto out; 189 + clone = rpc_clone_client(server->client); 190 + auth = rpcauth_create(flavor, clone); 191 + if (!auth) { 192 + flavor = -EIO; 193 + goto out; 194 + } 195 + err = server->nfs_client->rpc_ops->lookup(clone, parent->d_inode, 196 + &path->dentry->d_name, 197 + fh, fattr); 198 + if (err < 0) 199 + flavor = err; 200 + out: 201 + return flavor; 202 + } 203 + #else /* CONFIG_NFS_V4 */ 204 + static inline rpc_authflavor_t nfs_lookup_with_sec(struct nfs_server *server, 205 + struct dentry *parent, struct dentry *dentry, 206 + struct path *path, struct nfs_fh *fh, 207 + struct nfs_fattr *fattr) 208 + { 209 + return -EPERM; 210 + } 211 + #endif /* CONFIG_NFS_V4 */ 212 + 121 213 /* 122 214 * nfs_d_automount - Handle crossing a mountpoint on the server 123 215 * @path - The mountpoint ··· 232 136 struct nfs_fh *fh = NULL; 233 137 struct nfs_fattr *fattr = NULL; 234 138 int err; 139 + rpc_authflavor_t flavor = 1; 235 140 236 141 dprintk("--> nfs_d_automount()\n"); 237 142 ··· 250 153 251 154 /* Look it up again to get its attributes */ 252 155 parent = dget_parent(path->dentry); 253 - err = server->nfs_client->rpc_ops->lookup(parent->d_inode, 156 + err = server->nfs_client->rpc_ops->lookup(server->client, parent->d_inode, 254 157 &path->dentry->d_name, 255 158 fh, fattr); 159 + if (err == -EPERM) { 160 + flavor = nfs_lookup_with_sec(server, parent, path->dentry, path, fh, fattr); 161 + if (flavor < 0) 162 + err = flavor; 163 + else 164 + err = 0; 165 + } 256 166 dput(parent); 257 167 if (err != 0) { 258 168 mnt = ERR_PTR(err); ··· 269 165 if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 270 166 mnt = nfs_do_refmount(path->dentry); 271 167 else 272 - mnt = nfs_do_submount(path->dentry, fh, fattr); 168 + mnt = nfs_do_submount(path->dentry, fh, fattr, flavor); 273 169 if (IS_ERR(mnt)) 274 170 goto out; 275 171 ··· 336 232 * @dentry - parent directory 337 233 * @fh - filehandle for new root dentry 338 234 * @fattr - attributes for new root inode 235 + * @authflavor - security flavor to use when performing the mount 339 236 * 340 237 */ 341 238 static struct vfsmount *nfs_do_submount(struct dentry *dentry, 342 239 struct nfs_fh *fh, 343 - struct nfs_fattr *fattr) 240 + struct nfs_fattr *fattr, 241 + rpc_authflavor_t authflavor) 344 242 { 345 243 struct nfs_clone_mount mountdata = { 346 244 .sb = dentry->d_sb, 347 245 .dentry = dentry, 348 246 .fh = fh, 349 247 .fattr = fattr, 248 + .authflavor = authflavor, 350 249 }; 351 250 struct vfsmount *mnt = ERR_PTR(-ENOMEM); 352 251 char *page = (char *) __get_free_page(GFP_USER);
+1 -1
fs/nfs/nfs3proc.c
··· 141 141 } 142 142 143 143 static int 144 - nfs3_proc_lookup(struct inode *dir, struct qstr *name, 144 + nfs3_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, 145 145 struct nfs_fh *fhandle, struct nfs_fattr *fattr) 146 146 { 147 147 struct nfs3_diropargs arg = {
+4 -1
fs/nfs/nfs4_fs.h
··· 57 57 struct nfs4_minor_version_ops { 58 58 u32 minor_version; 59 59 60 - int (*call_sync)(struct nfs_server *server, 60 + int (*call_sync)(struct rpc_clnt *clnt, 61 + struct nfs_server *server, 61 62 struct rpc_message *msg, 62 63 struct nfs4_sequence_args *args, 63 64 struct nfs4_sequence_res *res, ··· 263 262 extern int nfs4_init_session(struct nfs_server *server); 264 263 extern int nfs4_proc_get_lease_time(struct nfs_client *clp, 265 264 struct nfs_fsinfo *fsinfo); 265 + extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, 266 + bool sync); 266 267 267 268 static inline bool 268 269 is_ds_only_client(struct nfs_client *clp)
+329 -23
fs/nfs/nfs4filelayout.c
··· 154 154 } 155 155 156 156 /* 157 + * We reference the rpc_cred of the first WRITE that triggers the need for 158 + * a LAYOUTCOMMIT, and use it to send the layoutcommit compound. 159 + * rfc5661 is not clear about which credential should be used. 160 + */ 161 + static void 162 + filelayout_set_layoutcommit(struct nfs_write_data *wdata) 163 + { 164 + if (FILELAYOUT_LSEG(wdata->lseg)->commit_through_mds || 165 + wdata->res.verf->committed == NFS_FILE_SYNC) 166 + return; 167 + 168 + pnfs_set_layoutcommit(wdata); 169 + dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino, 170 + (unsigned long) wdata->lseg->pls_end_pos); 171 + } 172 + 173 + /* 157 174 * Call ops for the async read/write cases 158 175 * In the case of dense layouts, the offset needs to be reset to its 159 176 * original value. ··· 227 210 return -EAGAIN; 228 211 } 229 212 213 + filelayout_set_layoutcommit(data); 214 + return 0; 215 + } 216 + 217 + /* Fake up some data that will cause nfs_commit_release to retry the writes. */ 218 + static void prepare_to_resend_writes(struct nfs_write_data *data) 219 + { 220 + struct nfs_page *first = nfs_list_entry(data->pages.next); 221 + 222 + data->task.tk_status = 0; 223 + memcpy(data->verf.verifier, first->wb_verf.verifier, 224 + sizeof(first->wb_verf.verifier)); 225 + data->verf.verifier[0]++; /* ensure verifier mismatch */ 226 + } 227 + 228 + static int filelayout_commit_done_cb(struct rpc_task *task, 229 + struct nfs_write_data *data) 230 + { 231 + int reset = 0; 232 + 233 + if (filelayout_async_handle_error(task, data->args.context->state, 234 + data->ds_clp, &reset) == -EAGAIN) { 235 + dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", 236 + __func__, data->ds_clp, data->ds_clp->cl_session); 237 + if (reset) { 238 + prepare_to_resend_writes(data); 239 + filelayout_set_lo_fail(data->lseg); 240 + } else 241 + nfs_restart_rpc(task, data->ds_clp); 242 + return -EAGAIN; 243 + } 244 + 230 245 return 0; 231 246 } 232 247 ··· 289 240 wdata->mds_ops->rpc_release(data); 290 241 } 291 242 243 + static void filelayout_commit_release(void *data) 244 + { 245 + struct nfs_write_data *wdata = (struct nfs_write_data *)data; 246 + 247 + nfs_commit_release_pages(wdata); 248 + if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) 249 + nfs_commit_clear_lock(NFS_I(wdata->inode)); 250 + nfs_commitdata_release(wdata); 251 + } 252 + 292 253 struct rpc_call_ops filelayout_read_call_ops = { 293 254 .rpc_call_prepare = filelayout_read_prepare, 294 255 .rpc_call_done = filelayout_read_call_done, ··· 309 250 .rpc_call_prepare = filelayout_write_prepare, 310 251 .rpc_call_done = filelayout_write_call_done, 311 252 .rpc_release = filelayout_write_release, 253 + }; 254 + 255 + struct rpc_call_ops filelayout_commit_call_ops = { 256 + .rpc_call_prepare = filelayout_write_prepare, 257 + .rpc_call_done = filelayout_write_call_done, 258 + .rpc_release = filelayout_commit_release, 312 259 }; 313 260 314 261 static enum pnfs_try_status ··· 384 319 dprintk("%s ino %lu sync %d req %Zu@%llu DS:%x:%hu\n", __func__, 385 320 data->inode->i_ino, sync, (size_t) data->args.count, offset, 386 321 ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); 387 - 388 - /* We can't handle commit to ds yet */ 389 - if (!FILELAYOUT_LSEG(lseg)->commit_through_mds) 390 - data->args.stable = NFS_FILE_SYNC; 391 322 392 323 data->write_done_cb = filelayout_write_done_cb; 393 324 data->ds_clp = ds->ds_clp; ··· 502 441 struct nfs4_layoutget_res *lgr, 503 442 struct nfs4_deviceid *id) 504 443 { 505 - uint32_t *p = (uint32_t *)lgr->layout.buf; 444 + struct xdr_stream stream; 445 + struct xdr_buf buf = { 446 + .pages = lgr->layoutp->pages, 447 + .page_len = lgr->layoutp->len, 448 + .buflen = lgr->layoutp->len, 449 + .len = lgr->layoutp->len, 450 + }; 451 + struct page *scratch; 452 + __be32 *p; 506 453 uint32_t nfl_util; 507 454 int i; 508 455 509 456 dprintk("%s: set_layout_map Begin\n", __func__); 457 + 458 + scratch = alloc_page(GFP_KERNEL); 459 + if (!scratch) 460 + return -ENOMEM; 461 + 462 + xdr_init_decode(&stream, &buf, NULL); 463 + xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); 464 + 465 + /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8), 466 + * num_fh (4) */ 467 + p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20); 468 + if (unlikely(!p)) 469 + goto out_err; 510 470 511 471 memcpy(id, p, sizeof(*id)); 512 472 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); ··· 550 468 __func__, nfl_util, fl->num_fh, fl->first_stripe_index, 551 469 fl->pattern_offset); 552 470 471 + if (!fl->num_fh) 472 + goto out_err; 473 + 553 474 fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *), 554 475 GFP_KERNEL); 555 476 if (!fl->fh_array) 556 - return -ENOMEM; 477 + goto out_err; 557 478 558 479 for (i = 0; i < fl->num_fh; i++) { 559 480 /* Do we want to use a mempool here? */ 560 481 fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); 561 - if (!fl->fh_array[i]) { 562 - filelayout_free_fh_array(fl); 563 - return -ENOMEM; 564 - } 482 + if (!fl->fh_array[i]) 483 + goto out_err_free; 484 + 485 + p = xdr_inline_decode(&stream, 4); 486 + if (unlikely(!p)) 487 + goto out_err_free; 565 488 fl->fh_array[i]->size = be32_to_cpup(p++); 566 489 if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) { 567 490 printk(KERN_ERR "Too big fh %d received %d\n", 568 491 i, fl->fh_array[i]->size); 569 - filelayout_free_fh_array(fl); 570 - return -EIO; 492 + goto out_err_free; 571 493 } 494 + 495 + p = xdr_inline_decode(&stream, fl->fh_array[i]->size); 496 + if (unlikely(!p)) 497 + goto out_err_free; 572 498 memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size); 573 - p += XDR_QUADLEN(fl->fh_array[i]->size); 574 499 dprintk("DEBUG: %s: fh len %d\n", __func__, 575 500 fl->fh_array[i]->size); 576 501 } 577 502 503 + __free_page(scratch); 578 504 return 0; 505 + 506 + out_err_free: 507 + filelayout_free_fh_array(fl); 508 + out_err: 509 + __free_page(scratch); 510 + return -EIO; 511 + } 512 + 513 + static void 514 + filelayout_free_lseg(struct pnfs_layout_segment *lseg) 515 + { 516 + struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); 517 + 518 + dprintk("--> %s\n", __func__); 519 + nfs4_fl_put_deviceid(fl->dsaddr); 520 + kfree(fl->commit_buckets); 521 + _filelayout_free_lseg(fl); 579 522 } 580 523 581 524 static struct pnfs_layout_segment * ··· 621 514 _filelayout_free_lseg(fl); 622 515 return NULL; 623 516 } 517 + 518 + /* This assumes there is only one IOMODE_RW lseg. What 519 + * we really want to do is have a layout_hdr level 520 + * dictionary of <multipath_list4, fh> keys, each 521 + * associated with a struct list_head, populated by calls 522 + * to filelayout_write_pagelist(). 523 + * */ 524 + if ((!fl->commit_through_mds) && (lgr->range.iomode == IOMODE_RW)) { 525 + int i; 526 + int size = (fl->stripe_type == STRIPE_SPARSE) ? 527 + fl->dsaddr->ds_num : fl->dsaddr->stripe_count; 528 + 529 + fl->commit_buckets = kcalloc(size, sizeof(struct list_head), GFP_KERNEL); 530 + if (!fl->commit_buckets) { 531 + filelayout_free_lseg(&fl->generic_hdr); 532 + return NULL; 533 + } 534 + fl->number_of_buckets = size; 535 + for (i = 0; i < size; i++) 536 + INIT_LIST_HEAD(&fl->commit_buckets[i]); 537 + } 624 538 return &fl->generic_hdr; 625 - } 626 - 627 - static void 628 - filelayout_free_lseg(struct pnfs_layout_segment *lseg) 629 - { 630 - struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); 631 - 632 - dprintk("--> %s\n", __func__); 633 - nfs4_fl_put_deviceid(fl->dsaddr); 634 - _filelayout_free_lseg(fl); 635 539 } 636 540 637 541 /* ··· 670 552 return (p_stripe == r_stripe); 671 553 } 672 554 555 + static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg) 556 + { 557 + return !FILELAYOUT_LSEG(lseg)->commit_through_mds; 558 + } 559 + 560 + static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) 561 + { 562 + if (fl->stripe_type == STRIPE_SPARSE) 563 + return nfs4_fl_calc_ds_index(&fl->generic_hdr, j); 564 + else 565 + return j; 566 + } 567 + 568 + struct list_head *filelayout_choose_commit_list(struct nfs_page *req) 569 + { 570 + struct pnfs_layout_segment *lseg = req->wb_commit_lseg; 571 + struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); 572 + u32 i, j; 573 + struct list_head *list; 574 + 575 + /* Note that we are calling nfs4_fl_calc_j_index on each page 576 + * that ends up being committed to a data server. An attractive 577 + * alternative is to add a field to nfs_write_data and nfs_page 578 + * to store the value calculated in filelayout_write_pagelist 579 + * and just use that here. 580 + */ 581 + j = nfs4_fl_calc_j_index(lseg, 582 + (loff_t)req->wb_index << PAGE_CACHE_SHIFT); 583 + i = select_bucket_index(fl, j); 584 + list = &fl->commit_buckets[i]; 585 + if (list_empty(list)) { 586 + /* Non-empty buckets hold a reference on the lseg */ 587 + get_lseg(lseg); 588 + } 589 + return list; 590 + } 591 + 592 + static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) 593 + { 594 + struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 595 + 596 + if (flseg->stripe_type == STRIPE_SPARSE) 597 + return i; 598 + else 599 + return nfs4_fl_calc_ds_index(lseg, i); 600 + } 601 + 602 + static struct nfs_fh * 603 + select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i) 604 + { 605 + struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 606 + 607 + if (flseg->stripe_type == STRIPE_SPARSE) { 608 + if (flseg->num_fh == 1) 609 + i = 0; 610 + else if (flseg->num_fh == 0) 611 + /* Use the MDS OPEN fh set in nfs_read_rpcsetup */ 612 + return NULL; 613 + } 614 + return flseg->fh_array[i]; 615 + } 616 + 617 + static int filelayout_initiate_commit(struct nfs_write_data *data, int how) 618 + { 619 + struct pnfs_layout_segment *lseg = data->lseg; 620 + struct nfs4_pnfs_ds *ds; 621 + u32 idx; 622 + struct nfs_fh *fh; 623 + 624 + idx = calc_ds_index_from_commit(lseg, data->ds_commit_index); 625 + ds = nfs4_fl_prepare_ds(lseg, idx); 626 + if (!ds) { 627 + printk(KERN_ERR "%s: prepare_ds failed, use MDS\n", __func__); 628 + set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); 629 + set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); 630 + prepare_to_resend_writes(data); 631 + data->mds_ops->rpc_release(data); 632 + return -EAGAIN; 633 + } 634 + dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); 635 + data->write_done_cb = filelayout_commit_done_cb; 636 + data->ds_clp = ds->ds_clp; 637 + fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); 638 + if (fh) 639 + data->args.fh = fh; 640 + return nfs_initiate_commit(data, ds->ds_clp->cl_rpcclient, 641 + &filelayout_commit_call_ops, how); 642 + } 643 + 644 + /* 645 + * This is only useful while we are using whole file layouts. 646 + */ 647 + static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) 648 + { 649 + struct pnfs_layout_segment *lseg, *rv = NULL; 650 + 651 + spin_lock(&inode->i_lock); 652 + list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) 653 + if (lseg->pls_range.iomode == IOMODE_RW) 654 + rv = get_lseg(lseg); 655 + spin_unlock(&inode->i_lock); 656 + return rv; 657 + } 658 + 659 + static int alloc_ds_commits(struct inode *inode, struct list_head *list) 660 + { 661 + struct pnfs_layout_segment *lseg; 662 + struct nfs4_filelayout_segment *fl; 663 + struct nfs_write_data *data; 664 + int i, j; 665 + 666 + /* Won't need this when non-whole file layout segments are supported 667 + * instead we will use a pnfs_layout_hdr structure */ 668 + lseg = find_only_write_lseg(inode); 669 + if (!lseg) 670 + return 0; 671 + fl = FILELAYOUT_LSEG(lseg); 672 + for (i = 0; i < fl->number_of_buckets; i++) { 673 + if (list_empty(&fl->commit_buckets[i])) 674 + continue; 675 + data = nfs_commitdata_alloc(); 676 + if (!data) 677 + goto out_bad; 678 + data->ds_commit_index = i; 679 + data->lseg = lseg; 680 + list_add(&data->pages, list); 681 + } 682 + put_lseg(lseg); 683 + return 0; 684 + 685 + out_bad: 686 + for (j = i; j < fl->number_of_buckets; j++) { 687 + if (list_empty(&fl->commit_buckets[i])) 688 + continue; 689 + nfs_retry_commit(&fl->commit_buckets[i], lseg); 690 + put_lseg(lseg); /* associated with emptying bucket */ 691 + } 692 + put_lseg(lseg); 693 + /* Caller will clean up entries put on list */ 694 + return -ENOMEM; 695 + } 696 + 697 + /* This follows nfs_commit_list pretty closely */ 698 + static int 699 + filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, 700 + int how) 701 + { 702 + struct nfs_write_data *data, *tmp; 703 + LIST_HEAD(list); 704 + 705 + if (!list_empty(mds_pages)) { 706 + data = nfs_commitdata_alloc(); 707 + if (!data) 708 + goto out_bad; 709 + data->lseg = NULL; 710 + list_add(&data->pages, &list); 711 + } 712 + 713 + if (alloc_ds_commits(inode, &list)) 714 + goto out_bad; 715 + 716 + list_for_each_entry_safe(data, tmp, &list, pages) { 717 + list_del_init(&data->pages); 718 + atomic_inc(&NFS_I(inode)->commits_outstanding); 719 + if (!data->lseg) { 720 + nfs_init_commit(data, mds_pages, NULL); 721 + nfs_initiate_commit(data, NFS_CLIENT(inode), 722 + data->mds_ops, how); 723 + } else { 724 + nfs_init_commit(data, &FILELAYOUT_LSEG(data->lseg)->commit_buckets[data->ds_commit_index], data->lseg); 725 + filelayout_initiate_commit(data, how); 726 + } 727 + } 728 + return 0; 729 + out_bad: 730 + list_for_each_entry_safe(data, tmp, &list, pages) { 731 + nfs_retry_commit(&data->pages, data->lseg); 732 + list_del_init(&data->pages); 733 + nfs_commit_free(data); 734 + } 735 + nfs_retry_commit(mds_pages, NULL); 736 + nfs_commit_clear_lock(NFS_I(inode)); 737 + return -ENOMEM; 738 + } 739 + 673 740 static struct pnfs_layoutdriver_type filelayout_type = { 674 741 .id = LAYOUT_NFSV4_1_FILES, 675 742 .name = "LAYOUT_NFSV4_1_FILES", ··· 862 559 .alloc_lseg = filelayout_alloc_lseg, 863 560 .free_lseg = filelayout_free_lseg, 864 561 .pg_test = filelayout_pg_test, 562 + .mark_pnfs_commit = filelayout_mark_pnfs_commit, 563 + .choose_commit_list = filelayout_choose_commit_list, 564 + .commit_pagelist = filelayout_commit_pagelist, 865 565 .read_pagelist = filelayout_read_pagelist, 866 566 .write_pagelist = filelayout_write_pagelist, 867 567 };
+2
fs/nfs/nfs4filelayout.h
··· 79 79 struct nfs4_file_layout_dsaddr *dsaddr; /* Point to GETDEVINFO data */ 80 80 unsigned int num_fh; 81 81 struct nfs_fh **fh_array; 82 + struct list_head *commit_buckets; /* Sort commits to ds */ 83 + int number_of_buckets; 82 84 }; 83 85 84 86 static inline struct nfs4_filelayout_segment *
+122 -56
fs/nfs/nfs4filelayoutdev.c
··· 261 261 * Currently only support ipv4, and one multi-path address. 262 262 */ 263 263 static struct nfs4_pnfs_ds * 264 - decode_and_add_ds(__be32 **pp, struct inode *inode) 264 + decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode) 265 265 { 266 266 struct nfs4_pnfs_ds *ds = NULL; 267 267 char *buf; ··· 269 269 u32 ip_addr, port; 270 270 int nlen, rlen, i; 271 271 int tmp[2]; 272 - __be32 *r_netid, *r_addr, *p = *pp; 272 + __be32 *p; 273 273 274 274 /* r_netid */ 275 + p = xdr_inline_decode(streamp, 4); 276 + if (unlikely(!p)) 277 + goto out_err; 275 278 nlen = be32_to_cpup(p++); 276 - r_netid = p; 277 - p += XDR_QUADLEN(nlen); 278 279 279 - /* r_addr */ 280 - rlen = be32_to_cpup(p++); 281 - r_addr = p; 282 - p += XDR_QUADLEN(rlen); 283 - *pp = p; 280 + p = xdr_inline_decode(streamp, nlen); 281 + if (unlikely(!p)) 282 + goto out_err; 284 283 285 284 /* Check that netid is "tcp" */ 286 - if (nlen != 3 || memcmp((char *)r_netid, "tcp", 3)) { 285 + if (nlen != 3 || memcmp((char *)p, "tcp", 3)) { 287 286 dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); 288 287 goto out_err; 289 288 } 289 + 290 + /* r_addr */ 291 + p = xdr_inline_decode(streamp, 4); 292 + if (unlikely(!p)) 293 + goto out_err; 294 + rlen = be32_to_cpup(p); 295 + 296 + p = xdr_inline_decode(streamp, rlen); 297 + if (unlikely(!p)) 298 + goto out_err; 290 299 291 300 /* ipv6 length plus port is legal */ 292 301 if (rlen > INET6_ADDRSTRLEN + 8) { ··· 309 300 goto out_err; 310 301 } 311 302 buf[rlen] = '\0'; 312 - memcpy(buf, r_addr, rlen); 303 + memcpy(buf, p, rlen); 313 304 314 305 /* replace the port dots with dashes for the in4_pton() delimiter*/ 315 306 for (i = 0; i < 2; i++) { ··· 345 336 static struct nfs4_file_layout_dsaddr* 346 337 decode_device(struct inode *ino, struct pnfs_device *pdev) 347 338 { 348 - int i, dummy; 339 + int i; 349 340 u32 cnt, num; 350 341 u8 *indexp; 351 - __be32 *p = (__be32 *)pdev->area, *indicesp; 352 - struct nfs4_file_layout_dsaddr *dsaddr; 342 + __be32 *p; 343 + u8 *stripe_indices; 344 + u8 max_stripe_index; 345 + struct nfs4_file_layout_dsaddr *dsaddr = NULL; 346 + struct xdr_stream stream; 347 + struct xdr_buf buf = { 348 + .pages = pdev->pages, 349 + .page_len = pdev->pglen, 350 + .buflen = pdev->pglen, 351 + .len = pdev->pglen, 352 + }; 353 + struct page *scratch; 354 + 355 + /* set up xdr stream */ 356 + scratch = alloc_page(GFP_KERNEL); 357 + if (!scratch) 358 + goto out_err; 359 + 360 + xdr_init_decode(&stream, &buf, NULL); 361 + xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); 353 362 354 363 /* Get the stripe count (number of stripe index) */ 355 - cnt = be32_to_cpup(p++); 364 + p = xdr_inline_decode(&stream, 4); 365 + if (unlikely(!p)) 366 + goto out_err_free_scratch; 367 + 368 + cnt = be32_to_cpup(p); 356 369 dprintk("%s stripe count %d\n", __func__, cnt); 357 370 if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { 358 371 printk(KERN_WARNING "%s: stripe count %d greater than " 359 372 "supported maximum %d\n", __func__, 360 373 cnt, NFS4_PNFS_MAX_STRIPE_CNT); 361 - goto out_err; 374 + goto out_err_free_scratch; 375 + } 376 + 377 + /* read stripe indices */ 378 + stripe_indices = kcalloc(cnt, sizeof(u8), GFP_KERNEL); 379 + if (!stripe_indices) 380 + goto out_err_free_scratch; 381 + 382 + p = xdr_inline_decode(&stream, cnt << 2); 383 + if (unlikely(!p)) 384 + goto out_err_free_stripe_indices; 385 + 386 + indexp = &stripe_indices[0]; 387 + max_stripe_index = 0; 388 + for (i = 0; i < cnt; i++) { 389 + *indexp = be32_to_cpup(p++); 390 + max_stripe_index = max(max_stripe_index, *indexp); 391 + indexp++; 362 392 } 363 393 364 394 /* Check the multipath list count */ 365 - indicesp = p; 366 - p += XDR_QUADLEN(cnt << 2); 367 - num = be32_to_cpup(p++); 395 + p = xdr_inline_decode(&stream, 4); 396 + if (unlikely(!p)) 397 + goto out_err_free_stripe_indices; 398 + 399 + num = be32_to_cpup(p); 368 400 dprintk("%s ds_num %u\n", __func__, num); 369 401 if (num > NFS4_PNFS_MAX_MULTI_CNT) { 370 402 printk(KERN_WARNING "%s: multipath count %d greater than " 371 403 "supported maximum %d\n", __func__, 372 404 num, NFS4_PNFS_MAX_MULTI_CNT); 373 - goto out_err; 405 + goto out_err_free_stripe_indices; 374 406 } 407 + 408 + /* validate stripe indices are all < num */ 409 + if (max_stripe_index >= num) { 410 + printk(KERN_WARNING "%s: stripe index %u >= num ds %u\n", 411 + __func__, max_stripe_index, num); 412 + goto out_err_free_stripe_indices; 413 + } 414 + 375 415 dsaddr = kzalloc(sizeof(*dsaddr) + 376 416 (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), 377 417 GFP_KERNEL); 378 418 if (!dsaddr) 379 - goto out_err; 380 - 381 - dsaddr->stripe_indices = kzalloc(sizeof(u8) * cnt, GFP_KERNEL); 382 - if (!dsaddr->stripe_indices) 383 - goto out_err_free; 419 + goto out_err_free_stripe_indices; 384 420 385 421 dsaddr->stripe_count = cnt; 422 + dsaddr->stripe_indices = stripe_indices; 423 + stripe_indices = NULL; 386 424 dsaddr->ds_num = num; 387 425 388 426 memcpy(&dsaddr->deviceid, &pdev->dev_id, sizeof(pdev->dev_id)); 389 427 390 - /* Go back an read stripe indices */ 391 - p = indicesp; 392 - indexp = &dsaddr->stripe_indices[0]; 393 - for (i = 0; i < dsaddr->stripe_count; i++) { 394 - *indexp = be32_to_cpup(p++); 395 - if (*indexp >= num) 396 - goto out_err_free; 397 - indexp++; 398 - } 399 - /* Skip already read multipath list count */ 400 - p++; 401 - 402 428 for (i = 0; i < dsaddr->ds_num; i++) { 403 429 int j; 430 + u32 mp_count; 404 431 405 - dummy = be32_to_cpup(p++); /* multipath count */ 406 - if (dummy > 1) { 432 + p = xdr_inline_decode(&stream, 4); 433 + if (unlikely(!p)) 434 + goto out_err_free_deviceid; 435 + 436 + mp_count = be32_to_cpup(p); /* multipath count */ 437 + if (mp_count > 1) { 407 438 printk(KERN_WARNING 408 439 "%s: Multipath count %d not supported, " 409 440 "skipping all greater than 1\n", __func__, 410 - dummy); 441 + mp_count); 411 442 } 412 - for (j = 0; j < dummy; j++) { 443 + for (j = 0; j < mp_count; j++) { 413 444 if (j == 0) { 414 - dsaddr->ds_list[i] = decode_and_add_ds(&p, ino); 445 + dsaddr->ds_list[i] = decode_and_add_ds(&stream, 446 + ino); 415 447 if (dsaddr->ds_list[i] == NULL) 416 - goto out_err_free; 448 + goto out_err_free_deviceid; 417 449 } else { 418 450 u32 len; 419 451 /* skip extra multipath */ 420 - len = be32_to_cpup(p++); 421 - p += XDR_QUADLEN(len); 422 - len = be32_to_cpup(p++); 423 - p += XDR_QUADLEN(len); 424 - continue; 452 + 453 + /* read len, skip */ 454 + p = xdr_inline_decode(&stream, 4); 455 + if (unlikely(!p)) 456 + goto out_err_free_deviceid; 457 + len = be32_to_cpup(p); 458 + 459 + p = xdr_inline_decode(&stream, len); 460 + if (unlikely(!p)) 461 + goto out_err_free_deviceid; 462 + 463 + /* read len, skip */ 464 + p = xdr_inline_decode(&stream, 4); 465 + if (unlikely(!p)) 466 + goto out_err_free_deviceid; 467 + len = be32_to_cpup(p); 468 + 469 + p = xdr_inline_decode(&stream, len); 470 + if (unlikely(!p)) 471 + goto out_err_free_deviceid; 425 472 } 426 473 } 427 474 } 475 + 476 + __free_page(scratch); 428 477 return dsaddr; 429 478 430 - out_err_free: 479 + out_err_free_deviceid: 431 480 nfs4_fl_free_deviceid(dsaddr); 481 + /* stripe_indicies was part of dsaddr */ 482 + goto out_err_free_scratch; 483 + out_err_free_stripe_indices: 484 + kfree(stripe_indices); 485 + out_err_free_scratch: 486 + __free_page(scratch); 432 487 out_err: 433 488 dprintk("%s ERROR: returning NULL\n", __func__); 434 489 return NULL; ··· 571 498 goto out_free; 572 499 } 573 500 574 - /* set pdev->area */ 575 - pdev->area = vmap(pages, max_pages, VM_MAP, PAGE_KERNEL); 576 - if (!pdev->area) 577 - goto out_free; 578 - 579 501 memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id)); 580 502 pdev->layout_type = LAYOUT_NFSV4_1_FILES; 581 503 pdev->pages = pages; ··· 589 521 */ 590 522 dsaddr = decode_and_add_device(inode, pdev); 591 523 out_free: 592 - if (pdev->area != NULL) 593 - vunmap(pdev->area); 594 524 for (i = 0; i < max_pages; i++) 595 525 __free_page(pages[i]); 596 526 kfree(pages);
+246 -56
fs/nfs/nfs4proc.c
··· 41 41 #include <linux/string.h> 42 42 #include <linux/slab.h> 43 43 #include <linux/sunrpc/clnt.h> 44 + #include <linux/sunrpc/gss_api.h> 44 45 #include <linux/nfs.h> 45 46 #include <linux/nfs4.h> 46 47 #include <linux/nfs_fs.h> ··· 72 71 static int _nfs4_recover_proc_open(struct nfs4_opendata *data); 73 72 static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); 74 73 static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); 75 - static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); 74 + static int _nfs4_proc_lookup(struct rpc_clnt *client, struct inode *dir, 75 + const struct qstr *name, struct nfs_fh *fhandle, 76 + struct nfs_fattr *fattr); 76 77 static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); 77 78 static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, 78 79 struct nfs_fattr *fattr, struct iattr *sattr, ··· 88 85 switch (err) { 89 86 case -NFS4ERR_RESOURCE: 90 87 return -EREMOTEIO; 88 + case -NFS4ERR_WRONGSEC: 89 + return -EPERM; 91 90 case -NFS4ERR_BADOWNER: 92 91 case -NFS4ERR_BADNAME: 93 92 return -EINVAL; ··· 662 657 .rpc_call_done = nfs41_call_sync_done, 663 658 }; 664 659 665 - static int nfs4_call_sync_sequence(struct nfs_server *server, 660 + static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, 661 + struct nfs_server *server, 666 662 struct rpc_message *msg, 667 663 struct nfs4_sequence_args *args, 668 664 struct nfs4_sequence_res *res, ··· 679 673 .cache_reply = cache_reply, 680 674 }; 681 675 struct rpc_task_setup task_setup = { 682 - .rpc_client = server->client, 676 + .rpc_client = clnt, 683 677 .rpc_message = msg, 684 678 .callback_ops = &nfs41_call_sync_ops, 685 679 .callback_data = &data ··· 698 692 return ret; 699 693 } 700 694 701 - int _nfs4_call_sync_session(struct nfs_server *server, 695 + int _nfs4_call_sync_session(struct rpc_clnt *clnt, 696 + struct nfs_server *server, 702 697 struct rpc_message *msg, 703 698 struct nfs4_sequence_args *args, 704 699 struct nfs4_sequence_res *res, 705 700 int cache_reply) 706 701 { 707 - return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); 702 + return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0); 708 703 } 709 704 710 705 #else ··· 716 709 } 717 710 #endif /* CONFIG_NFS_V4_1 */ 718 711 719 - int _nfs4_call_sync(struct nfs_server *server, 712 + int _nfs4_call_sync(struct rpc_clnt *clnt, 713 + struct nfs_server *server, 720 714 struct rpc_message *msg, 721 715 struct nfs4_sequence_args *args, 722 716 struct nfs4_sequence_res *res, 723 717 int cache_reply) 724 718 { 725 719 args->sa_session = res->sr_session = NULL; 726 - return rpc_call_sync(server->client, msg, 0); 720 + return rpc_call_sync(clnt, msg, 0); 727 721 } 728 722 729 - #define nfs4_call_sync(server, msg, args, res, cache_reply) \ 730 - (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ 731 - &(res)->seq_res, (cache_reply)) 723 + static inline 724 + int nfs4_call_sync(struct rpc_clnt *clnt, 725 + struct nfs_server *server, 726 + struct rpc_message *msg, 727 + struct nfs4_sequence_args *args, 728 + struct nfs4_sequence_res *res, 729 + int cache_reply) 730 + { 731 + return server->nfs_client->cl_mvops->call_sync(clnt, server, msg, 732 + args, res, cache_reply); 733 + } 732 734 733 735 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) 734 736 { ··· 1847 1831 } else 1848 1832 memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); 1849 1833 1850 - status = nfs4_call_sync(server, &msg, &arg, &res, 1); 1834 + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 1851 1835 if (status == 0 && state != NULL) 1852 1836 renew_lease(server, timestamp); 1853 1837 return status; ··· 2106 2090 }; 2107 2091 int status; 2108 2092 2109 - status = nfs4_call_sync(server, &msg, &args, &res, 0); 2093 + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 2110 2094 if (status == 0) { 2111 2095 memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); 2112 2096 server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS| ··· 2176 2160 }; 2177 2161 2178 2162 nfs_fattr_init(info->fattr); 2179 - return nfs4_call_sync(server, &msg, &args, &res, 0); 2163 + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 2180 2164 } 2181 2165 2182 2166 static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, ··· 2192 2176 return err; 2193 2177 } 2194 2178 2179 + static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, 2180 + struct nfs_fsinfo *info, rpc_authflavor_t flavor) 2181 + { 2182 + struct rpc_auth *auth; 2183 + int ret; 2184 + 2185 + auth = rpcauth_create(flavor, server->client); 2186 + if (!auth) { 2187 + ret = -EIO; 2188 + goto out; 2189 + } 2190 + ret = nfs4_lookup_root(server, fhandle, info); 2191 + if (ret < 0) 2192 + ret = -EAGAIN; 2193 + out: 2194 + return ret; 2195 + } 2196 + 2195 2197 /* 2196 2198 * get the file handle for the "/" directory on the server 2197 2199 */ 2198 2200 static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, 2199 2201 struct nfs_fsinfo *info) 2200 2202 { 2201 - int status; 2203 + int i, len, status = 0; 2204 + rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS + 2]; 2202 2205 2203 - status = nfs4_lookup_root(server, fhandle, info); 2206 + flav_array[0] = RPC_AUTH_UNIX; 2207 + len = gss_mech_list_pseudoflavors(&flav_array[1]); 2208 + flav_array[1+len] = RPC_AUTH_NULL; 2209 + len += 2; 2210 + 2211 + for (i = 0; i < len; i++) { 2212 + status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]); 2213 + if (status == 0) 2214 + break; 2215 + } 2204 2216 if (status == 0) 2205 2217 status = nfs4_server_capabilities(server, fhandle); 2206 2218 if (status == 0) ··· 2293 2249 }; 2294 2250 2295 2251 nfs_fattr_init(fattr); 2296 - return nfs4_call_sync(server, &msg, &args, &res, 0); 2252 + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 2297 2253 } 2298 2254 2299 2255 static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) ··· 2353 2309 return status; 2354 2310 } 2355 2311 2356 - static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh, 2357 - const struct qstr *name, struct nfs_fh *fhandle, 2358 - struct nfs_fattr *fattr) 2312 + static int _nfs4_proc_lookupfh(struct rpc_clnt *clnt, struct nfs_server *server, 2313 + const struct nfs_fh *dirfh, const struct qstr *name, 2314 + struct nfs_fh *fhandle, struct nfs_fattr *fattr) 2359 2315 { 2360 2316 int status; 2361 2317 struct nfs4_lookup_arg args = { ··· 2377 2333 nfs_fattr_init(fattr); 2378 2334 2379 2335 dprintk("NFS call lookupfh %s\n", name->name); 2380 - status = nfs4_call_sync(server, &msg, &args, &res, 0); 2336 + status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0); 2381 2337 dprintk("NFS reply lookupfh: %d\n", status); 2382 2338 return status; 2383 2339 } ··· 2389 2345 struct nfs4_exception exception = { }; 2390 2346 int err; 2391 2347 do { 2392 - err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); 2348 + err = _nfs4_proc_lookupfh(server->client, server, dirfh, name, fhandle, fattr); 2393 2349 /* FIXME: !!!! */ 2394 2350 if (err == -NFS4ERR_MOVED) { 2395 2351 err = -EREMOTE; ··· 2400 2356 return err; 2401 2357 } 2402 2358 2403 - static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, 2404 - struct nfs_fh *fhandle, struct nfs_fattr *fattr) 2359 + static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, 2360 + const struct qstr *name, struct nfs_fh *fhandle, 2361 + struct nfs_fattr *fattr) 2405 2362 { 2406 2363 int status; 2407 2364 2408 2365 dprintk("NFS call lookup %s\n", name->name); 2409 - status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); 2366 + status = _nfs4_proc_lookupfh(clnt, NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr); 2410 2367 if (status == -NFS4ERR_MOVED) 2411 2368 status = nfs4_get_referral(dir, name, fattr, fhandle); 2412 2369 dprintk("NFS reply lookup: %d\n", status); 2413 2370 return status; 2414 2371 } 2415 2372 2416 - static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) 2373 + void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh) 2374 + { 2375 + memset(fh, 0, sizeof(struct nfs_fh)); 2376 + fattr->fsid.major = 1; 2377 + fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE | 2378 + NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT; 2379 + fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO; 2380 + fattr->nlink = 2; 2381 + } 2382 + 2383 + static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, 2384 + struct nfs_fh *fhandle, struct nfs_fattr *fattr) 2417 2385 { 2418 2386 struct nfs4_exception exception = { }; 2419 2387 int err; 2420 2388 do { 2421 2389 err = nfs4_handle_exception(NFS_SERVER(dir), 2422 - _nfs4_proc_lookup(dir, name, fhandle, fattr), 2390 + _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr), 2423 2391 &exception); 2392 + if (err == -EPERM) 2393 + nfs_fixup_secinfo_attributes(fattr, fhandle); 2424 2394 } while (exception.retry); 2425 2395 return err; 2426 2396 } ··· 2479 2421 if (res.fattr == NULL) 2480 2422 return -ENOMEM; 2481 2423 2482 - status = nfs4_call_sync(server, &msg, &args, &res, 0); 2424 + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 2483 2425 if (!status) { 2484 2426 entry->mask = 0; 2485 2427 if (res.access & NFS4_ACCESS_READ) ··· 2546 2488 .rpc_resp = &res, 2547 2489 }; 2548 2490 2549 - return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); 2491 + return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); 2550 2492 } 2551 2493 2552 2494 static int nfs4_proc_readlink(struct inode *inode, struct page *page, ··· 2635 2577 if (res.dir_attr == NULL) 2636 2578 goto out; 2637 2579 2638 - status = nfs4_call_sync(server, &msg, &args, &res, 1); 2580 + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); 2639 2581 if (status == 0) { 2640 2582 update_changeattr(dir, &res.cinfo); 2641 2583 nfs_post_op_update_inode(dir, res.dir_attr); ··· 2736 2678 if (res.old_fattr == NULL || res.new_fattr == NULL) 2737 2679 goto out; 2738 2680 2739 - status = nfs4_call_sync(server, &msg, &arg, &res, 1); 2681 + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 2740 2682 if (!status) { 2741 2683 update_changeattr(old_dir, &res.old_cinfo); 2742 2684 nfs_post_op_update_inode(old_dir, res.old_fattr); ··· 2787 2729 if (res.fattr == NULL || res.dir_attr == NULL) 2788 2730 goto out; 2789 2731 2790 - status = nfs4_call_sync(server, &msg, &arg, &res, 1); 2732 + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 2791 2733 if (!status) { 2792 2734 update_changeattr(dir, &res.cinfo); 2793 2735 nfs_post_op_update_inode(dir, res.dir_attr); ··· 2850 2792 2851 2793 static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) 2852 2794 { 2853 - int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, 2854 - &data->arg, &data->res, 1); 2795 + int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg, 2796 + &data->arg.seq_args, &data->res.seq_res, 1); 2855 2797 if (status == 0) { 2856 2798 update_changeattr(dir, &data->res.dir_cinfo); 2857 2799 nfs_post_op_update_inode(dir, data->res.dir_fattr); ··· 2963 2905 (unsigned long long)cookie); 2964 2906 nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); 2965 2907 res.pgbase = args.pgbase; 2966 - status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); 2908 + status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); 2967 2909 if (status >= 0) { 2968 2910 memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); 2969 2911 status += args.pgbase; ··· 3055 2997 }; 3056 2998 3057 2999 nfs_fattr_init(fsstat->fattr); 3058 - return nfs4_call_sync(server, &msg, &args, &res, 0); 3000 + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 3059 3001 } 3060 3002 3061 3003 static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) ··· 3086 3028 .rpc_resp = &res, 3087 3029 }; 3088 3030 3089 - return nfs4_call_sync(server, &msg, &args, &res, 0); 3031 + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 3090 3032 } 3091 3033 3092 3034 static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) ··· 3131 3073 } 3132 3074 3133 3075 nfs_fattr_init(pathconf->fattr); 3134 - return nfs4_call_sync(server, &msg, &args, &res, 0); 3076 + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 3135 3077 } 3136 3078 3137 3079 static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, ··· 3253 3195 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; 3254 3196 } 3255 3197 3256 - static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) 3198 + static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data) 3257 3199 { 3258 3200 struct inode *inode = data->inode; 3259 - 3260 - if (!nfs4_sequence_done(task, &data->res.seq_res)) 3261 - return -EAGAIN; 3262 3201 3263 3202 if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { 3264 3203 nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); ··· 3265 3210 return 0; 3266 3211 } 3267 3212 3213 + static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) 3214 + { 3215 + if (!nfs4_sequence_done(task, &data->res.seq_res)) 3216 + return -EAGAIN; 3217 + return data->write_done_cb(task, data); 3218 + } 3219 + 3268 3220 static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg) 3269 3221 { 3270 3222 struct nfs_server *server = NFS_SERVER(data->inode); 3271 - 3272 - data->args.bitmask = server->cache_consistency_bitmask; 3223 + 3224 + if (data->lseg) { 3225 + data->args.bitmask = NULL; 3226 + data->res.fattr = NULL; 3227 + } else 3228 + data->args.bitmask = server->cache_consistency_bitmask; 3229 + if (!data->write_done_cb) 3230 + data->write_done_cb = nfs4_commit_done_cb; 3273 3231 data->res.server = server; 3274 3232 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; 3275 3233 } ··· 3520 3452 resp_buf = buf; 3521 3453 buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); 3522 3454 } 3523 - ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); 3455 + ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0); 3524 3456 if (ret) 3525 3457 goto out_free; 3526 3458 if (res.acl_len > args.acl_len) ··· 3595 3527 if (i < 0) 3596 3528 return i; 3597 3529 nfs_inode_return_delegation(inode); 3598 - ret = nfs4_call_sync(server, &msg, &arg, &res, 1); 3530 + ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 3599 3531 3600 3532 /* 3601 3533 * Free each page after tx, so the only ref left is ··· 3958 3890 lsp = request->fl_u.nfs4_fl.owner; 3959 3891 arg.lock_owner.id = lsp->ls_id.id; 3960 3892 arg.lock_owner.s_dev = server->s_dev; 3961 - status = nfs4_call_sync(server, &msg, &arg, &res, 1); 3893 + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); 3962 3894 switch (status) { 3963 3895 case 0: 3964 3896 request->fl_type = F_UNLCK; ··· 4686 4618 nfs_fattr_init(&fs_locations->fattr); 4687 4619 fs_locations->server = server; 4688 4620 fs_locations->nlocations = 0; 4689 - status = nfs4_call_sync(server, &msg, &args, &res, 0); 4621 + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 4690 4622 nfs_fixup_referral_attributes(&fs_locations->fattr); 4691 4623 dprintk("%s: returned status = %d\n", __func__, status); 4692 4624 return status; 4625 + } 4626 + 4627 + static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) 4628 + { 4629 + int status; 4630 + struct nfs4_secinfo_arg args = { 4631 + .dir_fh = NFS_FH(dir), 4632 + .name = name, 4633 + }; 4634 + struct nfs4_secinfo_res res = { 4635 + .flavors = flavors, 4636 + }; 4637 + struct rpc_message msg = { 4638 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO], 4639 + .rpc_argp = &args, 4640 + .rpc_resp = &res, 4641 + }; 4642 + 4643 + dprintk("NFS call secinfo %s\n", name->name); 4644 + status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0); 4645 + dprintk("NFS reply secinfo: %d\n", status); 4646 + return status; 4647 + } 4648 + 4649 + int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors) 4650 + { 4651 + struct nfs4_exception exception = { }; 4652 + int err; 4653 + do { 4654 + err = nfs4_handle_exception(NFS_SERVER(dir), 4655 + _nfs4_proc_secinfo(dir, name, flavors), 4656 + &exception); 4657 + } while (exception.retry); 4658 + return err; 4693 4659 } 4694 4660 4695 4661 #ifdef CONFIG_NFS_V4_1 ··· 5618 5516 struct nfs4_layoutget *lgp = calldata; 5619 5517 5620 5518 dprintk("--> %s\n", __func__); 5621 - if (lgp->res.layout.buf != NULL) 5622 - free_page((unsigned long) lgp->res.layout.buf); 5623 5519 put_nfs_open_context(lgp->args.ctx); 5624 5520 kfree(calldata); 5625 5521 dprintk("<-- %s\n", __func__); ··· 5649 5549 5650 5550 dprintk("--> %s\n", __func__); 5651 5551 5652 - lgp->res.layout.buf = (void *)__get_free_page(GFP_NOFS); 5653 - if (lgp->res.layout.buf == NULL) { 5654 - nfs4_layoutget_release(lgp); 5655 - return -ENOMEM; 5656 - } 5657 - 5552 + lgp->res.layoutp = &lgp->args.layout; 5658 5553 lgp->res.seq_res.sr_slot = NULL; 5659 5554 task = rpc_run_task(&task_setup_data); 5660 5555 if (IS_ERR(task)) ··· 5681 5586 int status; 5682 5587 5683 5588 dprintk("--> %s\n", __func__); 5684 - status = nfs4_call_sync(server, &msg, &args, &res, 0); 5589 + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 5685 5590 dprintk("<-- %s status=%d\n", __func__, status); 5686 5591 5687 5592 return status; ··· 5701 5606 } 5702 5607 EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); 5703 5608 5609 + static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) 5610 + { 5611 + struct nfs4_layoutcommit_data *data = calldata; 5612 + struct nfs_server *server = NFS_SERVER(data->args.inode); 5613 + 5614 + if (nfs4_setup_sequence(server, &data->args.seq_args, 5615 + &data->res.seq_res, 1, task)) 5616 + return; 5617 + rpc_call_start(task); 5618 + } 5619 + 5620 + static void 5621 + nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) 5622 + { 5623 + struct nfs4_layoutcommit_data *data = calldata; 5624 + struct nfs_server *server = NFS_SERVER(data->args.inode); 5625 + 5626 + if (!nfs4_sequence_done(task, &data->res.seq_res)) 5627 + return; 5628 + 5629 + switch (task->tk_status) { /* Just ignore these failures */ 5630 + case NFS4ERR_DELEG_REVOKED: /* layout was recalled */ 5631 + case NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ 5632 + case NFS4ERR_BADLAYOUT: /* no layout */ 5633 + case NFS4ERR_GRACE: /* loca_recalim always false */ 5634 + task->tk_status = 0; 5635 + } 5636 + 5637 + if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { 5638 + nfs_restart_rpc(task, server->nfs_client); 5639 + return; 5640 + } 5641 + 5642 + if (task->tk_status == 0) 5643 + nfs_post_op_update_inode_force_wcc(data->args.inode, 5644 + data->res.fattr); 5645 + } 5646 + 5647 + static void nfs4_layoutcommit_release(void *calldata) 5648 + { 5649 + struct nfs4_layoutcommit_data *data = calldata; 5650 + 5651 + /* Matched by references in pnfs_set_layoutcommit */ 5652 + put_lseg(data->lseg); 5653 + put_rpccred(data->cred); 5654 + kfree(data); 5655 + } 5656 + 5657 + static const struct rpc_call_ops nfs4_layoutcommit_ops = { 5658 + .rpc_call_prepare = nfs4_layoutcommit_prepare, 5659 + .rpc_call_done = nfs4_layoutcommit_done, 5660 + .rpc_release = nfs4_layoutcommit_release, 5661 + }; 5662 + 5663 + int 5664 + nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) 5665 + { 5666 + struct rpc_message msg = { 5667 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT], 5668 + .rpc_argp = &data->args, 5669 + .rpc_resp = &data->res, 5670 + .rpc_cred = data->cred, 5671 + }; 5672 + struct rpc_task_setup task_setup_data = { 5673 + .task = &data->task, 5674 + .rpc_client = NFS_CLIENT(data->args.inode), 5675 + .rpc_message = &msg, 5676 + .callback_ops = &nfs4_layoutcommit_ops, 5677 + .callback_data = data, 5678 + .flags = RPC_TASK_ASYNC, 5679 + }; 5680 + struct rpc_task *task; 5681 + int status = 0; 5682 + 5683 + dprintk("NFS: %4d initiating layoutcommit call. sync %d " 5684 + "lbw: %llu inode %lu\n", 5685 + data->task.tk_pid, sync, 5686 + data->args.lastbytewritten, 5687 + data->args.inode->i_ino); 5688 + 5689 + task = rpc_run_task(&task_setup_data); 5690 + if (IS_ERR(task)) 5691 + return PTR_ERR(task); 5692 + if (sync == false) 5693 + goto out; 5694 + status = nfs4_wait_for_completion_rpc_task(task); 5695 + if (status != 0) 5696 + goto out; 5697 + status = task->tk_status; 5698 + out: 5699 + dprintk("%s: status %d\n", __func__, status); 5700 + rpc_put_task(task); 5701 + return status; 5702 + } 5704 5703 #endif /* CONFIG_NFS_V4_1 */ 5705 5704 5706 5705 struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { ··· 5930 5741 .close_context = nfs4_close_context, 5931 5742 .open_context = nfs4_atomic_open, 5932 5743 .init_client = nfs4_init_client, 5744 + .secinfo = nfs4_proc_secinfo, 5933 5745 }; 5934 5746 5935 5747 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
+295 -18
fs/nfs/nfs4xdr.c
··· 46 46 #include <linux/kdev_t.h> 47 47 #include <linux/sunrpc/clnt.h> 48 48 #include <linux/sunrpc/msg_prot.h> 49 + #include <linux/sunrpc/gss_api.h> 49 50 #include <linux/nfs.h> 50 51 #include <linux/nfs4.h> 51 52 #include <linux/nfs_fs.h> ··· 113 112 #define encode_restorefh_maxsz (op_encode_hdr_maxsz) 114 113 #define decode_restorefh_maxsz (op_decode_hdr_maxsz) 115 114 #define encode_fsinfo_maxsz (encode_getattr_maxsz) 116 - #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) 115 + #define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 15) 117 116 #define encode_renew_maxsz (op_encode_hdr_maxsz + 3) 118 117 #define decode_renew_maxsz (op_decode_hdr_maxsz) 119 118 #define encode_setclientid_maxsz \ ··· 254 253 (encode_getattr_maxsz) 255 254 #define decode_fs_locations_maxsz \ 256 255 (0) 256 + #define encode_secinfo_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) 257 + #define decode_secinfo_maxsz (op_decode_hdr_maxsz + 4 + (NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN))) 257 258 258 259 #if defined(CONFIG_NFS_V4_1) 259 260 #define NFS4_MAX_MACHINE_NAME_LEN (64) ··· 327 324 #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ 328 325 decode_stateid_maxsz + \ 329 326 XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) 327 + #define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \ 328 + 2 /* offset */ + \ 329 + 2 /* length */ + \ 330 + 1 /* reclaim */ + \ 331 + encode_stateid_maxsz + \ 332 + 1 /* new offset (true) */ + \ 333 + 2 /* last byte written */ + \ 334 + 1 /* nt_timechanged (false) */ + \ 335 + 1 /* layoutupdate4 layout type */ + \ 336 + 1 /* NULL filelayout layoutupdate4 payload */) 337 + #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3) 338 + 330 339 #else /* CONFIG_NFS_V4_1 */ 331 340 #define encode_sequence_maxsz 0 332 341 #define decode_sequence_maxsz 0 ··· 691 676 decode_putfh_maxsz + \ 692 677 decode_lookup_maxsz + \ 693 678 decode_fs_locations_maxsz) 679 + #define NFS4_enc_secinfo_sz (compound_encode_hdr_maxsz + \ 680 + encode_sequence_maxsz + \ 681 + encode_putfh_maxsz + \ 682 + encode_secinfo_maxsz) 683 + #define NFS4_dec_secinfo_sz (compound_decode_hdr_maxsz + \ 684 + decode_sequence_maxsz + \ 685 + decode_putfh_maxsz + \ 686 + decode_secinfo_maxsz) 694 687 #if defined(CONFIG_NFS_V4_1) 695 688 #define NFS4_enc_exchange_id_sz \ 696 689 (compound_encode_hdr_maxsz + \ ··· 750 727 decode_sequence_maxsz + \ 751 728 decode_putfh_maxsz + \ 752 729 decode_layoutget_maxsz) 730 + #define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \ 731 + encode_sequence_maxsz +\ 732 + encode_putfh_maxsz + \ 733 + encode_layoutcommit_maxsz + \ 734 + encode_getattr_maxsz) 735 + #define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \ 736 + decode_sequence_maxsz + \ 737 + decode_putfh_maxsz + \ 738 + decode_layoutcommit_maxsz + \ 739 + decode_getattr_maxsz) 740 + 753 741 754 742 const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + 755 743 compound_encode_hdr_maxsz + ··· 1654 1620 hdr->replen += decode_delegreturn_maxsz; 1655 1621 } 1656 1622 1623 + static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) 1624 + { 1625 + int len = name->len; 1626 + __be32 *p; 1627 + 1628 + p = reserve_space(xdr, 8 + len); 1629 + *p++ = cpu_to_be32(OP_SECINFO); 1630 + xdr_encode_opaque(p, name->name, len); 1631 + hdr->nops++; 1632 + hdr->replen += decode_secinfo_maxsz; 1633 + } 1634 + 1657 1635 #if defined(CONFIG_NFS_V4_1) 1658 1636 /* NFSv4.1 operations */ 1659 1637 static void encode_exchange_id(struct xdr_stream *xdr, ··· 1861 1815 args->maxcount); 1862 1816 hdr->nops++; 1863 1817 hdr->replen += decode_layoutget_maxsz; 1818 + } 1819 + 1820 + static int 1821 + encode_layoutcommit(struct xdr_stream *xdr, 1822 + const struct nfs4_layoutcommit_args *args, 1823 + struct compound_hdr *hdr) 1824 + { 1825 + __be32 *p; 1826 + 1827 + dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten, 1828 + NFS_SERVER(args->inode)->pnfs_curr_ld->id); 1829 + 1830 + p = reserve_space(xdr, 48 + NFS4_STATEID_SIZE); 1831 + *p++ = cpu_to_be32(OP_LAYOUTCOMMIT); 1832 + /* Only whole file layouts */ 1833 + p = xdr_encode_hyper(p, 0); /* offset */ 1834 + p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */ 1835 + *p++ = cpu_to_be32(0); /* reclaim */ 1836 + p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE); 1837 + *p++ = cpu_to_be32(1); /* newoffset = TRUE */ 1838 + p = xdr_encode_hyper(p, args->lastbytewritten); 1839 + *p++ = cpu_to_be32(0); /* Never send time_modify_changed */ 1840 + *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */ 1841 + *p++ = cpu_to_be32(0); /* no file layout payload */ 1842 + 1843 + hdr->nops++; 1844 + hdr->replen += decode_layoutcommit_maxsz; 1845 + return 0; 1864 1846 } 1865 1847 #endif /* CONFIG_NFS_V4_1 */ 1866 1848 ··· 2368 2294 encode_sequence(xdr, &args->seq_args, &hdr); 2369 2295 encode_putfh(xdr, args->fh, &hdr); 2370 2296 encode_commit(xdr, args, &hdr); 2371 - encode_getfattr(xdr, args->bitmask, &hdr); 2297 + if (args->bitmask) 2298 + encode_getfattr(xdr, args->bitmask, &hdr); 2372 2299 encode_nops(&hdr); 2373 2300 } 2374 2301 ··· 2540 2465 encode_nops(&hdr); 2541 2466 } 2542 2467 2468 + /* 2469 + * Encode SECINFO request 2470 + */ 2471 + static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req, 2472 + struct xdr_stream *xdr, 2473 + struct nfs4_secinfo_arg *args) 2474 + { 2475 + struct compound_hdr hdr = { 2476 + .minorversion = nfs4_xdr_minorversion(&args->seq_args), 2477 + }; 2478 + 2479 + encode_compound_hdr(xdr, req, &hdr); 2480 + encode_sequence(xdr, &args->seq_args, &hdr); 2481 + encode_putfh(xdr, args->dir_fh, &hdr); 2482 + encode_secinfo(xdr, args->name, &hdr); 2483 + encode_nops(&hdr); 2484 + } 2485 + 2543 2486 #if defined(CONFIG_NFS_V4_1) 2544 2487 /* 2545 2488 * EXCHANGE_ID request ··· 2697 2604 encode_sequence(xdr, &args->seq_args, &hdr); 2698 2605 encode_putfh(xdr, NFS_FH(args->inode), &hdr); 2699 2606 encode_layoutget(xdr, args, &hdr); 2607 + 2608 + xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, 2609 + args->layout.pages, 0, args->layout.pglen); 2610 + 2700 2611 encode_nops(&hdr); 2612 + } 2613 + 2614 + /* 2615 + * Encode LAYOUTCOMMIT request 2616 + */ 2617 + static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req, 2618 + struct xdr_stream *xdr, 2619 + struct nfs4_layoutcommit_args *args) 2620 + { 2621 + struct compound_hdr hdr = { 2622 + .minorversion = nfs4_xdr_minorversion(&args->seq_args), 2623 + }; 2624 + 2625 + encode_compound_hdr(xdr, req, &hdr); 2626 + encode_sequence(xdr, &args->seq_args, &hdr); 2627 + encode_putfh(xdr, NFS_FH(args->inode), &hdr); 2628 + encode_layoutcommit(xdr, args, &hdr); 2629 + encode_getfattr(xdr, args->bitmask, &hdr); 2630 + encode_nops(&hdr); 2631 + return 0; 2701 2632 } 2702 2633 #endif /* CONFIG_NFS_V4_1 */ 2703 2634 ··· 3042 2925 if (unlikely(!p)) 3043 2926 goto out_overflow; 3044 2927 bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR; 2928 + return -be32_to_cpup(p); 3045 2929 } 3046 2930 return 0; 3047 2931 out_overflow: ··· 4030 3912 fattr->valid |= status; 4031 3913 4032 3914 status = decode_attr_error(xdr, bitmap); 3915 + if (status == -NFS4ERR_WRONGSEC) { 3916 + nfs_fixup_secinfo_attributes(fattr, fh); 3917 + status = 0; 3918 + } 4033 3919 if (status < 0) 4034 3920 goto xdr_error; 4035 3921 ··· 4802 4680 return decode_op_hdr(xdr, OP_DELEGRETURN); 4803 4681 } 4804 4682 4683 + static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor) 4684 + { 4685 + __be32 *p; 4686 + 4687 + p = xdr_inline_decode(xdr, 4); 4688 + if (unlikely(!p)) 4689 + goto out_overflow; 4690 + flavor->gss.sec_oid4.len = be32_to_cpup(p); 4691 + if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN) 4692 + goto out_err; 4693 + 4694 + p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len); 4695 + if (unlikely(!p)) 4696 + goto out_overflow; 4697 + memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len); 4698 + 4699 + p = xdr_inline_decode(xdr, 8); 4700 + if (unlikely(!p)) 4701 + goto out_overflow; 4702 + flavor->gss.qop4 = be32_to_cpup(p++); 4703 + flavor->gss.service = be32_to_cpup(p); 4704 + 4705 + return 0; 4706 + 4707 + out_overflow: 4708 + print_overflow_msg(__func__, xdr); 4709 + return -EIO; 4710 + out_err: 4711 + return -EINVAL; 4712 + } 4713 + 4714 + static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) 4715 + { 4716 + struct nfs4_secinfo_flavor *sec_flavor; 4717 + int status; 4718 + __be32 *p; 4719 + int i; 4720 + 4721 + status = decode_op_hdr(xdr, OP_SECINFO); 4722 + p = xdr_inline_decode(xdr, 4); 4723 + if (unlikely(!p)) 4724 + goto out_overflow; 4725 + res->flavors->num_flavors = be32_to_cpup(p); 4726 + 4727 + for (i = 0; i < res->flavors->num_flavors; i++) { 4728 + sec_flavor = &res->flavors->flavors[i]; 4729 + if ((char *)&sec_flavor[1] - (char *)res > PAGE_SIZE) 4730 + break; 4731 + 4732 + p = xdr_inline_decode(xdr, 4); 4733 + if (unlikely(!p)) 4734 + goto out_overflow; 4735 + sec_flavor->flavor = be32_to_cpup(p); 4736 + 4737 + if (sec_flavor->flavor == RPC_AUTH_GSS) { 4738 + if (decode_secinfo_gss(xdr, sec_flavor)) 4739 + break; 4740 + } 4741 + } 4742 + 4743 + return 0; 4744 + 4745 + out_overflow: 4746 + print_overflow_msg(__func__, xdr); 4747 + return -EIO; 4748 + } 4749 + 4805 4750 #if defined(CONFIG_NFS_V4_1) 4806 4751 static int decode_exchange_id(struct xdr_stream *xdr, 4807 4752 struct nfs41_exchange_id_res *res) ··· 5139 4950 __be32 *p; 5140 4951 int status; 5141 4952 u32 layout_count; 4953 + struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 4954 + struct kvec *iov = rcvbuf->head; 4955 + u32 hdrlen, recvd; 5142 4956 5143 4957 status = decode_op_hdr(xdr, OP_LAYOUTGET); 5144 4958 if (status) ··· 5158 4966 return -EINVAL; 5159 4967 } 5160 4968 5161 - p = xdr_inline_decode(xdr, 24); 4969 + p = xdr_inline_decode(xdr, 28); 5162 4970 if (unlikely(!p)) 5163 4971 goto out_overflow; 5164 4972 p = xdr_decode_hyper(p, &res->range.offset); 5165 4973 p = xdr_decode_hyper(p, &res->range.length); 5166 4974 res->range.iomode = be32_to_cpup(p++); 5167 4975 res->type = be32_to_cpup(p++); 5168 - 5169 - status = decode_opaque_inline(xdr, &res->layout.len, (char **)&p); 5170 - if (unlikely(status)) 5171 - return status; 4976 + res->layoutp->len = be32_to_cpup(p); 5172 4977 5173 4978 dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n", 5174 4979 __func__, ··· 5173 4984 (unsigned long)res->range.length, 5174 4985 res->range.iomode, 5175 4986 res->type, 5176 - res->layout.len); 4987 + res->layoutp->len); 5177 4988 5178 - /* nfs4_proc_layoutget allocated a single page */ 5179 - if (res->layout.len > PAGE_SIZE) 5180 - return -ENOMEM; 5181 - memcpy(res->layout.buf, p, res->layout.len); 4989 + hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base; 4990 + recvd = req->rq_rcv_buf.len - hdrlen; 4991 + if (res->layoutp->len > recvd) { 4992 + dprintk("NFS: server cheating in layoutget reply: " 4993 + "layout len %u > recvd %u\n", 4994 + res->layoutp->len, recvd); 4995 + return -EINVAL; 4996 + } 4997 + 4998 + xdr_read_pages(xdr, res->layoutp->len); 5182 4999 5183 5000 if (layout_count > 1) { 5184 5001 /* We only handle a length one array at the moment. Any ··· 5196 5001 __func__, layout_count); 5197 5002 } 5198 5003 5004 + return 0; 5005 + out_overflow: 5006 + print_overflow_msg(__func__, xdr); 5007 + return -EIO; 5008 + } 5009 + 5010 + static int decode_layoutcommit(struct xdr_stream *xdr, 5011 + struct rpc_rqst *req, 5012 + struct nfs4_layoutcommit_res *res) 5013 + { 5014 + __be32 *p; 5015 + __u32 sizechanged; 5016 + int status; 5017 + 5018 + status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT); 5019 + if (status) 5020 + return status; 5021 + 5022 + p = xdr_inline_decode(xdr, 4); 5023 + if (unlikely(!p)) 5024 + goto out_overflow; 5025 + sizechanged = be32_to_cpup(p); 5026 + 5027 + if (sizechanged) { 5028 + /* throw away new size */ 5029 + p = xdr_inline_decode(xdr, 8); 5030 + if (unlikely(!p)) 5031 + goto out_overflow; 5032 + } 5199 5033 return 0; 5200 5034 out_overflow: 5201 5035 print_overflow_msg(__func__, xdr); ··· 5947 5723 status = decode_commit(xdr, res); 5948 5724 if (status) 5949 5725 goto out; 5950 - decode_getfattr(xdr, res->fattr, res->server, 5951 - !RPC_IS_ASYNC(rqstp->rq_task)); 5726 + if (res->fattr) 5727 + decode_getfattr(xdr, res->fattr, res->server, 5728 + !RPC_IS_ASYNC(rqstp->rq_task)); 5952 5729 out: 5953 5730 return status; 5954 5731 } ··· 6144 5919 return status; 6145 5920 } 6146 5921 5922 + /* 5923 + * Decode SECINFO response 5924 + */ 5925 + static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp, 5926 + struct xdr_stream *xdr, 5927 + struct nfs4_secinfo_res *res) 5928 + { 5929 + struct compound_hdr hdr; 5930 + int status; 5931 + 5932 + status = decode_compound_hdr(xdr, &hdr); 5933 + if (status) 5934 + goto out; 5935 + status = decode_sequence(xdr, &res->seq_res, rqstp); 5936 + if (status) 5937 + goto out; 5938 + status = decode_putfh(xdr); 5939 + if (status) 5940 + goto out; 5941 + status = decode_secinfo(xdr, res); 5942 + if (status) 5943 + goto out; 5944 + out: 5945 + return status; 5946 + } 5947 + 6147 5948 #if defined(CONFIG_NFS_V4_1) 6148 5949 /* 6149 5950 * Decode EXCHANGE_ID response ··· 6317 6066 out: 6318 6067 return status; 6319 6068 } 6069 + 6070 + /* 6071 + * Decode LAYOUTCOMMIT response 6072 + */ 6073 + static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, 6074 + struct xdr_stream *xdr, 6075 + struct nfs4_layoutcommit_res *res) 6076 + { 6077 + struct compound_hdr hdr; 6078 + int status; 6079 + 6080 + status = decode_compound_hdr(xdr, &hdr); 6081 + if (status) 6082 + goto out; 6083 + status = decode_sequence(xdr, &res->seq_res, rqstp); 6084 + if (status) 6085 + goto out; 6086 + status = decode_putfh(xdr); 6087 + if (status) 6088 + goto out; 6089 + status = decode_layoutcommit(xdr, rqstp, res); 6090 + if (status) 6091 + goto out; 6092 + decode_getfattr(xdr, res->fattr, res->server, 6093 + !RPC_IS_ASYNC(rqstp->rq_task)); 6094 + out: 6095 + return status; 6096 + } 6320 6097 #endif /* CONFIG_NFS_V4_1 */ 6321 6098 6322 6099 /** ··· 6459 6180 { NFS4ERR_SYMLINK, -ELOOP }, 6460 6181 { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP }, 6461 6182 { NFS4ERR_DEADLOCK, -EDEADLK }, 6462 - { NFS4ERR_WRONGSEC, -EPERM }, /* FIXME: this needs 6463 - * to be handled by a 6464 - * middle-layer. 6465 - */ 6466 6183 { -1, -EIO } 6467 6184 }; 6468 6185 ··· 6533 6258 PROC(SETACL, enc_setacl, dec_setacl), 6534 6259 PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), 6535 6260 PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), 6261 + PROC(SECINFO, enc_secinfo, dec_secinfo), 6536 6262 #if defined(CONFIG_NFS_V4_1) 6537 6263 PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), 6538 6264 PROC(CREATE_SESSION, enc_create_session, dec_create_session), ··· 6543 6267 PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), 6544 6268 PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), 6545 6269 PROC(LAYOUTGET, enc_layoutget, dec_layoutget), 6270 + PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), 6546 6271 #endif /* CONFIG_NFS_V4_1 */ 6547 6272 }; 6548 6273
+6 -2
fs/nfs/pagelist.c
··· 223 223 desc->pg_count = 0; 224 224 desc->pg_bsize = bsize; 225 225 desc->pg_base = 0; 226 + desc->pg_moreio = 0; 226 227 desc->pg_inode = inode; 227 228 desc->pg_doio = doio; 228 229 desc->pg_ioflags = io_flags; ··· 336 335 struct nfs_page *req) 337 336 { 338 337 while (!nfs_pageio_do_add_request(desc, req)) { 338 + desc->pg_moreio = 1; 339 339 nfs_pageio_doio(desc); 340 340 if (desc->pg_error < 0) 341 341 return 0; 342 + desc->pg_moreio = 0; 342 343 } 343 344 return 1; 344 345 } ··· 398 395 pgoff_t idx_end; 399 396 int found, i; 400 397 int res; 398 + struct list_head *list; 401 399 402 400 res = 0; 403 401 if (npages == 0) ··· 419 415 idx_start = req->wb_index + 1; 420 416 if (nfs_set_page_tag_locked(req)) { 421 417 kref_get(&req->wb_kref); 422 - nfs_list_remove_request(req); 423 418 radix_tree_tag_clear(&nfsi->nfs_page_tree, 424 419 req->wb_index, tag); 425 - nfs_list_add_request(req, dst); 420 + list = pnfs_choose_commit_list(req, dst); 421 + nfs_list_add_request(req, list); 426 422 res++; 427 423 if (res == INT_MAX) 428 424 goto out;
+142
fs/nfs/pnfs.c
··· 259 259 pnfs_free_lseg_list(&free_me); 260 260 } 261 261 } 262 + EXPORT_SYMBOL_GPL(put_lseg); 262 263 263 264 static bool 264 265 should_free_lseg(u32 lseg_iomode, u32 recall_iomode) ··· 472 471 struct nfs_server *server = NFS_SERVER(ino); 473 472 struct nfs4_layoutget *lgp; 474 473 struct pnfs_layout_segment *lseg = NULL; 474 + struct page **pages = NULL; 475 + int i; 476 + u32 max_resp_sz, max_pages; 475 477 476 478 dprintk("--> %s\n", __func__); 477 479 ··· 482 478 lgp = kzalloc(sizeof(*lgp), GFP_KERNEL); 483 479 if (lgp == NULL) 484 480 return NULL; 481 + 482 + /* allocate pages for xdr post processing */ 483 + max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz; 484 + max_pages = max_resp_sz >> PAGE_SHIFT; 485 + 486 + pages = kzalloc(max_pages * sizeof(struct page *), GFP_KERNEL); 487 + if (!pages) 488 + goto out_err_free; 489 + 490 + for (i = 0; i < max_pages; i++) { 491 + pages[i] = alloc_page(GFP_KERNEL); 492 + if (!pages[i]) 493 + goto out_err_free; 494 + } 495 + 485 496 lgp->args.minlength = NFS4_MAX_UINT64; 486 497 lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; 487 498 lgp->args.range.iomode = iomode; ··· 505 486 lgp->args.type = server->pnfs_curr_ld->id; 506 487 lgp->args.inode = ino; 507 488 lgp->args.ctx = get_nfs_open_context(ctx); 489 + lgp->args.layout.pages = pages; 490 + lgp->args.layout.pglen = max_pages * PAGE_SIZE; 508 491 lgp->lsegpp = &lseg; 509 492 510 493 /* Synchronously retrieve layout information from server and ··· 517 496 /* remember that LAYOUTGET failed and suspend trying */ 518 497 set_bit(lo_fail_bit(iomode), &lo->plh_flags); 519 498 } 499 + 500 + /* free xdr pages */ 501 + for (i = 0; i < max_pages; i++) 502 + __free_page(pages[i]); 503 + kfree(pages); 504 + 520 505 return lseg; 506 + 507 + out_err_free: 508 + /* free any allocated xdr pages, lgp as it's not used */ 509 + if (pages) { 510 + for (i = 0; i < max_pages; i++) { 511 + if (!pages[i]) 512 + break; 513 + __free_page(pages[i]); 514 + } 515 + kfree(pages); 516 + } 517 + kfree(lgp); 518 + return NULL; 521 519 } 522 520 523 521 bool pnfs_roc(struct inode *ino) ··· 984 944 } 985 945 dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); 986 946 return trypnfs; 947 + } 948 + 949 + /* 950 + * Currently there is only one (whole file) write lseg. 951 + */ 952 + static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode) 953 + { 954 + struct pnfs_layout_segment *lseg, *rv = NULL; 955 + 956 + list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) 957 + if (lseg->pls_range.iomode == IOMODE_RW) 958 + rv = lseg; 959 + return rv; 960 + } 961 + 962 + void 963 + pnfs_set_layoutcommit(struct nfs_write_data *wdata) 964 + { 965 + struct nfs_inode *nfsi = NFS_I(wdata->inode); 966 + loff_t end_pos = wdata->args.offset + wdata->res.count; 967 + 968 + spin_lock(&nfsi->vfs_inode.i_lock); 969 + if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { 970 + /* references matched in nfs4_layoutcommit_release */ 971 + get_lseg(wdata->lseg); 972 + wdata->lseg->pls_lc_cred = 973 + get_rpccred(wdata->args.context->state->owner->so_cred); 974 + mark_inode_dirty_sync(wdata->inode); 975 + dprintk("%s: Set layoutcommit for inode %lu ", 976 + __func__, wdata->inode->i_ino); 977 + } 978 + if (end_pos > wdata->lseg->pls_end_pos) 979 + wdata->lseg->pls_end_pos = end_pos; 980 + spin_unlock(&nfsi->vfs_inode.i_lock); 981 + } 982 + EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); 983 + 984 + /* 985 + * For the LAYOUT4_NFSV4_1_FILES layout type, NFS_DATA_SYNC WRITEs and 986 + * NFS_UNSTABLE WRITEs with a COMMIT to data servers must store enough 987 + * data to disk to allow the server to recover the data if it crashes. 988 + * LAYOUTCOMMIT is only needed when the NFL4_UFLG_COMMIT_THRU_MDS flag 989 + * is off, and a COMMIT is sent to a data server, or 990 + * if WRITEs to a data server return NFS_DATA_SYNC. 991 + */ 992 + int 993 + pnfs_layoutcommit_inode(struct inode *inode, bool sync) 994 + { 995 + struct nfs4_layoutcommit_data *data; 996 + struct nfs_inode *nfsi = NFS_I(inode); 997 + struct pnfs_layout_segment *lseg; 998 + struct rpc_cred *cred; 999 + loff_t end_pos; 1000 + int status = 0; 1001 + 1002 + dprintk("--> %s inode %lu\n", __func__, inode->i_ino); 1003 + 1004 + if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) 1005 + return 0; 1006 + 1007 + /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ 1008 + data = kzalloc(sizeof(*data), GFP_NOFS); 1009 + if (!data) { 1010 + mark_inode_dirty_sync(inode); 1011 + status = -ENOMEM; 1012 + goto out; 1013 + } 1014 + 1015 + spin_lock(&inode->i_lock); 1016 + if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { 1017 + spin_unlock(&inode->i_lock); 1018 + kfree(data); 1019 + goto out; 1020 + } 1021 + /* 1022 + * Currently only one (whole file) write lseg which is referenced 1023 + * in pnfs_set_layoutcommit and will be found. 1024 + */ 1025 + lseg = pnfs_list_write_lseg(inode); 1026 + 1027 + end_pos = lseg->pls_end_pos; 1028 + cred = lseg->pls_lc_cred; 1029 + lseg->pls_end_pos = 0; 1030 + lseg->pls_lc_cred = NULL; 1031 + 1032 + memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data, 1033 + sizeof(nfsi->layout->plh_stateid.data)); 1034 + spin_unlock(&inode->i_lock); 1035 + 1036 + data->args.inode = inode; 1037 + data->lseg = lseg; 1038 + data->cred = cred; 1039 + nfs_fattr_init(&data->fattr); 1040 + data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; 1041 + data->res.fattr = &data->fattr; 1042 + data->args.lastbytewritten = end_pos - 1; 1043 + data->res.server = NFS_SERVER(inode); 1044 + 1045 + status = nfs4_proc_layoutcommit(data, sync); 1046 + out: 1047 + dprintk("<-- %s status %d\n", __func__, status); 1048 + return status; 987 1049 }
+81 -2
fs/nfs/pnfs.h
··· 43 43 atomic_t pls_refcount; 44 44 unsigned long pls_flags; 45 45 struct pnfs_layout_hdr *pls_layout; 46 + struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */ 47 + loff_t pls_end_pos; /* LAYOUTCOMMIT write end */ 46 48 }; 47 49 48 50 enum pnfs_try_status { ··· 76 74 /* test for nfs page cache coalescing */ 77 75 int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); 78 76 77 + /* Returns true if layoutdriver wants to divert this request to 78 + * driver's commit routine. 79 + */ 80 + bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg); 81 + struct list_head * (*choose_commit_list) (struct nfs_page *req); 82 + int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); 83 + 79 84 /* 80 85 * Return PNFS_ATTEMPTED to indicate the layout code has attempted 81 86 * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS ··· 109 100 unsigned int layout_type; 110 101 unsigned int mincount; 111 102 struct page **pages; 112 - void *area; 113 103 unsigned int pgbase; 114 104 unsigned int pglen; 115 105 }; ··· 153 145 void pnfs_roc_release(struct inode *ino); 154 146 void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); 155 147 bool pnfs_roc_drain(struct inode *ino, u32 *barrier); 156 - 148 + void pnfs_set_layoutcommit(struct nfs_write_data *wdata); 149 + int pnfs_layoutcommit_inode(struct inode *inode, bool sync); 157 150 158 151 static inline int lo_fail_bit(u32 iomode) 159 152 { ··· 176 167 static inline int pnfs_enabled_sb(struct nfs_server *nfss) 177 168 { 178 169 return nfss->pnfs_curr_ld != NULL; 170 + } 171 + 172 + static inline void 173 + pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 174 + { 175 + if (lseg) { 176 + struct pnfs_layoutdriver_type *ld; 177 + 178 + ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld; 179 + if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) { 180 + set_bit(PG_PNFS_COMMIT, &req->wb_flags); 181 + req->wb_commit_lseg = get_lseg(lseg); 182 + } 183 + } 184 + } 185 + 186 + static inline int 187 + pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) 188 + { 189 + if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags)) 190 + return PNFS_NOT_ATTEMPTED; 191 + return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); 192 + } 193 + 194 + static inline struct list_head * 195 + pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) 196 + { 197 + struct list_head *rv; 198 + 199 + if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) { 200 + struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode; 201 + 202 + set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); 203 + rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req); 204 + /* matched by ref taken when PG_PNFS_COMMIT is set */ 205 + put_lseg(req->wb_commit_lseg); 206 + } else 207 + rv = mds; 208 + return rv; 209 + } 210 + 211 + static inline void pnfs_clear_request_commit(struct nfs_page *req) 212 + { 213 + if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) 214 + put_lseg(req->wb_commit_lseg); 179 215 } 180 216 181 217 #else /* CONFIG_NFS_V4_1 */ ··· 306 252 pgio->pg_test = NULL; 307 253 } 308 254 255 + static inline void 256 + pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 257 + { 258 + } 259 + 260 + static inline int 261 + pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) 262 + { 263 + return PNFS_NOT_ATTEMPTED; 264 + } 265 + 266 + static inline struct list_head * 267 + pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) 268 + { 269 + return mds; 270 + } 271 + 272 + static inline void pnfs_clear_request_commit(struct nfs_page *req) 273 + { 274 + } 275 + 276 + static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) 277 + { 278 + return 0; 279 + } 309 280 #endif /* CONFIG_NFS_V4_1 */ 310 281 311 282 #endif /* FS_NFS_PNFS_H */
+1 -1
fs/nfs/proc.c
··· 177 177 } 178 178 179 179 static int 180 - nfs_proc_lookup(struct inode *dir, struct qstr *name, 180 + nfs_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name, 181 181 struct nfs_fh *fhandle, struct nfs_fattr *fattr) 182 182 { 183 183 struct nfs_diropargs arg = {
+152 -78
fs/nfs/write.c
··· 59 59 } 60 60 return p; 61 61 } 62 + EXPORT_SYMBOL_GPL(nfs_commitdata_alloc); 62 63 63 64 void nfs_commit_free(struct nfs_write_data *p) 64 65 { ··· 67 66 kfree(p->pagevec); 68 67 mempool_free(p, nfs_commit_mempool); 69 68 } 69 + EXPORT_SYMBOL_GPL(nfs_commit_free); 70 70 71 71 struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) 72 72 { ··· 181 179 if (wbc->for_reclaim) 182 180 return FLUSH_HIGHPRI | FLUSH_STABLE; 183 181 if (wbc->for_kupdate || wbc->for_background) 184 - return FLUSH_LOWPRI; 185 - return 0; 182 + return FLUSH_LOWPRI | FLUSH_COND_STABLE; 183 + return FLUSH_COND_STABLE; 186 184 } 187 185 188 186 /* ··· 443 441 * Add a request to the inode's commit list. 444 442 */ 445 443 static void 446 - nfs_mark_request_commit(struct nfs_page *req) 444 + nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 447 445 { 448 446 struct inode *inode = req->wb_context->path.dentry->d_inode; 449 447 struct nfs_inode *nfsi = NFS_I(inode); ··· 455 453 NFS_PAGE_TAG_COMMIT); 456 454 nfsi->ncommit++; 457 455 spin_unlock(&inode->i_lock); 456 + pnfs_mark_request_commit(req, lseg); 458 457 inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 459 458 inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); 460 459 __mark_inode_dirty(inode, I_DIRTY_DATASYNC); ··· 477 474 static inline 478 475 int nfs_write_need_commit(struct nfs_write_data *data) 479 476 { 480 - return data->verf.committed != NFS_FILE_SYNC; 477 + if (data->verf.committed == NFS_DATA_SYNC) 478 + return data->lseg == NULL; 479 + else 480 + return data->verf.committed != NFS_FILE_SYNC; 481 481 } 482 482 483 483 static inline 484 - int nfs_reschedule_unstable_write(struct nfs_page *req) 484 + int nfs_reschedule_unstable_write(struct nfs_page *req, 485 + struct nfs_write_data *data) 485 486 { 486 487 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { 487 - nfs_mark_request_commit(req); 488 + nfs_mark_request_commit(req, data->lseg); 488 489 return 1; 489 490 } 490 491 if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { ··· 499 492 } 500 493 #else 501 494 static inline void 502 - nfs_mark_request_commit(struct nfs_page *req) 495 + nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 503 496 { 504 497 } 505 498 ··· 516 509 } 517 510 518 511 static inline 519 - int nfs_reschedule_unstable_write(struct nfs_page *req) 512 + int nfs_reschedule_unstable_write(struct nfs_page *req, 513 + struct nfs_write_data *data) 520 514 { 521 515 return 0; 522 516 } ··· 620 612 } 621 613 622 614 if (nfs_clear_request_commit(req) && 623 - radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, 624 - req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) 615 + radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, 616 + req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) { 625 617 NFS_I(inode)->ncommit--; 618 + pnfs_clear_request_commit(req); 619 + } 626 620 627 621 /* Okay, the request matches. Update the region */ 628 622 if (offset < req->wb_offset) { ··· 772 762 return status; 773 763 } 774 764 775 - static void nfs_writepage_release(struct nfs_page *req) 765 + static void nfs_writepage_release(struct nfs_page *req, 766 + struct nfs_write_data *data) 776 767 { 777 768 struct page *page = req->wb_page; 778 769 779 - if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) 770 + if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data)) 780 771 nfs_inode_remove_request(req); 781 772 nfs_clear_page_tag_locked(req); 782 773 nfs_end_page_writeback(page); ··· 874 863 data->args.context = get_nfs_open_context(req->wb_context); 875 864 data->args.lock_context = req->wb_lock_context; 876 865 data->args.stable = NFS_UNSTABLE; 877 - if (how & FLUSH_STABLE) { 866 + if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { 878 867 data->args.stable = NFS_DATA_SYNC; 879 868 if (!nfs_need_commit(NFS_I(inode))) 880 869 data->args.stable = NFS_FILE_SYNC; ··· 922 911 LIST_HEAD(list); 923 912 924 913 nfs_list_remove_request(req); 914 + 915 + if ((desc->pg_ioflags & FLUSH_COND_STABLE) && 916 + (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit || 917 + desc->pg_count > wsize)) 918 + desc->pg_ioflags &= ~FLUSH_COND_STABLE; 919 + 925 920 926 921 nbytes = desc->pg_count; 927 922 do { ··· 1019 1002 if ((!lseg) && list_is_singular(&data->pages)) 1020 1003 lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); 1021 1004 1005 + if ((desc->pg_ioflags & FLUSH_COND_STABLE) && 1006 + (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) 1007 + desc->pg_ioflags &= ~FLUSH_COND_STABLE; 1008 + 1022 1009 /* Set up the argument struct */ 1023 1010 ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); 1024 1011 out: ··· 1095 1074 1096 1075 out: 1097 1076 if (atomic_dec_and_test(&req->wb_complete)) 1098 - nfs_writepage_release(req); 1077 + nfs_writepage_release(req, data); 1099 1078 nfs_writedata_release(calldata); 1100 1079 } 1101 1080 ··· 1162 1141 1163 1142 if (nfs_write_need_commit(data)) { 1164 1143 memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); 1165 - nfs_mark_request_commit(req); 1144 + nfs_mark_request_commit(req, data->lseg); 1166 1145 dprintk(" marked for commit\n"); 1167 1146 goto next; 1168 1147 } ··· 1272 1251 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 1273 1252 static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) 1274 1253 { 1254 + int ret; 1255 + 1275 1256 if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) 1276 1257 return 1; 1277 - if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, 1278 - NFS_INO_COMMIT, nfs_wait_bit_killable, 1279 - TASK_KILLABLE)) 1280 - return 1; 1281 - return 0; 1258 + if (!may_wait) 1259 + return 0; 1260 + ret = out_of_line_wait_on_bit_lock(&nfsi->flags, 1261 + NFS_INO_COMMIT, 1262 + nfs_wait_bit_killable, 1263 + TASK_KILLABLE); 1264 + return (ret < 0) ? ret : 1; 1282 1265 } 1283 1266 1284 - static void nfs_commit_clear_lock(struct nfs_inode *nfsi) 1267 + void nfs_commit_clear_lock(struct nfs_inode *nfsi) 1285 1268 { 1286 1269 clear_bit(NFS_INO_COMMIT, &nfsi->flags); 1287 1270 smp_mb__after_clear_bit(); 1288 1271 wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); 1289 1272 } 1273 + EXPORT_SYMBOL_GPL(nfs_commit_clear_lock); 1290 1274 1291 - 1292 - static void nfs_commitdata_release(void *data) 1275 + void nfs_commitdata_release(void *data) 1293 1276 { 1294 1277 struct nfs_write_data *wdata = data; 1295 1278 1279 + put_lseg(wdata->lseg); 1296 1280 put_nfs_open_context(wdata->args.context); 1297 1281 nfs_commit_free(wdata); 1298 1282 } 1283 + EXPORT_SYMBOL_GPL(nfs_commitdata_release); 1299 1284 1300 - /* 1301 - * Set up the argument/result storage required for the RPC call. 1302 - */ 1303 - static int nfs_commit_rpcsetup(struct list_head *head, 1304 - struct nfs_write_data *data, 1305 - int how) 1285 + int nfs_initiate_commit(struct nfs_write_data *data, struct rpc_clnt *clnt, 1286 + const struct rpc_call_ops *call_ops, 1287 + int how) 1306 1288 { 1307 - struct nfs_page *first = nfs_list_entry(head->next); 1308 - struct inode *inode = first->wb_context->path.dentry->d_inode; 1309 - int priority = flush_task_priority(how); 1310 1289 struct rpc_task *task; 1290 + int priority = flush_task_priority(how); 1311 1291 struct rpc_message msg = { 1312 1292 .rpc_argp = &data->args, 1313 1293 .rpc_resp = &data->res, 1314 - .rpc_cred = first->wb_context->cred, 1294 + .rpc_cred = data->cred, 1315 1295 }; 1316 1296 struct rpc_task_setup task_setup_data = { 1317 1297 .task = &data->task, 1318 - .rpc_client = NFS_CLIENT(inode), 1298 + .rpc_client = clnt, 1319 1299 .rpc_message = &msg, 1320 - .callback_ops = &nfs_commit_ops, 1300 + .callback_ops = call_ops, 1321 1301 .callback_data = data, 1322 1302 .workqueue = nfsiod_workqueue, 1323 1303 .flags = RPC_TASK_ASYNC, 1324 1304 .priority = priority, 1325 1305 }; 1326 - 1327 - /* Set up the RPC argument and reply structs 1328 - * NB: take care not to mess about with data->commit et al. */ 1329 - 1330 - list_splice_init(head, &data->pages); 1331 - 1332 - data->inode = inode; 1333 - data->cred = msg.rpc_cred; 1334 - 1335 - data->args.fh = NFS_FH(data->inode); 1336 - /* Note: we always request a commit of the entire inode */ 1337 - data->args.offset = 0; 1338 - data->args.count = 0; 1339 - data->args.context = get_nfs_open_context(first->wb_context); 1340 - data->res.count = 0; 1341 - data->res.fattr = &data->fattr; 1342 - data->res.verf = &data->verf; 1343 - nfs_fattr_init(&data->fattr); 1344 - 1345 1306 /* Set up the initial task struct. */ 1346 - NFS_PROTO(inode)->commit_setup(data, &msg); 1307 + NFS_PROTO(data->inode)->commit_setup(data, &msg); 1347 1308 1348 1309 dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); 1349 1310 ··· 1337 1334 rpc_put_task(task); 1338 1335 return 0; 1339 1336 } 1337 + EXPORT_SYMBOL_GPL(nfs_initiate_commit); 1338 + 1339 + /* 1340 + * Set up the argument/result storage required for the RPC call. 1341 + */ 1342 + void nfs_init_commit(struct nfs_write_data *data, 1343 + struct list_head *head, 1344 + struct pnfs_layout_segment *lseg) 1345 + { 1346 + struct nfs_page *first = nfs_list_entry(head->next); 1347 + struct inode *inode = first->wb_context->path.dentry->d_inode; 1348 + 1349 + /* Set up the RPC argument and reply structs 1350 + * NB: take care not to mess about with data->commit et al. */ 1351 + 1352 + list_splice_init(head, &data->pages); 1353 + 1354 + data->inode = inode; 1355 + data->cred = first->wb_context->cred; 1356 + data->lseg = lseg; /* reference transferred */ 1357 + data->mds_ops = &nfs_commit_ops; 1358 + 1359 + data->args.fh = NFS_FH(data->inode); 1360 + /* Note: we always request a commit of the entire inode */ 1361 + data->args.offset = 0; 1362 + data->args.count = 0; 1363 + data->args.context = get_nfs_open_context(first->wb_context); 1364 + data->res.count = 0; 1365 + data->res.fattr = &data->fattr; 1366 + data->res.verf = &data->verf; 1367 + nfs_fattr_init(&data->fattr); 1368 + } 1369 + EXPORT_SYMBOL_GPL(nfs_init_commit); 1370 + 1371 + void nfs_retry_commit(struct list_head *page_list, 1372 + struct pnfs_layout_segment *lseg) 1373 + { 1374 + struct nfs_page *req; 1375 + 1376 + while (!list_empty(page_list)) { 1377 + req = nfs_list_entry(page_list->next); 1378 + nfs_list_remove_request(req); 1379 + nfs_mark_request_commit(req, lseg); 1380 + dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 1381 + dec_bdi_stat(req->wb_page->mapping->backing_dev_info, 1382 + BDI_RECLAIMABLE); 1383 + nfs_clear_page_tag_locked(req); 1384 + } 1385 + } 1386 + EXPORT_SYMBOL_GPL(nfs_retry_commit); 1340 1387 1341 1388 /* 1342 1389 * Commit dirty pages ··· 1395 1342 nfs_commit_list(struct inode *inode, struct list_head *head, int how) 1396 1343 { 1397 1344 struct nfs_write_data *data; 1398 - struct nfs_page *req; 1399 1345 1400 1346 data = nfs_commitdata_alloc(); 1401 1347 ··· 1402 1350 goto out_bad; 1403 1351 1404 1352 /* Set up the argument struct */ 1405 - return nfs_commit_rpcsetup(head, data, how); 1353 + nfs_init_commit(data, head, NULL); 1354 + return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how); 1406 1355 out_bad: 1407 - while (!list_empty(head)) { 1408 - req = nfs_list_entry(head->next); 1409 - nfs_list_remove_request(req); 1410 - nfs_mark_request_commit(req); 1411 - dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 1412 - dec_bdi_stat(req->wb_page->mapping->backing_dev_info, 1413 - BDI_RECLAIMABLE); 1414 - nfs_clear_page_tag_locked(req); 1415 - } 1356 + nfs_retry_commit(head, NULL); 1416 1357 nfs_commit_clear_lock(NFS_I(inode)); 1417 1358 return -ENOMEM; 1418 1359 } ··· 1425 1380 return; 1426 1381 } 1427 1382 1428 - static void nfs_commit_release(void *calldata) 1383 + void nfs_commit_release_pages(struct nfs_write_data *data) 1429 1384 { 1430 - struct nfs_write_data *data = calldata; 1431 - struct nfs_page *req; 1385 + struct nfs_page *req; 1432 1386 int status = data->task.tk_status; 1433 1387 1434 1388 while (!list_empty(&data->pages)) { ··· 1461 1417 next: 1462 1418 nfs_clear_page_tag_locked(req); 1463 1419 } 1420 + } 1421 + EXPORT_SYMBOL_GPL(nfs_commit_release_pages); 1422 + 1423 + static void nfs_commit_release(void *calldata) 1424 + { 1425 + struct nfs_write_data *data = calldata; 1426 + 1427 + nfs_commit_release_pages(data); 1464 1428 nfs_commit_clear_lock(NFS_I(data->inode)); 1465 1429 nfs_commitdata_release(calldata); 1466 1430 } ··· 1485 1433 { 1486 1434 LIST_HEAD(head); 1487 1435 int may_wait = how & FLUSH_SYNC; 1488 - int res = 0; 1436 + int res; 1489 1437 1490 - if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) 1438 + res = nfs_commit_set_lock(NFS_I(inode), may_wait); 1439 + if (res <= 0) 1491 1440 goto out_mark_dirty; 1492 1441 spin_lock(&inode->i_lock); 1493 1442 res = nfs_scan_commit(inode, &head, 0, 0); 1494 1443 spin_unlock(&inode->i_lock); 1495 1444 if (res) { 1496 - int error = nfs_commit_list(inode, &head, how); 1445 + int error; 1446 + 1447 + error = pnfs_commit_list(inode, &head, how); 1448 + if (error == PNFS_NOT_ATTEMPTED) 1449 + error = nfs_commit_list(inode, &head, how); 1497 1450 if (error < 0) 1498 1451 return error; 1499 - if (may_wait) 1500 - wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, 1501 - nfs_wait_bit_killable, 1502 - TASK_KILLABLE); 1503 - else 1452 + if (!may_wait) 1504 1453 goto out_mark_dirty; 1454 + error = wait_on_bit(&NFS_I(inode)->flags, 1455 + NFS_INO_COMMIT, 1456 + nfs_wait_bit_killable, 1457 + TASK_KILLABLE); 1458 + if (error < 0) 1459 + return error; 1505 1460 } else 1506 1461 nfs_commit_clear_lock(NFS_I(inode)); 1507 1462 return res; ··· 1562 1503 1563 1504 int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) 1564 1505 { 1565 - return nfs_commit_unstable_pages(inode, wbc); 1506 + int ret; 1507 + 1508 + ret = nfs_commit_unstable_pages(inode, wbc); 1509 + if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { 1510 + int status; 1511 + bool sync = true; 1512 + 1513 + if (wbc->sync_mode == WB_SYNC_NONE || wbc->nonblocking || 1514 + wbc->for_background) 1515 + sync = false; 1516 + 1517 + status = pnfs_layoutcommit_inode(inode, sync); 1518 + if (status < 0) 1519 + return status; 1520 + } 1521 + return ret; 1566 1522 } 1567 1523 1568 1524 /*
-1
fs/nfs_common/nfsacl.c
··· 117 117 * invoked in contexts where a memory allocation failure is 118 118 * fatal. Fortunately this fake ACL is small enough to 119 119 * construct on the stack. */ 120 - memset(acl2, 0, sizeof(acl2)); 121 120 posix_acl_init(acl2, 4); 122 121 123 122 /* Insert entries in canonical order: other orders seem
+2
include/linux/nfs4.h
··· 550 550 NFSPROC4_CLNT_SETACL, 551 551 NFSPROC4_CLNT_FS_LOCATIONS, 552 552 NFSPROC4_CLNT_RELEASE_LOCKOWNER, 553 + NFSPROC4_CLNT_SECINFO, 553 554 554 555 /* nfs41 */ 555 556 NFSPROC4_CLNT_EXCHANGE_ID, ··· 561 560 NFSPROC4_CLNT_RECLAIM_COMPLETE, 562 561 NFSPROC4_CLNT_LAYOUTGET, 563 562 NFSPROC4_CLNT_GETDEVICEINFO, 563 + NFSPROC4_CLNT_LAYOUTCOMMIT, 564 564 }; 565 565 566 566 /* nfs41 types */
+10
include/linux/nfs_fs.h
··· 33 33 #define FLUSH_STABLE 4 /* commit to stable storage */ 34 34 #define FLUSH_LOWPRI 8 /* low priority background flush */ 35 35 #define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ 36 + #define FLUSH_COND_STABLE 32 /* conditional stable write - only stable 37 + * if everything fits in one RPC */ 36 38 37 39 #ifdef __KERNEL__ 38 40 ··· 95 93 int error; 96 94 97 95 struct list_head list; 96 + }; 98 97 98 + struct nfs_open_dir_context { 99 + struct rpc_cred *cred; 99 100 __u64 dir_cookie; 101 + __u64 dup_cookie; 102 + int duped; 100 103 }; 101 104 102 105 /* ··· 198 191 199 192 /* pNFS layout information */ 200 193 struct pnfs_layout_hdr *layout; 194 + atomic_t commits_outstanding; 201 195 #endif /* CONFIG_NFS_V4*/ 202 196 #ifdef CONFIG_NFS_FSCACHE 203 197 struct fscache_cookie *fscache; ··· 227 219 #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ 228 220 #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ 229 221 #define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ 222 + #define NFS_INO_PNFS_COMMIT (8) /* use pnfs code for commit */ 223 + #define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ 230 224 231 225 static inline struct nfs_inode *NFS_I(const struct inode *inode) 232 226 {
+6 -1
include/linux/nfs_page.h
··· 33 33 PG_CLEAN, 34 34 PG_NEED_COMMIT, 35 35 PG_NEED_RESCHED, 36 + PG_PNFS_COMMIT, 36 37 }; 37 38 38 39 struct nfs_inode; 39 40 struct nfs_page { 40 - struct list_head wb_list; /* Defines state of page: */ 41 + union { 42 + struct list_head wb_list; /* Defines state of page: */ 43 + struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */ 44 + }; 41 45 struct page *wb_page; /* page to read in/write out */ 42 46 struct nfs_open_context *wb_context; /* File state context info */ 43 47 struct nfs_lock_context *wb_lock_context; /* lock context info */ ··· 61 57 size_t pg_count; 62 58 size_t pg_bsize; 63 59 unsigned int pg_base; 60 + char pg_moreio; 64 61 65 62 struct inode *pg_inode; 66 63 int (*pg_doio)(struct nfs_pageio_descriptor *);
+67 -3
include/linux/nfs_xdr.h
··· 3 3 4 4 #include <linux/nfsacl.h> 5 5 #include <linux/nfs3.h> 6 + #include <linux/sunrpc/gss_api.h> 6 7 7 8 /* 8 9 * To change the maximum rsize and wsize supported by the NFS client, adjust ··· 14 13 #define NFS_MAX_FILE_IO_SIZE (1048576U) 15 14 #define NFS_DEF_FILE_IO_SIZE (4096U) 16 15 #define NFS_MIN_FILE_IO_SIZE (1024U) 16 + 17 + /* Forward declaration for NFS v3 */ 18 + struct nfs4_secinfo_flavors; 17 19 18 20 struct nfs_fsid { 19 21 uint64_t major; ··· 82 78 #define NFS_ATTR_FATTR_CHANGE (1U << 17) 83 79 #define NFS_ATTR_FATTR_PRECHANGE (1U << 18) 84 80 #define NFS_ATTR_FATTR_V4_REFERRAL (1U << 19) /* NFSv4 referral */ 81 + #define NFS_ATTR_FATTR_MOUNTPOINT (1U << 20) /* Treat as mountpoint */ 85 82 86 83 #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ 87 84 | NFS_ATTR_FATTR_MODE \ ··· 195 190 #define PNFS_LAYOUT_MAXSIZE 4096 196 191 197 192 struct nfs4_layoutdriver_data { 193 + struct page **pages; 194 + __u32 pglen; 198 195 __u32 len; 199 - void *buf; 200 196 }; 201 197 202 198 struct pnfs_layout_range { ··· 215 209 struct nfs_open_context *ctx; 216 210 struct nfs4_sequence_args seq_args; 217 211 nfs4_stateid stateid; 212 + struct nfs4_layoutdriver_data layout; 218 213 }; 219 214 220 215 struct nfs4_layoutget_res { ··· 223 216 struct pnfs_layout_range range; 224 217 __u32 type; 225 218 nfs4_stateid stateid; 226 - struct nfs4_layoutdriver_data layout; 227 219 struct nfs4_sequence_res seq_res; 220 + struct nfs4_layoutdriver_data *layoutp; 228 221 }; 229 222 230 223 struct nfs4_layoutget { ··· 241 234 struct nfs4_getdeviceinfo_res { 242 235 struct pnfs_device *pdev; 243 236 struct nfs4_sequence_res seq_res; 237 + }; 238 + 239 + struct nfs4_layoutcommit_args { 240 + nfs4_stateid stateid; 241 + __u64 lastbytewritten; 242 + struct inode *inode; 243 + const u32 *bitmask; 244 + struct nfs4_sequence_args seq_args; 245 + }; 246 + 247 + struct nfs4_layoutcommit_res { 248 + struct nfs_fattr *fattr; 249 + const struct nfs_server *server; 250 + struct nfs4_sequence_res seq_res; 251 + }; 252 + 253 + struct nfs4_layoutcommit_data { 254 + struct rpc_task task; 255 + struct nfs_fattr fattr; 256 + struct pnfs_layout_segment *lseg; 257 + struct rpc_cred *cred; 258 + struct nfs4_layoutcommit_args args; 259 + struct nfs4_layoutcommit_res res; 244 260 }; 245 261 246 262 /* ··· 966 936 struct nfs4_sequence_res seq_res; 967 937 }; 968 938 939 + struct nfs4_secinfo_oid { 940 + unsigned int len; 941 + char data[GSS_OID_MAX_LEN]; 942 + }; 943 + 944 + struct nfs4_secinfo_gss { 945 + struct nfs4_secinfo_oid sec_oid4; 946 + unsigned int qop4; 947 + unsigned int service; 948 + }; 949 + 950 + struct nfs4_secinfo_flavor { 951 + unsigned int flavor; 952 + struct nfs4_secinfo_gss gss; 953 + }; 954 + 955 + struct nfs4_secinfo_flavors { 956 + unsigned int num_flavors; 957 + struct nfs4_secinfo_flavor flavors[0]; 958 + }; 959 + 960 + struct nfs4_secinfo_arg { 961 + const struct nfs_fh *dir_fh; 962 + const struct qstr *name; 963 + struct nfs4_sequence_args seq_args; 964 + }; 965 + 966 + struct nfs4_secinfo_res { 967 + struct nfs4_secinfo_flavors *flavors; 968 + struct nfs4_sequence_res seq_res; 969 + }; 970 + 969 971 #endif /* CONFIG_NFS_V4 */ 970 972 971 973 struct nfstime4 { ··· 1102 1040 struct nfs_writeres res; /* result struct */ 1103 1041 struct pnfs_layout_segment *lseg; 1104 1042 struct nfs_client *ds_clp; /* pNFS data server */ 1043 + int ds_commit_index; 1105 1044 const struct rpc_call_ops *mds_ops; 1106 1045 int (*write_done_cb) (struct rpc_task *task, struct nfs_write_data *data); 1107 1046 #ifdef CONFIG_NFS_V4 ··· 1134 1071 struct nfs_fattr *); 1135 1072 int (*setattr) (struct dentry *, struct nfs_fattr *, 1136 1073 struct iattr *); 1137 - int (*lookup) (struct inode *, struct qstr *, 1074 + int (*lookup) (struct rpc_clnt *clnt, struct inode *, struct qstr *, 1138 1075 struct nfs_fh *, struct nfs_fattr *); 1139 1076 int (*access) (struct inode *, struct nfs_access_entry *); 1140 1077 int (*readlink)(struct inode *, struct page *, unsigned int, ··· 1181 1118 struct iattr *iattr); 1182 1119 int (*init_client) (struct nfs_client *, const struct rpc_timeout *, 1183 1120 const char *, rpc_authflavor_t, int); 1121 + int (*secinfo)(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); 1184 1122 }; 1185 1123 1186 1124 /*
+3
include/linux/sunrpc/gss_api.h
··· 126 126 /* Similar, but get by pseudoflavor. */ 127 127 struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); 128 128 129 + /* Fill in an array with a list of supported pseudoflavors */ 130 + int gss_mech_list_pseudoflavors(u32 *); 131 + 129 132 /* Just increments the mechanism's reference count and returns its input: */ 130 133 struct gss_api_mech * gss_mech_get(struct gss_api_mech *); 131 134
+38
net/sunrpc/auth_gss/gss_mech_switch.c
··· 160 160 161 161 EXPORT_SYMBOL_GPL(gss_mech_get_by_name); 162 162 163 + struct gss_api_mech * 164 + gss_mech_get_by_OID(struct xdr_netobj *obj) 165 + { 166 + struct gss_api_mech *pos, *gm = NULL; 167 + 168 + spin_lock(&registered_mechs_lock); 169 + list_for_each_entry(pos, &registered_mechs, gm_list) { 170 + if (obj->len == pos->gm_oid.len) { 171 + if (0 == memcmp(obj->data, pos->gm_oid.data, obj->len)) { 172 + if (try_module_get(pos->gm_owner)) 173 + gm = pos; 174 + break; 175 + } 176 + } 177 + } 178 + spin_unlock(&registered_mechs_lock); 179 + return gm; 180 + 181 + } 182 + 183 + EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); 184 + 163 185 static inline int 164 186 mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) 165 187 { ··· 214 192 } 215 193 216 194 EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); 195 + 196 + int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr) 197 + { 198 + struct gss_api_mech *pos = NULL; 199 + int i = 0; 200 + 201 + spin_lock(&registered_mechs_lock); 202 + list_for_each_entry(pos, &registered_mechs, gm_list) { 203 + array_ptr[i] = pos->gm_pfs->pseudoflavor; 204 + i++; 205 + } 206 + spin_unlock(&registered_mechs_lock); 207 + return i; 208 + } 209 + 210 + EXPORT_SYMBOL_GPL(gss_mech_list_pseudoflavors); 217 211 218 212 u32 219 213 gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
+2
net/sunrpc/xprtsock.c
··· 710 710 if (sk == NULL) 711 711 return; 712 712 713 + transport->srcport = 0; 714 + 713 715 write_lock_bh(&sk->sk_callback_lock); 714 716 transport->inet = NULL; 715 717 transport->sock = NULL;