diff options
56 files changed, 3378 insertions, 853 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index acc9c4943b84..7ec9b34a59f8 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -934,7 +934,6 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str | |||
| 934 | } | 934 | } |
| 935 | 935 | ||
| 936 | fsinfo.fattr = fattr; | 936 | fsinfo.fattr = fattr; |
| 937 | nfs_fattr_init(fattr); | ||
| 938 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | 937 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); |
| 939 | if (error < 0) | 938 | if (error < 0) |
| 940 | goto out_error; | 939 | goto out_error; |
| @@ -1047,13 +1046,18 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1047 | struct nfs_fh *mntfh) | 1046 | struct nfs_fh *mntfh) |
| 1048 | { | 1047 | { |
| 1049 | struct nfs_server *server; | 1048 | struct nfs_server *server; |
| 1050 | struct nfs_fattr fattr; | 1049 | struct nfs_fattr *fattr; |
| 1051 | int error; | 1050 | int error; |
| 1052 | 1051 | ||
| 1053 | server = nfs_alloc_server(); | 1052 | server = nfs_alloc_server(); |
| 1054 | if (!server) | 1053 | if (!server) |
| 1055 | return ERR_PTR(-ENOMEM); | 1054 | return ERR_PTR(-ENOMEM); |
| 1056 | 1055 | ||
| 1056 | error = -ENOMEM; | ||
| 1057 | fattr = nfs_alloc_fattr(); | ||
| 1058 | if (fattr == NULL) | ||
| 1059 | goto error; | ||
| 1060 | |||
| 1057 | /* Get a client representation */ | 1061 | /* Get a client representation */ |
| 1058 | error = nfs_init_server(server, data); | 1062 | error = nfs_init_server(server, data); |
| 1059 | if (error < 0) | 1063 | if (error < 0) |
| @@ -1064,7 +1068,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1064 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1068 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
| 1065 | 1069 | ||
| 1066 | /* Probe the root fh to retrieve its FSID */ | 1070 | /* Probe the root fh to retrieve its FSID */ |
| 1067 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1071 | error = nfs_probe_fsinfo(server, mntfh, fattr); |
| 1068 | if (error < 0) | 1072 | if (error < 0) |
| 1069 | goto error; | 1073 | goto error; |
| 1070 | if (server->nfs_client->rpc_ops->version == 3) { | 1074 | if (server->nfs_client->rpc_ops->version == 3) { |
| @@ -1077,14 +1081,14 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1077 | server->namelen = NFS2_MAXNAMLEN; | 1081 | server->namelen = NFS2_MAXNAMLEN; |
| 1078 | } | 1082 | } |
| 1079 | 1083 | ||
| 1080 | if (!(fattr.valid & NFS_ATTR_FATTR)) { | 1084 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
| 1081 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 1085 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
| 1082 | if (error < 0) { | 1086 | if (error < 0) { |
| 1083 | dprintk("nfs_create_server: getattr error = %d\n", -error); | 1087 | dprintk("nfs_create_server: getattr error = %d\n", -error); |
| 1084 | goto error; | 1088 | goto error; |
| 1085 | } | 1089 | } |
| 1086 | } | 1090 | } |
| 1087 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | 1091 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); |
| 1088 | 1092 | ||
| 1089 | dprintk("Server FSID: %llx:%llx\n", | 1093 | dprintk("Server FSID: %llx:%llx\n", |
| 1090 | (unsigned long long) server->fsid.major, | 1094 | (unsigned long long) server->fsid.major, |
| @@ -1096,9 +1100,11 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1096 | spin_unlock(&nfs_client_lock); | 1100 | spin_unlock(&nfs_client_lock); |
| 1097 | 1101 | ||
| 1098 | server->mount_time = jiffies; | 1102 | server->mount_time = jiffies; |
| 1103 | nfs_free_fattr(fattr); | ||
| 1099 | return server; | 1104 | return server; |
| 1100 | 1105 | ||
| 1101 | error: | 1106 | error: |
| 1107 | nfs_free_fattr(fattr); | ||
| 1102 | nfs_free_server(server); | 1108 | nfs_free_server(server); |
| 1103 | return ERR_PTR(error); | 1109 | return ERR_PTR(error); |
| 1104 | } | 1110 | } |
| @@ -1340,7 +1346,7 @@ error: | |||
| 1340 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | 1346 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, |
| 1341 | struct nfs_fh *mntfh) | 1347 | struct nfs_fh *mntfh) |
| 1342 | { | 1348 | { |
| 1343 | struct nfs_fattr fattr; | 1349 | struct nfs_fattr *fattr; |
| 1344 | struct nfs_server *server; | 1350 | struct nfs_server *server; |
| 1345 | int error; | 1351 | int error; |
| 1346 | 1352 | ||
| @@ -1350,6 +1356,11 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1350 | if (!server) | 1356 | if (!server) |
| 1351 | return ERR_PTR(-ENOMEM); | 1357 | return ERR_PTR(-ENOMEM); |
| 1352 | 1358 | ||
| 1359 | error = -ENOMEM; | ||
| 1360 | fattr = nfs_alloc_fattr(); | ||
| 1361 | if (fattr == NULL) | ||
| 1362 | goto error; | ||
| 1363 | |||
| 1353 | /* set up the general RPC client */ | 1364 | /* set up the general RPC client */ |
| 1354 | error = nfs4_init_server(server, data); | 1365 | error = nfs4_init_server(server, data); |
| 1355 | if (error < 0) | 1366 | if (error < 0) |
| @@ -1364,7 +1375,7 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1364 | goto error; | 1375 | goto error; |
| 1365 | 1376 | ||
| 1366 | /* Probe the root fh to retrieve its FSID */ | 1377 | /* Probe the root fh to retrieve its FSID */ |
| 1367 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1378 | error = nfs4_get_rootfh(server, mntfh); |
| 1368 | if (error < 0) | 1379 | if (error < 0) |
| 1369 | goto error; | 1380 | goto error; |
| 1370 | 1381 | ||
| @@ -1375,7 +1386,7 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1375 | 1386 | ||
| 1376 | nfs4_session_set_rwsize(server); | 1387 | nfs4_session_set_rwsize(server); |
| 1377 | 1388 | ||
| 1378 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1389 | error = nfs_probe_fsinfo(server, mntfh, fattr); |
| 1379 | if (error < 0) | 1390 | if (error < 0) |
| 1380 | goto error; | 1391 | goto error; |
| 1381 | 1392 | ||
| @@ -1389,9 +1400,11 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1389 | 1400 | ||
| 1390 | server->mount_time = jiffies; | 1401 | server->mount_time = jiffies; |
| 1391 | dprintk("<-- nfs4_create_server() = %p\n", server); | 1402 | dprintk("<-- nfs4_create_server() = %p\n", server); |
| 1403 | nfs_free_fattr(fattr); | ||
| 1392 | return server; | 1404 | return server; |
| 1393 | 1405 | ||
| 1394 | error: | 1406 | error: |
| 1407 | nfs_free_fattr(fattr); | ||
| 1395 | nfs_free_server(server); | 1408 | nfs_free_server(server); |
| 1396 | dprintk("<-- nfs4_create_server() = error %d\n", error); | 1409 | dprintk("<-- nfs4_create_server() = error %d\n", error); |
| 1397 | return ERR_PTR(error); | 1410 | return ERR_PTR(error); |
| @@ -1405,7 +1418,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1405 | { | 1418 | { |
| 1406 | struct nfs_client *parent_client; | 1419 | struct nfs_client *parent_client; |
| 1407 | struct nfs_server *server, *parent_server; | 1420 | struct nfs_server *server, *parent_server; |
| 1408 | struct nfs_fattr fattr; | 1421 | struct nfs_fattr *fattr; |
| 1409 | int error; | 1422 | int error; |
| 1410 | 1423 | ||
| 1411 | dprintk("--> nfs4_create_referral_server()\n"); | 1424 | dprintk("--> nfs4_create_referral_server()\n"); |
| @@ -1414,6 +1427,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1414 | if (!server) | 1427 | if (!server) |
| 1415 | return ERR_PTR(-ENOMEM); | 1428 | return ERR_PTR(-ENOMEM); |
| 1416 | 1429 | ||
| 1430 | error = -ENOMEM; | ||
| 1431 | fattr = nfs_alloc_fattr(); | ||
| 1432 | if (fattr == NULL) | ||
| 1433 | goto error; | ||
| 1434 | |||
| 1417 | parent_server = NFS_SB(data->sb); | 1435 | parent_server = NFS_SB(data->sb); |
| 1418 | parent_client = parent_server->nfs_client; | 1436 | parent_client = parent_server->nfs_client; |
| 1419 | 1437 | ||
| @@ -1443,12 +1461,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1443 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1461 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
| 1444 | 1462 | ||
| 1445 | /* Probe the root fh to retrieve its FSID and filehandle */ | 1463 | /* Probe the root fh to retrieve its FSID and filehandle */ |
| 1446 | error = nfs4_path_walk(server, mntfh, data->mnt_path); | 1464 | error = nfs4_get_rootfh(server, mntfh); |
| 1447 | if (error < 0) | 1465 | if (error < 0) |
| 1448 | goto error; | 1466 | goto error; |
| 1449 | 1467 | ||
| 1450 | /* probe the filesystem info for this server filesystem */ | 1468 | /* probe the filesystem info for this server filesystem */ |
| 1451 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1469 | error = nfs_probe_fsinfo(server, mntfh, fattr); |
| 1452 | if (error < 0) | 1470 | if (error < 0) |
| 1453 | goto error; | 1471 | goto error; |
| 1454 | 1472 | ||
| @@ -1466,10 +1484,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1466 | 1484 | ||
| 1467 | server->mount_time = jiffies; | 1485 | server->mount_time = jiffies; |
| 1468 | 1486 | ||
| 1487 | nfs_free_fattr(fattr); | ||
| 1469 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | 1488 | dprintk("<-- nfs_create_referral_server() = %p\n", server); |
| 1470 | return server; | 1489 | return server; |
| 1471 | 1490 | ||
| 1472 | error: | 1491 | error: |
| 1492 | nfs_free_fattr(fattr); | ||
| 1473 | nfs_free_server(server); | 1493 | nfs_free_server(server); |
| 1474 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); | 1494 | dprintk("<-- nfs4_create_referral_server() = error %d\n", error); |
| 1475 | return ERR_PTR(error); | 1495 | return ERR_PTR(error); |
| @@ -1485,7 +1505,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1485 | struct nfs_fattr *fattr) | 1505 | struct nfs_fattr *fattr) |
| 1486 | { | 1506 | { |
| 1487 | struct nfs_server *server; | 1507 | struct nfs_server *server; |
| 1488 | struct nfs_fattr fattr_fsinfo; | 1508 | struct nfs_fattr *fattr_fsinfo; |
| 1489 | int error; | 1509 | int error; |
| 1490 | 1510 | ||
| 1491 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", | 1511 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", |
| @@ -1496,6 +1516,11 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1496 | if (!server) | 1516 | if (!server) |
| 1497 | return ERR_PTR(-ENOMEM); | 1517 | return ERR_PTR(-ENOMEM); |
| 1498 | 1518 | ||
| 1519 | error = -ENOMEM; | ||
| 1520 | fattr_fsinfo = nfs_alloc_fattr(); | ||
| 1521 | if (fattr_fsinfo == NULL) | ||
| 1522 | goto out_free_server; | ||
| 1523 | |||
| 1499 | /* Copy data from the source */ | 1524 | /* Copy data from the source */ |
| 1500 | server->nfs_client = source->nfs_client; | 1525 | server->nfs_client = source->nfs_client; |
| 1501 | atomic_inc(&server->nfs_client->cl_count); | 1526 | atomic_inc(&server->nfs_client->cl_count); |
| @@ -1512,7 +1537,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1512 | nfs_init_server_aclclient(server); | 1537 | nfs_init_server_aclclient(server); |
| 1513 | 1538 | ||
| 1514 | /* probe the filesystem info for this server filesystem */ | 1539 | /* probe the filesystem info for this server filesystem */ |
| 1515 | error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); | 1540 | error = nfs_probe_fsinfo(server, fh, fattr_fsinfo); |
| 1516 | if (error < 0) | 1541 | if (error < 0) |
| 1517 | goto out_free_server; | 1542 | goto out_free_server; |
| 1518 | 1543 | ||
| @@ -1534,10 +1559,12 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1534 | 1559 | ||
| 1535 | server->mount_time = jiffies; | 1560 | server->mount_time = jiffies; |
| 1536 | 1561 | ||
| 1562 | nfs_free_fattr(fattr_fsinfo); | ||
| 1537 | dprintk("<-- nfs_clone_server() = %p\n", server); | 1563 | dprintk("<-- nfs_clone_server() = %p\n", server); |
| 1538 | return server; | 1564 | return server; |
| 1539 | 1565 | ||
| 1540 | out_free_server: | 1566 | out_free_server: |
| 1567 | nfs_free_fattr(fattr_fsinfo); | ||
| 1541 | nfs_free_server(server); | 1568 | nfs_free_server(server); |
| 1542 | dprintk("<-- nfs_clone_server() = error %d\n", error); | 1569 | dprintk("<-- nfs_clone_server() = error %d\n", error); |
| 1543 | return ERR_PTR(error); | 1570 | return ERR_PTR(error); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ea61d26e7871..301634543974 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -213,7 +213,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 213 | struct nfs_delegation *freeme = NULL; | 213 | struct nfs_delegation *freeme = NULL; |
| 214 | int status = 0; | 214 | int status = 0; |
| 215 | 215 | ||
| 216 | delegation = kmalloc(sizeof(*delegation), GFP_KERNEL); | 216 | delegation = kmalloc(sizeof(*delegation), GFP_NOFS); |
| 217 | if (delegation == NULL) | 217 | if (delegation == NULL) |
| 218 | return -ENOMEM; | 218 | return -ENOMEM; |
| 219 | memcpy(delegation->stateid.data, res->delegation.data, | 219 | memcpy(delegation->stateid.data, res->delegation.data, |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a7bb5c694aa3..ee9a179ebdf3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -530,9 +530,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 530 | nfs_readdir_descriptor_t my_desc, | 530 | nfs_readdir_descriptor_t my_desc, |
| 531 | *desc = &my_desc; | 531 | *desc = &my_desc; |
| 532 | struct nfs_entry my_entry; | 532 | struct nfs_entry my_entry; |
| 533 | struct nfs_fh fh; | 533 | int res = -ENOMEM; |
| 534 | struct nfs_fattr fattr; | ||
| 535 | long res; | ||
| 536 | 534 | ||
| 537 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 535 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
| 538 | dentry->d_parent->d_name.name, dentry->d_name.name, | 536 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| @@ -554,9 +552,11 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 554 | 552 | ||
| 555 | my_entry.cookie = my_entry.prev_cookie = 0; | 553 | my_entry.cookie = my_entry.prev_cookie = 0; |
| 556 | my_entry.eof = 0; | 554 | my_entry.eof = 0; |
| 557 | my_entry.fh = &fh; | 555 | my_entry.fh = nfs_alloc_fhandle(); |
| 558 | my_entry.fattr = &fattr; | 556 | my_entry.fattr = nfs_alloc_fattr(); |
| 559 | nfs_fattr_init(&fattr); | 557 | if (my_entry.fh == NULL || my_entry.fattr == NULL) |
| 558 | goto out_alloc_failed; | ||
| 559 | |||
| 560 | desc->entry = &my_entry; | 560 | desc->entry = &my_entry; |
| 561 | 561 | ||
| 562 | nfs_block_sillyrename(dentry); | 562 | nfs_block_sillyrename(dentry); |
| @@ -598,7 +598,10 @@ out: | |||
| 598 | nfs_unblock_sillyrename(dentry); | 598 | nfs_unblock_sillyrename(dentry); |
| 599 | if (res > 0) | 599 | if (res > 0) |
| 600 | res = 0; | 600 | res = 0; |
| 601 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %ld\n", | 601 | out_alloc_failed: |
| 602 | nfs_free_fattr(my_entry.fattr); | ||
| 603 | nfs_free_fhandle(my_entry.fh); | ||
| 604 | dfprintk(FILE, "NFS: readdir(%s/%s) returns %d\n", | ||
| 602 | dentry->d_parent->d_name.name, dentry->d_name.name, | 605 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 603 | res); | 606 | res); |
| 604 | return res; | 607 | return res; |
| @@ -776,9 +779,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 776 | struct inode *dir; | 779 | struct inode *dir; |
| 777 | struct inode *inode; | 780 | struct inode *inode; |
| 778 | struct dentry *parent; | 781 | struct dentry *parent; |
| 782 | struct nfs_fh *fhandle = NULL; | ||
| 783 | struct nfs_fattr *fattr = NULL; | ||
| 779 | int error; | 784 | int error; |
| 780 | struct nfs_fh fhandle; | ||
| 781 | struct nfs_fattr fattr; | ||
| 782 | 785 | ||
| 783 | parent = dget_parent(dentry); | 786 | parent = dget_parent(dentry); |
| 784 | dir = parent->d_inode; | 787 | dir = parent->d_inode; |
| @@ -811,14 +814,22 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 811 | if (NFS_STALE(inode)) | 814 | if (NFS_STALE(inode)) |
| 812 | goto out_bad; | 815 | goto out_bad; |
| 813 | 816 | ||
| 814 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 817 | error = -ENOMEM; |
| 818 | fhandle = nfs_alloc_fhandle(); | ||
| 819 | fattr = nfs_alloc_fattr(); | ||
| 820 | if (fhandle == NULL || fattr == NULL) | ||
| 821 | goto out_error; | ||
| 822 | |||
| 823 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | ||
| 815 | if (error) | 824 | if (error) |
| 816 | goto out_bad; | 825 | goto out_bad; |
| 817 | if (nfs_compare_fh(NFS_FH(inode), &fhandle)) | 826 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
| 818 | goto out_bad; | 827 | goto out_bad; |
| 819 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) | 828 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
| 820 | goto out_bad; | 829 | goto out_bad; |
| 821 | 830 | ||
| 831 | nfs_free_fattr(fattr); | ||
| 832 | nfs_free_fhandle(fhandle); | ||
| 822 | out_set_verifier: | 833 | out_set_verifier: |
| 823 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 834 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 824 | out_valid: | 835 | out_valid: |
| @@ -842,11 +853,21 @@ out_zap_parent: | |||
| 842 | shrink_dcache_parent(dentry); | 853 | shrink_dcache_parent(dentry); |
| 843 | } | 854 | } |
| 844 | d_drop(dentry); | 855 | d_drop(dentry); |
| 856 | nfs_free_fattr(fattr); | ||
| 857 | nfs_free_fhandle(fhandle); | ||
| 845 | dput(parent); | 858 | dput(parent); |
| 846 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 859 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
| 847 | __func__, dentry->d_parent->d_name.name, | 860 | __func__, dentry->d_parent->d_name.name, |
| 848 | dentry->d_name.name); | 861 | dentry->d_name.name); |
| 849 | return 0; | 862 | return 0; |
| 863 | out_error: | ||
| 864 | nfs_free_fattr(fattr); | ||
| 865 | nfs_free_fhandle(fhandle); | ||
| 866 | dput(parent); | ||
| 867 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", | ||
| 868 | __func__, dentry->d_parent->d_name.name, | ||
| 869 | dentry->d_name.name, error); | ||
| 870 | return error; | ||
| 850 | } | 871 | } |
| 851 | 872 | ||
| 852 | /* | 873 | /* |
| @@ -911,9 +932,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 911 | struct dentry *res; | 932 | struct dentry *res; |
| 912 | struct dentry *parent; | 933 | struct dentry *parent; |
| 913 | struct inode *inode = NULL; | 934 | struct inode *inode = NULL; |
| 935 | struct nfs_fh *fhandle = NULL; | ||
| 936 | struct nfs_fattr *fattr = NULL; | ||
| 914 | int error; | 937 | int error; |
| 915 | struct nfs_fh fhandle; | ||
| 916 | struct nfs_fattr fattr; | ||
| 917 | 938 | ||
| 918 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 939 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
| 919 | dentry->d_parent->d_name.name, dentry->d_name.name); | 940 | dentry->d_parent->d_name.name, dentry->d_name.name); |
| @@ -923,7 +944,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 923 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 944 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
| 924 | goto out; | 945 | goto out; |
| 925 | 946 | ||
| 926 | res = ERR_PTR(-ENOMEM); | ||
| 927 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 947 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; |
| 928 | 948 | ||
| 929 | /* | 949 | /* |
| @@ -936,17 +956,23 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 936 | goto out; | 956 | goto out; |
| 937 | } | 957 | } |
| 938 | 958 | ||
| 959 | res = ERR_PTR(-ENOMEM); | ||
| 960 | fhandle = nfs_alloc_fhandle(); | ||
| 961 | fattr = nfs_alloc_fattr(); | ||
| 962 | if (fhandle == NULL || fattr == NULL) | ||
| 963 | goto out; | ||
| 964 | |||
| 939 | parent = dentry->d_parent; | 965 | parent = dentry->d_parent; |
| 940 | /* Protect against concurrent sillydeletes */ | 966 | /* Protect against concurrent sillydeletes */ |
| 941 | nfs_block_sillyrename(parent); | 967 | nfs_block_sillyrename(parent); |
| 942 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 968 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
| 943 | if (error == -ENOENT) | 969 | if (error == -ENOENT) |
| 944 | goto no_entry; | 970 | goto no_entry; |
| 945 | if (error < 0) { | 971 | if (error < 0) { |
| 946 | res = ERR_PTR(error); | 972 | res = ERR_PTR(error); |
| 947 | goto out_unblock_sillyrename; | 973 | goto out_unblock_sillyrename; |
| 948 | } | 974 | } |
| 949 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); | 975 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
| 950 | res = (struct dentry *)inode; | 976 | res = (struct dentry *)inode; |
| 951 | if (IS_ERR(res)) | 977 | if (IS_ERR(res)) |
| 952 | goto out_unblock_sillyrename; | 978 | goto out_unblock_sillyrename; |
| @@ -962,6 +988,8 @@ no_entry: | |||
| 962 | out_unblock_sillyrename: | 988 | out_unblock_sillyrename: |
| 963 | nfs_unblock_sillyrename(parent); | 989 | nfs_unblock_sillyrename(parent); |
| 964 | out: | 990 | out: |
| 991 | nfs_free_fattr(fattr); | ||
| 992 | nfs_free_fhandle(fhandle); | ||
| 965 | return res; | 993 | return res; |
| 966 | } | 994 | } |
| 967 | 995 | ||
| @@ -1669,28 +1697,33 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) | |||
| 1669 | smp_mb__after_atomic_dec(); | 1697 | smp_mb__after_atomic_dec(); |
| 1670 | } | 1698 | } |
| 1671 | 1699 | ||
| 1700 | static void nfs_access_free_list(struct list_head *head) | ||
| 1701 | { | ||
| 1702 | struct nfs_access_entry *cache; | ||
| 1703 | |||
| 1704 | while (!list_empty(head)) { | ||
| 1705 | cache = list_entry(head->next, struct nfs_access_entry, lru); | ||
| 1706 | list_del(&cache->lru); | ||
| 1707 | nfs_access_free_entry(cache); | ||
| 1708 | } | ||
| 1709 | } | ||
| 1710 | |||
| 1672 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | 1711 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) |
| 1673 | { | 1712 | { |
| 1674 | LIST_HEAD(head); | 1713 | LIST_HEAD(head); |
| 1675 | struct nfs_inode *nfsi; | 1714 | struct nfs_inode *nfsi; |
| 1676 | struct nfs_access_entry *cache; | 1715 | struct nfs_access_entry *cache; |
| 1677 | 1716 | ||
| 1678 | restart: | 1717 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
| 1718 | return (nr_to_scan == 0) ? 0 : -1; | ||
| 1719 | |||
| 1679 | spin_lock(&nfs_access_lru_lock); | 1720 | spin_lock(&nfs_access_lru_lock); |
| 1680 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1721 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
| 1681 | struct rw_semaphore *s_umount; | ||
| 1682 | struct inode *inode; | 1722 | struct inode *inode; |
| 1683 | 1723 | ||
| 1684 | if (nr_to_scan-- == 0) | 1724 | if (nr_to_scan-- == 0) |
| 1685 | break; | 1725 | break; |
| 1686 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | 1726 | inode = &nfsi->vfs_inode; |
| 1687 | if (!down_read_trylock(s_umount)) | ||
| 1688 | continue; | ||
| 1689 | inode = igrab(&nfsi->vfs_inode); | ||
| 1690 | if (inode == NULL) { | ||
| 1691 | up_read(s_umount); | ||
| 1692 | continue; | ||
| 1693 | } | ||
| 1694 | spin_lock(&inode->i_lock); | 1727 | spin_lock(&inode->i_lock); |
| 1695 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1728 | if (list_empty(&nfsi->access_cache_entry_lru)) |
| 1696 | goto remove_lru_entry; | 1729 | goto remove_lru_entry; |
| @@ -1704,61 +1737,47 @@ restart: | |||
| 1704 | else { | 1737 | else { |
| 1705 | remove_lru_entry: | 1738 | remove_lru_entry: |
| 1706 | list_del_init(&nfsi->access_cache_inode_lru); | 1739 | list_del_init(&nfsi->access_cache_inode_lru); |
| 1740 | smp_mb__before_clear_bit(); | ||
| 1707 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | 1741 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); |
| 1742 | smp_mb__after_clear_bit(); | ||
| 1708 | } | 1743 | } |
| 1709 | spin_unlock(&inode->i_lock); | ||
| 1710 | spin_unlock(&nfs_access_lru_lock); | ||
| 1711 | iput(inode); | ||
| 1712 | up_read(s_umount); | ||
| 1713 | goto restart; | ||
| 1714 | } | 1744 | } |
| 1715 | spin_unlock(&nfs_access_lru_lock); | 1745 | spin_unlock(&nfs_access_lru_lock); |
| 1716 | while (!list_empty(&head)) { | 1746 | nfs_access_free_list(&head); |
| 1717 | cache = list_entry(head.next, struct nfs_access_entry, lru); | ||
| 1718 | list_del(&cache->lru); | ||
| 1719 | nfs_access_free_entry(cache); | ||
| 1720 | } | ||
| 1721 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; | 1747 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; |
| 1722 | } | 1748 | } |
| 1723 | 1749 | ||
| 1724 | static void __nfs_access_zap_cache(struct inode *inode) | 1750 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
| 1725 | { | 1751 | { |
| 1726 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 1727 | struct rb_root *root_node = &nfsi->access_cache; | 1752 | struct rb_root *root_node = &nfsi->access_cache; |
| 1728 | struct rb_node *n, *dispose = NULL; | 1753 | struct rb_node *n; |
| 1729 | struct nfs_access_entry *entry; | 1754 | struct nfs_access_entry *entry; |
| 1730 | 1755 | ||
| 1731 | /* Unhook entries from the cache */ | 1756 | /* Unhook entries from the cache */ |
| 1732 | while ((n = rb_first(root_node)) != NULL) { | 1757 | while ((n = rb_first(root_node)) != NULL) { |
| 1733 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | 1758 | entry = rb_entry(n, struct nfs_access_entry, rb_node); |
| 1734 | rb_erase(n, root_node); | 1759 | rb_erase(n, root_node); |
| 1735 | list_del(&entry->lru); | 1760 | list_move(&entry->lru, head); |
| 1736 | n->rb_left = dispose; | ||
| 1737 | dispose = n; | ||
| 1738 | } | 1761 | } |
| 1739 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1762 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; |
| 1740 | spin_unlock(&inode->i_lock); | ||
| 1741 | |||
| 1742 | /* Now kill them all! */ | ||
| 1743 | while (dispose != NULL) { | ||
| 1744 | n = dispose; | ||
| 1745 | dispose = n->rb_left; | ||
| 1746 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); | ||
| 1747 | } | ||
| 1748 | } | 1763 | } |
| 1749 | 1764 | ||
| 1750 | void nfs_access_zap_cache(struct inode *inode) | 1765 | void nfs_access_zap_cache(struct inode *inode) |
| 1751 | { | 1766 | { |
| 1767 | LIST_HEAD(head); | ||
| 1768 | |||
| 1769 | if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) | ||
| 1770 | return; | ||
| 1752 | /* Remove from global LRU init */ | 1771 | /* Remove from global LRU init */ |
| 1753 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1772 | spin_lock(&nfs_access_lru_lock); |
| 1754 | spin_lock(&nfs_access_lru_lock); | 1773 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
| 1755 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); | 1774 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
| 1756 | spin_unlock(&nfs_access_lru_lock); | ||
| 1757 | } | ||
| 1758 | 1775 | ||
| 1759 | spin_lock(&inode->i_lock); | 1776 | spin_lock(&inode->i_lock); |
| 1760 | /* This will release the spinlock */ | 1777 | __nfs_access_zap_cache(NFS_I(inode), &head); |
| 1761 | __nfs_access_zap_cache(inode); | 1778 | spin_unlock(&inode->i_lock); |
| 1779 | spin_unlock(&nfs_access_lru_lock); | ||
| 1780 | nfs_access_free_list(&head); | ||
| 1762 | } | 1781 | } |
| 1763 | 1782 | ||
| 1764 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | 1783 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) |
| @@ -1809,8 +1828,8 @@ out_stale: | |||
| 1809 | nfs_access_free_entry(cache); | 1828 | nfs_access_free_entry(cache); |
| 1810 | return -ENOENT; | 1829 | return -ENOENT; |
| 1811 | out_zap: | 1830 | out_zap: |
| 1812 | /* This will release the spinlock */ | 1831 | spin_unlock(&inode->i_lock); |
| 1813 | __nfs_access_zap_cache(inode); | 1832 | nfs_access_zap_cache(inode); |
| 1814 | return -ENOENT; | 1833 | return -ENOENT; |
| 1815 | } | 1834 | } |
| 1816 | 1835 | ||
| @@ -1865,9 +1884,11 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
| 1865 | smp_mb__after_atomic_inc(); | 1884 | smp_mb__after_atomic_inc(); |
| 1866 | 1885 | ||
| 1867 | /* Add inode to global LRU list */ | 1886 | /* Add inode to global LRU list */ |
| 1868 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1887 | if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
| 1869 | spin_lock(&nfs_access_lru_lock); | 1888 | spin_lock(&nfs_access_lru_lock); |
| 1870 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1889 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
| 1890 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, | ||
| 1891 | &nfs_access_lru_list); | ||
| 1871 | spin_unlock(&nfs_access_lru_lock); | 1892 | spin_unlock(&nfs_access_lru_lock); |
| 1872 | } | 1893 | } |
| 1873 | } | 1894 | } |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8d965bddb87e..cac96bcc91e4 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -161,14 +161,17 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
| 161 | struct nfs_server *server = NFS_SERVER(inode); | 161 | struct nfs_server *server = NFS_SERVER(inode); |
| 162 | struct nfs_inode *nfsi = NFS_I(inode); | 162 | struct nfs_inode *nfsi = NFS_I(inode); |
| 163 | 163 | ||
| 164 | if (server->flags & NFS_MOUNT_NOAC) | 164 | if (nfs_have_delegated_attributes(inode)) |
| 165 | goto force_reval; | 165 | goto out_noreval; |
| 166 | |||
| 166 | if (filp->f_flags & O_DIRECT) | 167 | if (filp->f_flags & O_DIRECT) |
| 167 | goto force_reval; | 168 | goto force_reval; |
| 168 | if (nfsi->npages != 0) | 169 | if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
| 169 | return 0; | 170 | goto force_reval; |
| 170 | if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) | 171 | if (nfs_attribute_timeout(inode)) |
| 171 | return 0; | 172 | goto force_reval; |
| 173 | out_noreval: | ||
| 174 | return 0; | ||
| 172 | force_reval: | 175 | force_reval: |
| 173 | return __nfs_revalidate_inode(server, inode); | 176 | return __nfs_revalidate_inode(server, inode); |
| 174 | } | 177 | } |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index a6b16ed93229..ce153a6b3aec 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
| @@ -467,7 +467,8 @@ int __nfs_readpages_from_fscache(struct nfs_open_context *ctx, | |||
| 467 | struct list_head *pages, | 467 | struct list_head *pages, |
| 468 | unsigned *nr_pages) | 468 | unsigned *nr_pages) |
| 469 | { | 469 | { |
| 470 | int ret, npages = *nr_pages; | 470 | unsigned npages = *nr_pages; |
| 471 | int ret; | ||
| 471 | 472 | ||
| 472 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", | 473 | dfprintk(FSCACHE, "NFS: nfs_getpages_from_fscache (0x%p/%u/0x%p)\n", |
| 473 | NFS_I(inode)->fscache, npages, inode); | 474 | NFS_I(inode)->fscache, npages, inode); |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index b35d2a616066..7428f7d6273b 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
| @@ -78,159 +78,94 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 78 | { | 78 | { |
| 79 | struct nfs_server *server = NFS_SB(sb); | 79 | struct nfs_server *server = NFS_SB(sb); |
| 80 | struct nfs_fsinfo fsinfo; | 80 | struct nfs_fsinfo fsinfo; |
| 81 | struct nfs_fattr fattr; | 81 | struct dentry *ret; |
| 82 | struct dentry *mntroot; | ||
| 83 | struct inode *inode; | 82 | struct inode *inode; |
| 84 | int error; | 83 | int error; |
| 85 | 84 | ||
| 86 | /* get the actual root for this mount */ | 85 | /* get the actual root for this mount */ |
| 87 | fsinfo.fattr = &fattr; | 86 | fsinfo.fattr = nfs_alloc_fattr(); |
| 87 | if (fsinfo.fattr == NULL) | ||
| 88 | return ERR_PTR(-ENOMEM); | ||
| 88 | 89 | ||
| 89 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 90 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
| 90 | if (error < 0) { | 91 | if (error < 0) { |
| 91 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 92 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
| 92 | return ERR_PTR(error); | 93 | ret = ERR_PTR(error); |
| 94 | goto out; | ||
| 93 | } | 95 | } |
| 94 | 96 | ||
| 95 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); | 97 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr); |
| 96 | if (IS_ERR(inode)) { | 98 | if (IS_ERR(inode)) { |
| 97 | dprintk("nfs_get_root: get root inode failed\n"); | 99 | dprintk("nfs_get_root: get root inode failed\n"); |
| 98 | return ERR_CAST(inode); | 100 | ret = ERR_CAST(inode); |
| 101 | goto out; | ||
| 99 | } | 102 | } |
| 100 | 103 | ||
| 101 | error = nfs_superblock_set_dummy_root(sb, inode); | 104 | error = nfs_superblock_set_dummy_root(sb, inode); |
| 102 | if (error != 0) | 105 | if (error != 0) { |
| 103 | return ERR_PTR(error); | 106 | ret = ERR_PTR(error); |
| 107 | goto out; | ||
| 108 | } | ||
| 104 | 109 | ||
| 105 | /* root dentries normally start off anonymous and get spliced in later | 110 | /* root dentries normally start off anonymous and get spliced in later |
| 106 | * if the dentry tree reaches them; however if the dentry already | 111 | * if the dentry tree reaches them; however if the dentry already |
| 107 | * exists, we'll pick it up at this point and use it as the root | 112 | * exists, we'll pick it up at this point and use it as the root |
| 108 | */ | 113 | */ |
| 109 | mntroot = d_obtain_alias(inode); | 114 | ret = d_obtain_alias(inode); |
| 110 | if (IS_ERR(mntroot)) { | 115 | if (IS_ERR(ret)) { |
| 111 | dprintk("nfs_get_root: get root dentry failed\n"); | 116 | dprintk("nfs_get_root: get root dentry failed\n"); |
| 112 | return mntroot; | 117 | goto out; |
| 113 | } | 118 | } |
| 114 | 119 | ||
| 115 | security_d_instantiate(mntroot, inode); | 120 | security_d_instantiate(ret, inode); |
| 116 | |||
| 117 | if (!mntroot->d_op) | ||
| 118 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
| 119 | 121 | ||
| 120 | return mntroot; | 122 | if (ret->d_op == NULL) |
| 123 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; | ||
| 124 | out: | ||
| 125 | nfs_free_fattr(fsinfo.fattr); | ||
| 126 | return ret; | ||
| 121 | } | 127 | } |
| 122 | 128 | ||
| 123 | #ifdef CONFIG_NFS_V4 | 129 | #ifdef CONFIG_NFS_V4 |
| 124 | 130 | ||
| 125 | /* | 131 | int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) |
| 126 | * Do a simple pathwalk from the root FH of the server to the nominated target | ||
| 127 | * of the mountpoint | ||
| 128 | * - give error on symlinks | ||
| 129 | * - give error on ".." occurring in the path | ||
| 130 | * - follow traversals | ||
| 131 | */ | ||
| 132 | int nfs4_path_walk(struct nfs_server *server, | ||
| 133 | struct nfs_fh *mntfh, | ||
| 134 | const char *path) | ||
| 135 | { | 132 | { |
| 136 | struct nfs_fsinfo fsinfo; | 133 | struct nfs_fsinfo fsinfo; |
| 137 | struct nfs_fattr fattr; | 134 | int ret = -ENOMEM; |
| 138 | struct nfs_fh lastfh; | ||
| 139 | struct qstr name; | ||
| 140 | int ret; | ||
| 141 | 135 | ||
| 142 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | 136 | dprintk("--> nfs4_get_rootfh()\n"); |
| 143 | 137 | ||
| 144 | fsinfo.fattr = &fattr; | 138 | fsinfo.fattr = nfs_alloc_fattr(); |
| 145 | nfs_fattr_init(&fattr); | 139 | if (fsinfo.fattr == NULL) |
| 146 | 140 | goto out; | |
| 147 | /* Eat leading slashes */ | ||
| 148 | while (*path == '/') | ||
| 149 | path++; | ||
| 150 | 141 | ||
| 151 | /* Start by getting the root filehandle from the server */ | 142 | /* Start by getting the root filehandle from the server */ |
| 152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 143 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
| 153 | if (ret < 0) { | 144 | if (ret < 0) { |
| 154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | 145 | dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); |
| 155 | return ret; | 146 | goto out; |
| 156 | } | 147 | } |
| 157 | 148 | ||
| 158 | if (!S_ISDIR(fattr.mode)) { | 149 | if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_MODE) |
| 159 | printk(KERN_ERR "nfs4_get_root:" | 150 | || !S_ISDIR(fsinfo.fattr->mode)) { |
| 151 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
| 160 | " getroot encountered non-directory\n"); | 152 | " getroot encountered non-directory\n"); |
| 161 | return -ENOTDIR; | 153 | ret = -ENOTDIR; |
| 154 | goto out; | ||
| 162 | } | 155 | } |
| 163 | 156 | ||
| 164 | /* FIXME: It is quite valid for the server to return a referral here */ | 157 | if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
| 165 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 158 | printk(KERN_ERR "nfs4_get_rootfh:" |
| 166 | printk(KERN_ERR "nfs4_get_root:" | ||
| 167 | " getroot obtained referral\n"); | 159 | " getroot obtained referral\n"); |
| 168 | return -EREMOTE; | 160 | ret = -EREMOTE; |
| 169 | } | 161 | goto out; |
| 170 | |||
| 171 | next_component: | ||
| 172 | dprintk("Next: %s\n", path); | ||
| 173 | |||
| 174 | /* extract the next bit of the path */ | ||
| 175 | if (!*path) | ||
| 176 | goto path_walk_complete; | ||
| 177 | |||
| 178 | name.name = path; | ||
| 179 | while (*path && *path != '/') | ||
| 180 | path++; | ||
| 181 | name.len = path - (const char *) name.name; | ||
| 182 | |||
| 183 | if (name.len > NFS4_MAXNAMLEN) | ||
| 184 | return -ENAMETOOLONG; | ||
| 185 | |||
| 186 | eat_dot_dir: | ||
| 187 | while (*path == '/') | ||
| 188 | path++; | ||
| 189 | |||
| 190 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | ||
| 191 | path += 2; | ||
| 192 | goto eat_dot_dir; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* FIXME: Why shouldn't the user be able to use ".." in the path? */ | ||
| 196 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | ||
| 197 | ) { | ||
| 198 | printk(KERN_ERR "nfs4_get_root:" | ||
| 199 | " Mount path contains reference to \"..\"\n"); | ||
| 200 | return -EINVAL; | ||
| 201 | } | 162 | } |
| 202 | 163 | ||
| 203 | /* lookup the next FH in the sequence */ | 164 | memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); |
| 204 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | 165 | out: |
| 205 | 166 | nfs_free_fattr(fsinfo.fattr); | |
| 206 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | 167 | dprintk("<-- nfs4_get_rootfh() = %d\n", ret); |
| 207 | 168 | return ret; | |
| 208 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | ||
| 209 | mntfh, &fattr); | ||
| 210 | if (ret < 0) { | ||
| 211 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
| 212 | return ret; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (!S_ISDIR(fattr.mode)) { | ||
| 216 | printk(KERN_ERR "nfs4_get_root:" | ||
| 217 | " lookupfh encountered non-directory\n"); | ||
| 218 | return -ENOTDIR; | ||
| 219 | } | ||
| 220 | |||
| 221 | /* FIXME: Referrals are quite valid here too */ | ||
| 222 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
| 223 | printk(KERN_ERR "nfs4_get_root:" | ||
| 224 | " lookupfh obtained referral\n"); | ||
| 225 | return -EREMOTE; | ||
| 226 | } | ||
| 227 | |||
| 228 | goto next_component; | ||
| 229 | |||
| 230 | path_walk_complete: | ||
| 231 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
| 232 | dprintk("<-- nfs4_path_walk() = 0\n"); | ||
| 233 | return 0; | ||
| 234 | } | 169 | } |
| 235 | 170 | ||
| 236 | /* | 171 | /* |
| @@ -239,8 +174,8 @@ path_walk_complete: | |||
| 239 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 174 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) |
| 240 | { | 175 | { |
| 241 | struct nfs_server *server = NFS_SB(sb); | 176 | struct nfs_server *server = NFS_SB(sb); |
| 242 | struct nfs_fattr fattr; | 177 | struct nfs_fattr *fattr = NULL; |
| 243 | struct dentry *mntroot; | 178 | struct dentry *ret; |
| 244 | struct inode *inode; | 179 | struct inode *inode; |
| 245 | int error; | 180 | int error; |
| 246 | 181 | ||
| @@ -254,40 +189,50 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 254 | return ERR_PTR(error); | 189 | return ERR_PTR(error); |
| 255 | } | 190 | } |
| 256 | 191 | ||
| 192 | fattr = nfs_alloc_fattr(); | ||
| 193 | if (fattr == NULL) | ||
| 194 | return ERR_PTR(-ENOMEM);; | ||
| 195 | |||
| 257 | /* get the actual root for this mount */ | 196 | /* get the actual root for this mount */ |
| 258 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 197 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
| 259 | if (error < 0) { | 198 | if (error < 0) { |
| 260 | dprintk("nfs_get_root: getattr error = %d\n", -error); | 199 | dprintk("nfs_get_root: getattr error = %d\n", -error); |
| 261 | return ERR_PTR(error); | 200 | ret = ERR_PTR(error); |
| 201 | goto out; | ||
| 262 | } | 202 | } |
| 263 | 203 | ||
| 264 | inode = nfs_fhget(sb, mntfh, &fattr); | 204 | inode = nfs_fhget(sb, mntfh, fattr); |
| 265 | if (IS_ERR(inode)) { | 205 | if (IS_ERR(inode)) { |
| 266 | dprintk("nfs_get_root: get root inode failed\n"); | 206 | dprintk("nfs_get_root: get root inode failed\n"); |
| 267 | return ERR_CAST(inode); | 207 | ret = ERR_CAST(inode); |
| 208 | goto out; | ||
| 268 | } | 209 | } |
| 269 | 210 | ||
| 270 | error = nfs_superblock_set_dummy_root(sb, inode); | 211 | error = nfs_superblock_set_dummy_root(sb, inode); |
| 271 | if (error != 0) | 212 | if (error != 0) { |
| 272 | return ERR_PTR(error); | 213 | ret = ERR_PTR(error); |
| 214 | goto out; | ||
| 215 | } | ||
| 273 | 216 | ||
| 274 | /* root dentries normally start off anonymous and get spliced in later | 217 | /* root dentries normally start off anonymous and get spliced in later |
| 275 | * if the dentry tree reaches them; however if the dentry already | 218 | * if the dentry tree reaches them; however if the dentry already |
| 276 | * exists, we'll pick it up at this point and use it as the root | 219 | * exists, we'll pick it up at this point and use it as the root |
| 277 | */ | 220 | */ |
| 278 | mntroot = d_obtain_alias(inode); | 221 | ret = d_obtain_alias(inode); |
| 279 | if (IS_ERR(mntroot)) { | 222 | if (IS_ERR(ret)) { |
| 280 | dprintk("nfs_get_root: get root dentry failed\n"); | 223 | dprintk("nfs_get_root: get root dentry failed\n"); |
| 281 | return mntroot; | 224 | goto out; |
| 282 | } | 225 | } |
| 283 | 226 | ||
| 284 | security_d_instantiate(mntroot, inode); | 227 | security_d_instantiate(ret, inode); |
| 285 | 228 | ||
| 286 | if (!mntroot->d_op) | 229 | if (ret->d_op == NULL) |
| 287 | mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; | 230 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; |
| 288 | 231 | ||
| 232 | out: | ||
| 233 | nfs_free_fattr(fattr); | ||
| 289 | dprintk("<-- nfs4_get_root()\n"); | 234 | dprintk("<-- nfs4_get_root()\n"); |
| 290 | return mntroot; | 235 | return ret; |
| 291 | } | 236 | } |
| 292 | 237 | ||
| 293 | #endif /* CONFIG_NFS_V4 */ | 238 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 50a56edca0b5..099b3518feea 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -393,8 +393,8 @@ int | |||
| 393 | nfs_setattr(struct dentry *dentry, struct iattr *attr) | 393 | nfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 394 | { | 394 | { |
| 395 | struct inode *inode = dentry->d_inode; | 395 | struct inode *inode = dentry->d_inode; |
| 396 | struct nfs_fattr fattr; | 396 | struct nfs_fattr *fattr; |
| 397 | int error; | 397 | int error = -ENOMEM; |
| 398 | 398 | ||
| 399 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); | 399 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); |
| 400 | 400 | ||
| @@ -417,14 +417,20 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 417 | filemap_write_and_wait(inode->i_mapping); | 417 | filemap_write_and_wait(inode->i_mapping); |
| 418 | nfs_wb_all(inode); | 418 | nfs_wb_all(inode); |
| 419 | } | 419 | } |
| 420 | |||
| 421 | fattr = nfs_alloc_fattr(); | ||
| 422 | if (fattr == NULL) | ||
| 423 | goto out; | ||
| 420 | /* | 424 | /* |
| 421 | * Return any delegations if we're going to change ACLs | 425 | * Return any delegations if we're going to change ACLs |
| 422 | */ | 426 | */ |
| 423 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 427 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
| 424 | nfs_inode_return_delegation(inode); | 428 | nfs_inode_return_delegation(inode); |
| 425 | error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); | 429 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); |
| 426 | if (error == 0) | 430 | if (error == 0) |
| 427 | nfs_refresh_inode(inode, &fattr); | 431 | nfs_refresh_inode(inode, fattr); |
| 432 | nfs_free_fattr(fattr); | ||
| 433 | out: | ||
| 428 | return error; | 434 | return error; |
| 429 | } | 435 | } |
| 430 | 436 | ||
| @@ -682,7 +688,7 @@ int | |||
| 682 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 688 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
| 683 | { | 689 | { |
| 684 | int status = -ESTALE; | 690 | int status = -ESTALE; |
| 685 | struct nfs_fattr fattr; | 691 | struct nfs_fattr *fattr = NULL; |
| 686 | struct nfs_inode *nfsi = NFS_I(inode); | 692 | struct nfs_inode *nfsi = NFS_I(inode); |
| 687 | 693 | ||
| 688 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", | 694 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", |
| @@ -693,8 +699,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 693 | if (NFS_STALE(inode)) | 699 | if (NFS_STALE(inode)) |
| 694 | goto out; | 700 | goto out; |
| 695 | 701 | ||
| 702 | status = -ENOMEM; | ||
| 703 | fattr = nfs_alloc_fattr(); | ||
| 704 | if (fattr == NULL) | ||
| 705 | goto out; | ||
| 706 | |||
| 696 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | 707 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); |
| 697 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); | 708 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); |
| 698 | if (status != 0) { | 709 | if (status != 0) { |
| 699 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", | 710 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", |
| 700 | inode->i_sb->s_id, | 711 | inode->i_sb->s_id, |
| @@ -707,7 +718,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 707 | goto out; | 718 | goto out; |
| 708 | } | 719 | } |
| 709 | 720 | ||
| 710 | status = nfs_refresh_inode(inode, &fattr); | 721 | status = nfs_refresh_inode(inode, fattr); |
| 711 | if (status) { | 722 | if (status) { |
| 712 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", | 723 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", |
| 713 | inode->i_sb->s_id, | 724 | inode->i_sb->s_id, |
| @@ -723,6 +734,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 723 | (long long)NFS_FILEID(inode)); | 734 | (long long)NFS_FILEID(inode)); |
| 724 | 735 | ||
| 725 | out: | 736 | out: |
| 737 | nfs_free_fattr(fattr); | ||
| 726 | return status; | 738 | return status; |
| 727 | } | 739 | } |
| 728 | 740 | ||
| @@ -730,9 +742,14 @@ int nfs_attribute_timeout(struct inode *inode) | |||
| 730 | { | 742 | { |
| 731 | struct nfs_inode *nfsi = NFS_I(inode); | 743 | struct nfs_inode *nfsi = NFS_I(inode); |
| 732 | 744 | ||
| 745 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | ||
| 746 | } | ||
| 747 | |||
| 748 | static int nfs_attribute_cache_expired(struct inode *inode) | ||
| 749 | { | ||
| 733 | if (nfs_have_delegated_attributes(inode)) | 750 | if (nfs_have_delegated_attributes(inode)) |
| 734 | return 0; | 751 | return 0; |
| 735 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 752 | return nfs_attribute_timeout(inode); |
| 736 | } | 753 | } |
| 737 | 754 | ||
| 738 | /** | 755 | /** |
| @@ -745,7 +762,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
| 745 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 762 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
| 746 | { | 763 | { |
| 747 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) | 764 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) |
| 748 | && !nfs_attribute_timeout(inode)) | 765 | && !nfs_attribute_cache_expired(inode)) |
| 749 | return NFS_STALE(inode) ? -ESTALE : 0; | 766 | return NFS_STALE(inode) ? -ESTALE : 0; |
| 750 | return __nfs_revalidate_inode(server, inode); | 767 | return __nfs_revalidate_inode(server, inode); |
| 751 | } | 768 | } |
| @@ -782,7 +799,8 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
| 782 | int ret = 0; | 799 | int ret = 0; |
| 783 | 800 | ||
| 784 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | 801 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
| 785 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { | 802 | || nfs_attribute_cache_expired(inode) |
| 803 | || NFS_STALE(inode)) { | ||
| 786 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 804 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
| 787 | if (ret < 0) | 805 | if (ret < 0) |
| 788 | goto out; | 806 | goto out; |
| @@ -916,6 +934,26 @@ void nfs_fattr_init(struct nfs_fattr *fattr) | |||
| 916 | fattr->gencount = nfs_inc_attr_generation_counter(); | 934 | fattr->gencount = nfs_inc_attr_generation_counter(); |
| 917 | } | 935 | } |
| 918 | 936 | ||
| 937 | struct nfs_fattr *nfs_alloc_fattr(void) | ||
| 938 | { | ||
| 939 | struct nfs_fattr *fattr; | ||
| 940 | |||
| 941 | fattr = kmalloc(sizeof(*fattr), GFP_NOFS); | ||
| 942 | if (fattr != NULL) | ||
| 943 | nfs_fattr_init(fattr); | ||
| 944 | return fattr; | ||
| 945 | } | ||
| 946 | |||
| 947 | struct nfs_fh *nfs_alloc_fhandle(void) | ||
| 948 | { | ||
| 949 | struct nfs_fh *fh; | ||
| 950 | |||
| 951 | fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS); | ||
| 952 | if (fh != NULL) | ||
| 953 | fh->size = 0; | ||
| 954 | return fh; | ||
| 955 | } | ||
| 956 | |||
| 919 | /** | 957 | /** |
| 920 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | 958 | * nfs_inode_attrs_need_update - check if the inode attributes need updating |
| 921 | * @inode - pointer to inode | 959 | * @inode - pointer to inode |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 11f82f03c5de..d8bd619e386c 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -244,9 +244,7 @@ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); | |||
| 244 | #ifdef CONFIG_NFS_V4 | 244 | #ifdef CONFIG_NFS_V4 |
| 245 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); | 245 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); |
| 246 | 246 | ||
| 247 | extern int nfs4_path_walk(struct nfs_server *server, | 247 | extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); |
| 248 | struct nfs_fh *mntfh, | ||
| 249 | const char *path); | ||
| 250 | #endif | 248 | #endif |
| 251 | 249 | ||
| 252 | /* read.c */ | 250 | /* read.c */ |
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h index 1d8d5c813b01..c5832487c456 100644 --- a/fs/nfs/iostat.h +++ b/fs/nfs/iostat.h | |||
| @@ -36,14 +36,14 @@ static inline void nfs_inc_stats(const struct inode *inode, | |||
| 36 | 36 | ||
| 37 | static inline void nfs_add_server_stats(const struct nfs_server *server, | 37 | static inline void nfs_add_server_stats(const struct nfs_server *server, |
| 38 | enum nfs_stat_bytecounters stat, | 38 | enum nfs_stat_bytecounters stat, |
| 39 | unsigned long addend) | 39 | long addend) |
| 40 | { | 40 | { |
| 41 | this_cpu_add(server->io_stats->bytes[stat], addend); | 41 | this_cpu_add(server->io_stats->bytes[stat], addend); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static inline void nfs_add_stats(const struct inode *inode, | 44 | static inline void nfs_add_stats(const struct inode *inode, |
| 45 | enum nfs_stat_bytecounters stat, | 45 | enum nfs_stat_bytecounters stat, |
| 46 | unsigned long addend) | 46 | long addend) |
| 47 | { | 47 | { |
| 48 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); | 48 | nfs_add_server_stats(NFS_SERVER(inode), stat, addend); |
| 49 | } | 49 | } |
| @@ -51,7 +51,7 @@ static inline void nfs_add_stats(const struct inode *inode, | |||
| 51 | #ifdef CONFIG_NFS_FSCACHE | 51 | #ifdef CONFIG_NFS_FSCACHE |
| 52 | static inline void nfs_add_fscache_stats(struct inode *inode, | 52 | static inline void nfs_add_fscache_stats(struct inode *inode, |
| 53 | enum nfs_stat_fscachecounters stat, | 53 | enum nfs_stat_fscachecounters stat, |
| 54 | unsigned long addend) | 54 | long addend) |
| 55 | { | 55 | { |
| 56 | this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend); | 56 | this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend); |
| 57 | } | 57 | } |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 7888cf36022d..db6aa3673cf3 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -105,8 +105,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 105 | struct vfsmount *mnt; | 105 | struct vfsmount *mnt; |
| 106 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); | 106 | struct nfs_server *server = NFS_SERVER(dentry->d_inode); |
| 107 | struct dentry *parent; | 107 | struct dentry *parent; |
| 108 | struct nfs_fh fh; | 108 | struct nfs_fh *fh = NULL; |
| 109 | struct nfs_fattr fattr; | 109 | struct nfs_fattr *fattr = NULL; |
| 110 | int err; | 110 | int err; |
| 111 | 111 | ||
| 112 | dprintk("--> nfs_follow_mountpoint()\n"); | 112 | dprintk("--> nfs_follow_mountpoint()\n"); |
| @@ -115,6 +115,12 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 115 | if (IS_ROOT(dentry)) | 115 | if (IS_ROOT(dentry)) |
| 116 | goto out_err; | 116 | goto out_err; |
| 117 | 117 | ||
| 118 | err = -ENOMEM; | ||
| 119 | fh = nfs_alloc_fhandle(); | ||
| 120 | fattr = nfs_alloc_fattr(); | ||
| 121 | if (fh == NULL || fattr == NULL) | ||
| 122 | goto out_err; | ||
| 123 | |||
| 118 | dprintk("%s: enter\n", __func__); | 124 | dprintk("%s: enter\n", __func__); |
| 119 | dput(nd->path.dentry); | 125 | dput(nd->path.dentry); |
| 120 | nd->path.dentry = dget(dentry); | 126 | nd->path.dentry = dget(dentry); |
| @@ -123,16 +129,16 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 123 | parent = dget_parent(nd->path.dentry); | 129 | parent = dget_parent(nd->path.dentry); |
| 124 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, | 130 | err = server->nfs_client->rpc_ops->lookup(parent->d_inode, |
| 125 | &nd->path.dentry->d_name, | 131 | &nd->path.dentry->d_name, |
| 126 | &fh, &fattr); | 132 | fh, fattr); |
| 127 | dput(parent); | 133 | dput(parent); |
| 128 | if (err != 0) | 134 | if (err != 0) |
| 129 | goto out_err; | 135 | goto out_err; |
| 130 | 136 | ||
| 131 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) | 137 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
| 132 | mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); | 138 | mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); |
| 133 | else | 139 | else |
| 134 | mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, &fh, | 140 | mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh, |
| 135 | &fattr); | 141 | fattr); |
| 136 | err = PTR_ERR(mnt); | 142 | err = PTR_ERR(mnt); |
| 137 | if (IS_ERR(mnt)) | 143 | if (IS_ERR(mnt)) |
| 138 | goto out_err; | 144 | goto out_err; |
| @@ -151,6 +157,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 151 | nd->path.dentry = dget(mnt->mnt_root); | 157 | nd->path.dentry = dget(mnt->mnt_root); |
| 152 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | 158 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); |
| 153 | out: | 159 | out: |
| 160 | nfs_free_fattr(fattr); | ||
| 161 | nfs_free_fhandle(fh); | ||
| 154 | dprintk("%s: done, returned %d\n", __func__, err); | 162 | dprintk("%s: done, returned %d\n", __func__, err); |
| 155 | 163 | ||
| 156 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); | 164 | dprintk("<-- nfs_follow_mountpoint() = %d\n", err); |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index d150ae0c5ecd..9f88c5f4c7e2 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
| @@ -185,7 +185,6 @@ static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl, | |||
| 185 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | 185 | struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) |
| 186 | { | 186 | { |
| 187 | struct nfs_server *server = NFS_SERVER(inode); | 187 | struct nfs_server *server = NFS_SERVER(inode); |
| 188 | struct nfs_fattr fattr; | ||
| 189 | struct page *pages[NFSACL_MAXPAGES] = { }; | 188 | struct page *pages[NFSACL_MAXPAGES] = { }; |
| 190 | struct nfs3_getaclargs args = { | 189 | struct nfs3_getaclargs args = { |
| 191 | .fh = NFS_FH(inode), | 190 | .fh = NFS_FH(inode), |
| @@ -193,7 +192,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
| 193 | .pages = pages, | 192 | .pages = pages, |
| 194 | }; | 193 | }; |
| 195 | struct nfs3_getaclres res = { | 194 | struct nfs3_getaclres res = { |
| 196 | .fattr = &fattr, | 195 | 0 |
| 197 | }; | 196 | }; |
| 198 | struct rpc_message msg = { | 197 | struct rpc_message msg = { |
| 199 | .rpc_argp = &args, | 198 | .rpc_argp = &args, |
| @@ -228,7 +227,10 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
| 228 | 227 | ||
| 229 | dprintk("NFS call getacl\n"); | 228 | dprintk("NFS call getacl\n"); |
| 230 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; | 229 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; |
| 231 | nfs_fattr_init(&fattr); | 230 | res.fattr = nfs_alloc_fattr(); |
| 231 | if (res.fattr == NULL) | ||
| 232 | return ERR_PTR(-ENOMEM); | ||
| 233 | |||
| 232 | status = rpc_call_sync(server->client_acl, &msg, 0); | 234 | status = rpc_call_sync(server->client_acl, &msg, 0); |
| 233 | dprintk("NFS reply getacl: %d\n", status); | 235 | dprintk("NFS reply getacl: %d\n", status); |
| 234 | 236 | ||
| @@ -238,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
| 238 | 240 | ||
| 239 | switch (status) { | 241 | switch (status) { |
| 240 | case 0: | 242 | case 0: |
| 241 | status = nfs_refresh_inode(inode, &fattr); | 243 | status = nfs_refresh_inode(inode, res.fattr); |
| 242 | break; | 244 | break; |
| 243 | case -EPFNOSUPPORT: | 245 | case -EPFNOSUPPORT: |
| 244 | case -EPROTONOSUPPORT: | 246 | case -EPROTONOSUPPORT: |
| @@ -278,6 +280,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
| 278 | getout: | 280 | getout: |
| 279 | posix_acl_release(res.acl_access); | 281 | posix_acl_release(res.acl_access); |
| 280 | posix_acl_release(res.acl_default); | 282 | posix_acl_release(res.acl_default); |
| 283 | nfs_free_fattr(res.fattr); | ||
| 281 | 284 | ||
| 282 | if (status != 0) { | 285 | if (status != 0) { |
| 283 | posix_acl_release(acl); | 286 | posix_acl_release(acl); |
| @@ -290,7 +293,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
| 290 | struct posix_acl *dfacl) | 293 | struct posix_acl *dfacl) |
| 291 | { | 294 | { |
| 292 | struct nfs_server *server = NFS_SERVER(inode); | 295 | struct nfs_server *server = NFS_SERVER(inode); |
| 293 | struct nfs_fattr fattr; | 296 | struct nfs_fattr *fattr; |
| 294 | struct page *pages[NFSACL_MAXPAGES]; | 297 | struct page *pages[NFSACL_MAXPAGES]; |
| 295 | struct nfs3_setaclargs args = { | 298 | struct nfs3_setaclargs args = { |
| 296 | .inode = inode, | 299 | .inode = inode, |
| @@ -335,8 +338,13 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
| 335 | } | 338 | } |
| 336 | 339 | ||
| 337 | dprintk("NFS call setacl\n"); | 340 | dprintk("NFS call setacl\n"); |
| 341 | status = -ENOMEM; | ||
| 342 | fattr = nfs_alloc_fattr(); | ||
| 343 | if (fattr == NULL) | ||
| 344 | goto out_freepages; | ||
| 345 | |||
| 338 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; | 346 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; |
| 339 | nfs_fattr_init(&fattr); | 347 | msg.rpc_resp = fattr; |
| 340 | status = rpc_call_sync(server->client_acl, &msg, 0); | 348 | status = rpc_call_sync(server->client_acl, &msg, 0); |
| 341 | nfs_access_zap_cache(inode); | 349 | nfs_access_zap_cache(inode); |
| 342 | nfs_zap_acl_cache(inode); | 350 | nfs_zap_acl_cache(inode); |
| @@ -344,7 +352,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
| 344 | 352 | ||
| 345 | switch (status) { | 353 | switch (status) { |
| 346 | case 0: | 354 | case 0: |
| 347 | status = nfs_refresh_inode(inode, &fattr); | 355 | status = nfs_refresh_inode(inode, fattr); |
| 348 | nfs3_cache_acls(inode, acl, dfacl); | 356 | nfs3_cache_acls(inode, acl, dfacl); |
| 349 | break; | 357 | break; |
| 350 | case -EPFNOSUPPORT: | 358 | case -EPFNOSUPPORT: |
| @@ -355,6 +363,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, | |||
| 355 | case -ENOTSUPP: | 363 | case -ENOTSUPP: |
| 356 | status = -EOPNOTSUPP; | 364 | status = -EOPNOTSUPP; |
| 357 | } | 365 | } |
| 366 | nfs_free_fattr(fattr); | ||
| 358 | out_freepages: | 367 | out_freepages: |
| 359 | while (args.npages != 0) { | 368 | while (args.npages != 0) { |
| 360 | args.npages--; | 369 | args.npages--; |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index e701002694e5..fabb4f2849a1 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -144,14 +144,12 @@ static int | |||
| 144 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, | 144 | nfs3_proc_lookup(struct inode *dir, struct qstr *name, |
| 145 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 145 | struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
| 146 | { | 146 | { |
| 147 | struct nfs_fattr dir_attr; | ||
| 148 | struct nfs3_diropargs arg = { | 147 | struct nfs3_diropargs arg = { |
| 149 | .fh = NFS_FH(dir), | 148 | .fh = NFS_FH(dir), |
| 150 | .name = name->name, | 149 | .name = name->name, |
| 151 | .len = name->len | 150 | .len = name->len |
| 152 | }; | 151 | }; |
| 153 | struct nfs3_diropres res = { | 152 | struct nfs3_diropres res = { |
| 154 | .dir_attr = &dir_attr, | ||
| 155 | .fh = fhandle, | 153 | .fh = fhandle, |
| 156 | .fattr = fattr | 154 | .fattr = fattr |
| 157 | }; | 155 | }; |
| @@ -163,29 +161,30 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, | |||
| 163 | int status; | 161 | int status; |
| 164 | 162 | ||
| 165 | dprintk("NFS call lookup %s\n", name->name); | 163 | dprintk("NFS call lookup %s\n", name->name); |
| 166 | nfs_fattr_init(&dir_attr); | 164 | res.dir_attr = nfs_alloc_fattr(); |
| 165 | if (res.dir_attr == NULL) | ||
| 166 | return -ENOMEM; | ||
| 167 | |||
| 167 | nfs_fattr_init(fattr); | 168 | nfs_fattr_init(fattr); |
| 168 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 169 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 169 | nfs_refresh_inode(dir, &dir_attr); | 170 | nfs_refresh_inode(dir, res.dir_attr); |
| 170 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { | 171 | if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { |
| 171 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; | 172 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; |
| 172 | msg.rpc_argp = fhandle; | 173 | msg.rpc_argp = fhandle; |
| 173 | msg.rpc_resp = fattr; | 174 | msg.rpc_resp = fattr; |
| 174 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 175 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 175 | } | 176 | } |
| 177 | nfs_free_fattr(res.dir_attr); | ||
| 176 | dprintk("NFS reply lookup: %d\n", status); | 178 | dprintk("NFS reply lookup: %d\n", status); |
| 177 | return status; | 179 | return status; |
| 178 | } | 180 | } |
| 179 | 181 | ||
| 180 | static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 182 | static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
| 181 | { | 183 | { |
| 182 | struct nfs_fattr fattr; | ||
| 183 | struct nfs3_accessargs arg = { | 184 | struct nfs3_accessargs arg = { |
| 184 | .fh = NFS_FH(inode), | 185 | .fh = NFS_FH(inode), |
| 185 | }; | 186 | }; |
| 186 | struct nfs3_accessres res = { | 187 | struct nfs3_accessres res; |
| 187 | .fattr = &fattr, | ||
| 188 | }; | ||
| 189 | struct rpc_message msg = { | 188 | struct rpc_message msg = { |
| 190 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], | 189 | .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], |
| 191 | .rpc_argp = &arg, | 190 | .rpc_argp = &arg, |
| @@ -193,7 +192,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
| 193 | .rpc_cred = entry->cred, | 192 | .rpc_cred = entry->cred, |
| 194 | }; | 193 | }; |
| 195 | int mode = entry->mask; | 194 | int mode = entry->mask; |
| 196 | int status; | 195 | int status = -ENOMEM; |
| 197 | 196 | ||
| 198 | dprintk("NFS call access\n"); | 197 | dprintk("NFS call access\n"); |
| 199 | 198 | ||
| @@ -210,9 +209,13 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
| 210 | if (mode & MAY_EXEC) | 209 | if (mode & MAY_EXEC) |
| 211 | arg.access |= NFS3_ACCESS_EXECUTE; | 210 | arg.access |= NFS3_ACCESS_EXECUTE; |
| 212 | } | 211 | } |
| 213 | nfs_fattr_init(&fattr); | 212 | |
| 213 | res.fattr = nfs_alloc_fattr(); | ||
| 214 | if (res.fattr == NULL) | ||
| 215 | goto out; | ||
| 216 | |||
| 214 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 217 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 215 | nfs_refresh_inode(inode, &fattr); | 218 | nfs_refresh_inode(inode, res.fattr); |
| 216 | if (status == 0) { | 219 | if (status == 0) { |
| 217 | entry->mask = 0; | 220 | entry->mask = 0; |
| 218 | if (res.access & NFS3_ACCESS_READ) | 221 | if (res.access & NFS3_ACCESS_READ) |
| @@ -222,6 +225,8 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
| 222 | if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE)) | 225 | if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE)) |
| 223 | entry->mask |= MAY_EXEC; | 226 | entry->mask |= MAY_EXEC; |
| 224 | } | 227 | } |
| 228 | nfs_free_fattr(res.fattr); | ||
| 229 | out: | ||
| 225 | dprintk("NFS reply access: %d\n", status); | 230 | dprintk("NFS reply access: %d\n", status); |
| 226 | return status; | 231 | return status; |
| 227 | } | 232 | } |
| @@ -229,7 +234,7 @@ static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry) | |||
| 229 | static int nfs3_proc_readlink(struct inode *inode, struct page *page, | 234 | static int nfs3_proc_readlink(struct inode *inode, struct page *page, |
| 230 | unsigned int pgbase, unsigned int pglen) | 235 | unsigned int pgbase, unsigned int pglen) |
| 231 | { | 236 | { |
| 232 | struct nfs_fattr fattr; | 237 | struct nfs_fattr *fattr; |
| 233 | struct nfs3_readlinkargs args = { | 238 | struct nfs3_readlinkargs args = { |
| 234 | .fh = NFS_FH(inode), | 239 | .fh = NFS_FH(inode), |
| 235 | .pgbase = pgbase, | 240 | .pgbase = pgbase, |
| @@ -239,14 +244,19 @@ static int nfs3_proc_readlink(struct inode *inode, struct page *page, | |||
| 239 | struct rpc_message msg = { | 244 | struct rpc_message msg = { |
| 240 | .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], | 245 | .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], |
| 241 | .rpc_argp = &args, | 246 | .rpc_argp = &args, |
| 242 | .rpc_resp = &fattr, | ||
| 243 | }; | 247 | }; |
| 244 | int status; | 248 | int status = -ENOMEM; |
| 245 | 249 | ||
| 246 | dprintk("NFS call readlink\n"); | 250 | dprintk("NFS call readlink\n"); |
| 247 | nfs_fattr_init(&fattr); | 251 | fattr = nfs_alloc_fattr(); |
| 252 | if (fattr == NULL) | ||
| 253 | goto out; | ||
| 254 | msg.rpc_resp = fattr; | ||
| 255 | |||
| 248 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 256 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 249 | nfs_refresh_inode(inode, &fattr); | 257 | nfs_refresh_inode(inode, fattr); |
| 258 | nfs_free_fattr(fattr); | ||
| 259 | out: | ||
| 250 | dprintk("NFS reply readlink: %d\n", status); | 260 | dprintk("NFS reply readlink: %d\n", status); |
| 251 | return status; | 261 | return status; |
| 252 | } | 262 | } |
| @@ -396,12 +406,17 @@ nfs3_proc_remove(struct inode *dir, struct qstr *name) | |||
| 396 | .rpc_argp = &arg, | 406 | .rpc_argp = &arg, |
| 397 | .rpc_resp = &res, | 407 | .rpc_resp = &res, |
| 398 | }; | 408 | }; |
| 399 | int status; | 409 | int status = -ENOMEM; |
| 400 | 410 | ||
| 401 | dprintk("NFS call remove %s\n", name->name); | 411 | dprintk("NFS call remove %s\n", name->name); |
| 402 | nfs_fattr_init(&res.dir_attr); | 412 | res.dir_attr = nfs_alloc_fattr(); |
| 413 | if (res.dir_attr == NULL) | ||
| 414 | goto out; | ||
| 415 | |||
| 403 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 416 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 404 | nfs_post_op_update_inode(dir, &res.dir_attr); | 417 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 418 | nfs_free_fattr(res.dir_attr); | ||
| 419 | out: | ||
| 405 | dprintk("NFS reply remove: %d\n", status); | 420 | dprintk("NFS reply remove: %d\n", status); |
| 406 | return status; | 421 | return status; |
| 407 | } | 422 | } |
| @@ -419,7 +434,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 419 | if (nfs3_async_handle_jukebox(task, dir)) | 434 | if (nfs3_async_handle_jukebox(task, dir)) |
| 420 | return 0; | 435 | return 0; |
| 421 | res = task->tk_msg.rpc_resp; | 436 | res = task->tk_msg.rpc_resp; |
| 422 | nfs_post_op_update_inode(dir, &res->dir_attr); | 437 | nfs_post_op_update_inode(dir, res->dir_attr); |
| 423 | return 1; | 438 | return 1; |
| 424 | } | 439 | } |
| 425 | 440 | ||
| @@ -427,7 +442,6 @@ static int | |||
| 427 | nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | 442 | nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, |
| 428 | struct inode *new_dir, struct qstr *new_name) | 443 | struct inode *new_dir, struct qstr *new_name) |
| 429 | { | 444 | { |
| 430 | struct nfs_fattr old_dir_attr, new_dir_attr; | ||
| 431 | struct nfs3_renameargs arg = { | 445 | struct nfs3_renameargs arg = { |
| 432 | .fromfh = NFS_FH(old_dir), | 446 | .fromfh = NFS_FH(old_dir), |
| 433 | .fromname = old_name->name, | 447 | .fromname = old_name->name, |
| @@ -436,23 +450,27 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
| 436 | .toname = new_name->name, | 450 | .toname = new_name->name, |
| 437 | .tolen = new_name->len | 451 | .tolen = new_name->len |
| 438 | }; | 452 | }; |
| 439 | struct nfs3_renameres res = { | 453 | struct nfs3_renameres res; |
| 440 | .fromattr = &old_dir_attr, | ||
| 441 | .toattr = &new_dir_attr | ||
| 442 | }; | ||
| 443 | struct rpc_message msg = { | 454 | struct rpc_message msg = { |
| 444 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], | 455 | .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], |
| 445 | .rpc_argp = &arg, | 456 | .rpc_argp = &arg, |
| 446 | .rpc_resp = &res, | 457 | .rpc_resp = &res, |
| 447 | }; | 458 | }; |
| 448 | int status; | 459 | int status = -ENOMEM; |
| 449 | 460 | ||
| 450 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); | 461 | dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); |
| 451 | nfs_fattr_init(&old_dir_attr); | 462 | |
| 452 | nfs_fattr_init(&new_dir_attr); | 463 | res.fromattr = nfs_alloc_fattr(); |
| 464 | res.toattr = nfs_alloc_fattr(); | ||
| 465 | if (res.fromattr == NULL || res.toattr == NULL) | ||
| 466 | goto out; | ||
| 467 | |||
| 453 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); | 468 | status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); |
| 454 | nfs_post_op_update_inode(old_dir, &old_dir_attr); | 469 | nfs_post_op_update_inode(old_dir, res.fromattr); |
| 455 | nfs_post_op_update_inode(new_dir, &new_dir_attr); | 470 | nfs_post_op_update_inode(new_dir, res.toattr); |
| 471 | out: | ||
| 472 | nfs_free_fattr(res.toattr); | ||
| 473 | nfs_free_fattr(res.fromattr); | ||
| 456 | dprintk("NFS reply rename: %d\n", status); | 474 | dprintk("NFS reply rename: %d\n", status); |
| 457 | return status; | 475 | return status; |
| 458 | } | 476 | } |
| @@ -460,30 +478,32 @@ nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
| 460 | static int | 478 | static int |
| 461 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) | 479 | nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) |
| 462 | { | 480 | { |
| 463 | struct nfs_fattr dir_attr, fattr; | ||
| 464 | struct nfs3_linkargs arg = { | 481 | struct nfs3_linkargs arg = { |
| 465 | .fromfh = NFS_FH(inode), | 482 | .fromfh = NFS_FH(inode), |
| 466 | .tofh = NFS_FH(dir), | 483 | .tofh = NFS_FH(dir), |
| 467 | .toname = name->name, | 484 | .toname = name->name, |
| 468 | .tolen = name->len | 485 | .tolen = name->len |
| 469 | }; | 486 | }; |
| 470 | struct nfs3_linkres res = { | 487 | struct nfs3_linkres res; |
| 471 | .dir_attr = &dir_attr, | ||
| 472 | .fattr = &fattr | ||
| 473 | }; | ||
| 474 | struct rpc_message msg = { | 488 | struct rpc_message msg = { |
| 475 | .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], | 489 | .rpc_proc = &nfs3_procedures[NFS3PROC_LINK], |
| 476 | .rpc_argp = &arg, | 490 | .rpc_argp = &arg, |
| 477 | .rpc_resp = &res, | 491 | .rpc_resp = &res, |
| 478 | }; | 492 | }; |
| 479 | int status; | 493 | int status = -ENOMEM; |
| 480 | 494 | ||
| 481 | dprintk("NFS call link %s\n", name->name); | 495 | dprintk("NFS call link %s\n", name->name); |
| 482 | nfs_fattr_init(&dir_attr); | 496 | res.fattr = nfs_alloc_fattr(); |
| 483 | nfs_fattr_init(&fattr); | 497 | res.dir_attr = nfs_alloc_fattr(); |
| 498 | if (res.fattr == NULL || res.dir_attr == NULL) | ||
| 499 | goto out; | ||
| 500 | |||
| 484 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 501 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); |
| 485 | nfs_post_op_update_inode(dir, &dir_attr); | 502 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 486 | nfs_post_op_update_inode(inode, &fattr); | 503 | nfs_post_op_update_inode(inode, res.fattr); |
| 504 | out: | ||
| 505 | nfs_free_fattr(res.dir_attr); | ||
| 506 | nfs_free_fattr(res.fattr); | ||
| 487 | dprintk("NFS reply link: %d\n", status); | 507 | dprintk("NFS reply link: %d\n", status); |
| 488 | return status; | 508 | return status; |
| 489 | } | 509 | } |
| @@ -554,7 +574,7 @@ out: | |||
| 554 | static int | 574 | static int |
| 555 | nfs3_proc_rmdir(struct inode *dir, struct qstr *name) | 575 | nfs3_proc_rmdir(struct inode *dir, struct qstr *name) |
| 556 | { | 576 | { |
| 557 | struct nfs_fattr dir_attr; | 577 | struct nfs_fattr *dir_attr; |
| 558 | struct nfs3_diropargs arg = { | 578 | struct nfs3_diropargs arg = { |
| 559 | .fh = NFS_FH(dir), | 579 | .fh = NFS_FH(dir), |
| 560 | .name = name->name, | 580 | .name = name->name, |
| @@ -563,14 +583,19 @@ nfs3_proc_rmdir(struct inode *dir, struct qstr *name) | |||
| 563 | struct rpc_message msg = { | 583 | struct rpc_message msg = { |
| 564 | .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], | 584 | .rpc_proc = &nfs3_procedures[NFS3PROC_RMDIR], |
| 565 | .rpc_argp = &arg, | 585 | .rpc_argp = &arg, |
| 566 | .rpc_resp = &dir_attr, | ||
| 567 | }; | 586 | }; |
| 568 | int status; | 587 | int status = -ENOMEM; |
| 569 | 588 | ||
| 570 | dprintk("NFS call rmdir %s\n", name->name); | 589 | dprintk("NFS call rmdir %s\n", name->name); |
| 571 | nfs_fattr_init(&dir_attr); | 590 | dir_attr = nfs_alloc_fattr(); |
| 591 | if (dir_attr == NULL) | ||
| 592 | goto out; | ||
| 593 | |||
| 594 | msg.rpc_resp = dir_attr; | ||
| 572 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 595 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 573 | nfs_post_op_update_inode(dir, &dir_attr); | 596 | nfs_post_op_update_inode(dir, dir_attr); |
| 597 | nfs_free_fattr(dir_attr); | ||
| 598 | out: | ||
| 574 | dprintk("NFS reply rmdir: %d\n", status); | 599 | dprintk("NFS reply rmdir: %d\n", status); |
| 575 | return status; | 600 | return status; |
| 576 | } | 601 | } |
| @@ -589,7 +614,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
| 589 | u64 cookie, struct page *page, unsigned int count, int plus) | 614 | u64 cookie, struct page *page, unsigned int count, int plus) |
| 590 | { | 615 | { |
| 591 | struct inode *dir = dentry->d_inode; | 616 | struct inode *dir = dentry->d_inode; |
| 592 | struct nfs_fattr dir_attr; | ||
| 593 | __be32 *verf = NFS_COOKIEVERF(dir); | 617 | __be32 *verf = NFS_COOKIEVERF(dir); |
| 594 | struct nfs3_readdirargs arg = { | 618 | struct nfs3_readdirargs arg = { |
| 595 | .fh = NFS_FH(dir), | 619 | .fh = NFS_FH(dir), |
| @@ -600,7 +624,6 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
| 600 | .pages = &page | 624 | .pages = &page |
| 601 | }; | 625 | }; |
| 602 | struct nfs3_readdirres res = { | 626 | struct nfs3_readdirres res = { |
| 603 | .dir_attr = &dir_attr, | ||
| 604 | .verf = verf, | 627 | .verf = verf, |
| 605 | .plus = plus | 628 | .plus = plus |
| 606 | }; | 629 | }; |
| @@ -610,7 +633,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
| 610 | .rpc_resp = &res, | 633 | .rpc_resp = &res, |
| 611 | .rpc_cred = cred | 634 | .rpc_cred = cred |
| 612 | }; | 635 | }; |
| 613 | int status; | 636 | int status = -ENOMEM; |
| 614 | 637 | ||
| 615 | if (plus) | 638 | if (plus) |
| 616 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; | 639 | msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS]; |
| @@ -618,12 +641,17 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
| 618 | dprintk("NFS call readdir%s %d\n", | 641 | dprintk("NFS call readdir%s %d\n", |
| 619 | plus? "plus" : "", (unsigned int) cookie); | 642 | plus? "plus" : "", (unsigned int) cookie); |
| 620 | 643 | ||
| 621 | nfs_fattr_init(&dir_attr); | 644 | res.dir_attr = nfs_alloc_fattr(); |
| 645 | if (res.dir_attr == NULL) | ||
| 646 | goto out; | ||
| 647 | |||
| 622 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 648 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 623 | 649 | ||
| 624 | nfs_invalidate_atime(dir); | 650 | nfs_invalidate_atime(dir); |
| 651 | nfs_refresh_inode(dir, res.dir_attr); | ||
| 625 | 652 | ||
| 626 | nfs_refresh_inode(dir, &dir_attr); | 653 | nfs_free_fattr(res.dir_attr); |
| 654 | out: | ||
| 627 | dprintk("NFS reply readdir: %d\n", status); | 655 | dprintk("NFS reply readdir: %d\n", status); |
| 628 | return status; | 656 | return status; |
| 629 | } | 657 | } |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 56a86f6ac8b5..75dcfc7da365 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -762,7 +762,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr) | |||
| 762 | static int | 762 | static int |
| 763 | nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) | 763 | nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res) |
| 764 | { | 764 | { |
| 765 | return nfs3_xdr_wccstat(req, p, &res->dir_attr); | 765 | return nfs3_xdr_wccstat(req, p, res->dir_attr); |
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | /* | 768 | /* |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a187200a7aac..c538c6106e16 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -206,14 +206,14 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
| 206 | 206 | ||
| 207 | 207 | ||
| 208 | /* nfs4proc.c */ | 208 | /* nfs4proc.c */ |
| 209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); | 209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *); |
| 210 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 210 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *); |
| 211 | extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); | 211 | extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); |
| 212 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 212 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
| 213 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 213 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
| 214 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | 214 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); |
| 215 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | 215 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); |
| 216 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 216 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait); |
| 217 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 217 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
| 218 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 218 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
| 219 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); | 219 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
| @@ -286,7 +286,7 @@ extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | |||
| 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
| 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
| 288 | 288 | ||
| 289 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); | 289 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask); |
| 290 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 290 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); |
| 291 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); | 291 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); |
| 292 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); | 292 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index f071d12c613b..3c2a1724fbd2 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -115,6 +115,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 115 | char *page, char *page2, | 115 | char *page, char *page2, |
| 116 | const struct nfs4_fs_location *location) | 116 | const struct nfs4_fs_location *location) |
| 117 | { | 117 | { |
| 118 | const size_t addr_bufsize = sizeof(struct sockaddr_storage); | ||
| 118 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 119 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
| 119 | char *mnt_path; | 120 | char *mnt_path; |
| 120 | unsigned int maxbuflen; | 121 | unsigned int maxbuflen; |
| @@ -126,9 +127,12 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 126 | mountdata->mnt_path = mnt_path; | 127 | mountdata->mnt_path = mnt_path; |
| 127 | maxbuflen = mnt_path - 1 - page2; | 128 | maxbuflen = mnt_path - 1 - page2; |
| 128 | 129 | ||
| 130 | mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL); | ||
| 131 | if (mountdata->addr == NULL) | ||
| 132 | return ERR_PTR(-ENOMEM); | ||
| 133 | |||
| 129 | for (s = 0; s < location->nservers; s++) { | 134 | for (s = 0; s < location->nservers; s++) { |
| 130 | const struct nfs4_string *buf = &location->servers[s]; | 135 | const struct nfs4_string *buf = &location->servers[s]; |
| 131 | struct sockaddr_storage addr; | ||
| 132 | 136 | ||
| 133 | if (buf->len <= 0 || buf->len >= maxbuflen) | 137 | if (buf->len <= 0 || buf->len >= maxbuflen) |
| 134 | continue; | 138 | continue; |
| @@ -137,11 +141,10 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 137 | continue; | 141 | continue; |
| 138 | 142 | ||
| 139 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, | 143 | mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, |
| 140 | (struct sockaddr *)&addr, sizeof(addr)); | 144 | mountdata->addr, addr_bufsize); |
| 141 | if (mountdata->addrlen == 0) | 145 | if (mountdata->addrlen == 0) |
| 142 | continue; | 146 | continue; |
| 143 | 147 | ||
| 144 | mountdata->addr = (struct sockaddr *)&addr; | ||
| 145 | rpc_set_port(mountdata->addr, NFS_PORT); | 148 | rpc_set_port(mountdata->addr, NFS_PORT); |
| 146 | 149 | ||
| 147 | memcpy(page2, buf->data, buf->len); | 150 | memcpy(page2, buf->data, buf->len); |
| @@ -156,6 +159,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 156 | if (!IS_ERR(mnt)) | 159 | if (!IS_ERR(mnt)) |
| 157 | break; | 160 | break; |
| 158 | } | 161 | } |
| 162 | kfree(mountdata->addr); | ||
| 159 | return mnt; | 163 | return mnt; |
| 160 | } | 164 | } |
| 161 | 165 | ||
| @@ -221,8 +225,8 @@ out: | |||
| 221 | 225 | ||
| 222 | /* | 226 | /* |
| 223 | * nfs_do_refmount - handle crossing a referral on server | 227 | * nfs_do_refmount - handle crossing a referral on server |
| 228 | * @mnt_parent - mountpoint of referral | ||
| 224 | * @dentry - dentry of referral | 229 | * @dentry - dentry of referral |
| 225 | * @nd - nameidata info | ||
| 226 | * | 230 | * |
| 227 | */ | 231 | */ |
| 228 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 232 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 071fcedd517c..70015dd60a98 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -70,6 +70,9 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
| 70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
| 71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| 72 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 72 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
| 73 | static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | ||
| 74 | struct nfs_fattr *fattr, struct iattr *sattr, | ||
| 75 | struct nfs4_state *state); | ||
| 73 | 76 | ||
| 74 | /* Prevent leaks of NFSv4 errors into userland */ | 77 | /* Prevent leaks of NFSv4 errors into userland */ |
| 75 | static int nfs4_map_errors(int err) | 78 | static int nfs4_map_errors(int err) |
| @@ -714,17 +717,18 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
| 714 | 717 | ||
| 715 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 718 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
| 716 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 719 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
| 717 | const struct iattr *attrs) | 720 | const struct iattr *attrs, |
| 721 | gfp_t gfp_mask) | ||
| 718 | { | 722 | { |
| 719 | struct dentry *parent = dget_parent(path->dentry); | 723 | struct dentry *parent = dget_parent(path->dentry); |
| 720 | struct inode *dir = parent->d_inode; | 724 | struct inode *dir = parent->d_inode; |
| 721 | struct nfs_server *server = NFS_SERVER(dir); | 725 | struct nfs_server *server = NFS_SERVER(dir); |
| 722 | struct nfs4_opendata *p; | 726 | struct nfs4_opendata *p; |
| 723 | 727 | ||
| 724 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 728 | p = kzalloc(sizeof(*p), gfp_mask); |
| 725 | if (p == NULL) | 729 | if (p == NULL) |
| 726 | goto err; | 730 | goto err; |
| 727 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 731 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); |
| 728 | if (p->o_arg.seqid == NULL) | 732 | if (p->o_arg.seqid == NULL) |
| 729 | goto err_free; | 733 | goto err_free; |
| 730 | path_get(path); | 734 | path_get(path); |
| @@ -1060,7 +1064,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
| 1060 | { | 1064 | { |
| 1061 | struct nfs4_opendata *opendata; | 1065 | struct nfs4_opendata *opendata; |
| 1062 | 1066 | ||
| 1063 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); | 1067 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); |
| 1064 | if (opendata == NULL) | 1068 | if (opendata == NULL) |
| 1065 | return ERR_PTR(-ENOMEM); | 1069 | return ERR_PTR(-ENOMEM); |
| 1066 | opendata->state = state; | 1070 | opendata->state = state; |
| @@ -1648,7 +1652,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
| 1648 | if (path->dentry->d_inode != NULL) | 1652 | if (path->dentry->d_inode != NULL) |
| 1649 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); | 1653 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
| 1650 | status = -ENOMEM; | 1654 | status = -ENOMEM; |
| 1651 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); | 1655 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); |
| 1652 | if (opendata == NULL) | 1656 | if (opendata == NULL) |
| 1653 | goto err_put_state_owner; | 1657 | goto err_put_state_owner; |
| 1654 | 1658 | ||
| @@ -1659,15 +1663,24 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
| 1659 | if (status != 0) | 1663 | if (status != 0) |
| 1660 | goto err_opendata_put; | 1664 | goto err_opendata_put; |
| 1661 | 1665 | ||
| 1662 | if (opendata->o_arg.open_flags & O_EXCL) | ||
| 1663 | nfs4_exclusive_attrset(opendata, sattr); | ||
| 1664 | |||
| 1665 | state = nfs4_opendata_to_nfs4_state(opendata); | 1666 | state = nfs4_opendata_to_nfs4_state(opendata); |
| 1666 | status = PTR_ERR(state); | 1667 | status = PTR_ERR(state); |
| 1667 | if (IS_ERR(state)) | 1668 | if (IS_ERR(state)) |
| 1668 | goto err_opendata_put; | 1669 | goto err_opendata_put; |
| 1669 | if (server->caps & NFS_CAP_POSIX_LOCK) | 1670 | if (server->caps & NFS_CAP_POSIX_LOCK) |
| 1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 1671 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
| 1672 | |||
| 1673 | if (opendata->o_arg.open_flags & O_EXCL) { | ||
| 1674 | nfs4_exclusive_attrset(opendata, sattr); | ||
| 1675 | |||
| 1676 | nfs_fattr_init(opendata->o_res.f_attr); | ||
| 1677 | status = nfs4_do_setattr(state->inode, cred, | ||
| 1678 | opendata->o_res.f_attr, sattr, | ||
| 1679 | state); | ||
| 1680 | if (status == 0) | ||
| 1681 | nfs_setattr_update_inode(state->inode, sattr); | ||
| 1682 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); | ||
| 1683 | } | ||
| 1671 | nfs4_opendata_put(opendata); | 1684 | nfs4_opendata_put(opendata); |
| 1672 | nfs4_put_state_owner(sp); | 1685 | nfs4_put_state_owner(sp); |
| 1673 | *res = state; | 1686 | *res = state; |
| @@ -1914,7 +1927,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
| 1914 | * | 1927 | * |
| 1915 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1928 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
| 1916 | */ | 1929 | */ |
| 1917 | int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | 1930 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait) |
| 1918 | { | 1931 | { |
| 1919 | struct nfs_server *server = NFS_SERVER(state->inode); | 1932 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 1920 | struct nfs4_closedata *calldata; | 1933 | struct nfs4_closedata *calldata; |
| @@ -1933,7 +1946,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1933 | }; | 1946 | }; |
| 1934 | int status = -ENOMEM; | 1947 | int status = -ENOMEM; |
| 1935 | 1948 | ||
| 1936 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 1949 | calldata = kzalloc(sizeof(*calldata), gfp_mask); |
| 1937 | if (calldata == NULL) | 1950 | if (calldata == NULL) |
| 1938 | goto out; | 1951 | goto out; |
| 1939 | calldata->inode = state->inode; | 1952 | calldata->inode = state->inode; |
| @@ -1941,7 +1954,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1941 | calldata->arg.fh = NFS_FH(state->inode); | 1954 | calldata->arg.fh = NFS_FH(state->inode); |
| 1942 | calldata->arg.stateid = &state->open_stateid; | 1955 | calldata->arg.stateid = &state->open_stateid; |
| 1943 | /* Serialization for the sequence id */ | 1956 | /* Serialization for the sequence id */ |
| 1944 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1957 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask); |
| 1945 | if (calldata->arg.seqid == NULL) | 1958 | if (calldata->arg.seqid == NULL) |
| 1946 | goto out_free_calldata; | 1959 | goto out_free_calldata; |
| 1947 | calldata->arg.fmode = 0; | 1960 | calldata->arg.fmode = 0; |
| @@ -2404,14 +2417,12 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh | |||
| 2404 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) | 2417 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
| 2405 | { | 2418 | { |
| 2406 | struct nfs_server *server = NFS_SERVER(inode); | 2419 | struct nfs_server *server = NFS_SERVER(inode); |
| 2407 | struct nfs_fattr fattr; | ||
| 2408 | struct nfs4_accessargs args = { | 2420 | struct nfs4_accessargs args = { |
| 2409 | .fh = NFS_FH(inode), | 2421 | .fh = NFS_FH(inode), |
| 2410 | .bitmask = server->attr_bitmask, | 2422 | .bitmask = server->attr_bitmask, |
| 2411 | }; | 2423 | }; |
| 2412 | struct nfs4_accessres res = { | 2424 | struct nfs4_accessres res = { |
| 2413 | .server = server, | 2425 | .server = server, |
| 2414 | .fattr = &fattr, | ||
| 2415 | }; | 2426 | }; |
| 2416 | struct rpc_message msg = { | 2427 | struct rpc_message msg = { |
| 2417 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], | 2428 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], |
| @@ -2438,7 +2449,11 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 2438 | if (mode & MAY_EXEC) | 2449 | if (mode & MAY_EXEC) |
| 2439 | args.access |= NFS4_ACCESS_EXECUTE; | 2450 | args.access |= NFS4_ACCESS_EXECUTE; |
| 2440 | } | 2451 | } |
| 2441 | nfs_fattr_init(&fattr); | 2452 | |
| 2453 | res.fattr = nfs_alloc_fattr(); | ||
| 2454 | if (res.fattr == NULL) | ||
| 2455 | return -ENOMEM; | ||
| 2456 | |||
| 2442 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2457 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 2443 | if (!status) { | 2458 | if (!status) { |
| 2444 | entry->mask = 0; | 2459 | entry->mask = 0; |
| @@ -2448,8 +2463,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 2448 | entry->mask |= MAY_WRITE; | 2463 | entry->mask |= MAY_WRITE; |
| 2449 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | 2464 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) |
| 2450 | entry->mask |= MAY_EXEC; | 2465 | entry->mask |= MAY_EXEC; |
| 2451 | nfs_refresh_inode(inode, &fattr); | 2466 | nfs_refresh_inode(inode, res.fattr); |
| 2452 | } | 2467 | } |
| 2468 | nfs_free_fattr(res.fattr); | ||
| 2453 | return status; | 2469 | return status; |
| 2454 | } | 2470 | } |
| 2455 | 2471 | ||
| @@ -2562,13 +2578,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 2562 | } | 2578 | } |
| 2563 | d_add(dentry, igrab(state->inode)); | 2579 | d_add(dentry, igrab(state->inode)); |
| 2564 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 2580 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 2565 | if (flags & O_EXCL) { | ||
| 2566 | struct nfs_fattr fattr; | ||
| 2567 | status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state); | ||
| 2568 | if (status == 0) | ||
| 2569 | nfs_setattr_update_inode(state->inode, sattr); | ||
| 2570 | nfs_post_op_update_inode(state->inode, &fattr); | ||
| 2571 | } | ||
| 2572 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) | 2581 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
| 2573 | status = nfs4_intent_set_file(nd, &path, state, fmode); | 2582 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
| 2574 | else | 2583 | else |
| @@ -2596,14 +2605,19 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
| 2596 | .rpc_argp = &args, | 2605 | .rpc_argp = &args, |
| 2597 | .rpc_resp = &res, | 2606 | .rpc_resp = &res, |
| 2598 | }; | 2607 | }; |
| 2599 | int status; | 2608 | int status = -ENOMEM; |
| 2609 | |||
| 2610 | res.dir_attr = nfs_alloc_fattr(); | ||
| 2611 | if (res.dir_attr == NULL) | ||
| 2612 | goto out; | ||
| 2600 | 2613 | ||
| 2601 | nfs_fattr_init(&res.dir_attr); | ||
| 2602 | status = nfs4_call_sync(server, &msg, &args, &res, 1); | 2614 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
| 2603 | if (status == 0) { | 2615 | if (status == 0) { |
| 2604 | update_changeattr(dir, &res.cinfo); | 2616 | update_changeattr(dir, &res.cinfo); |
| 2605 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2617 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 2606 | } | 2618 | } |
| 2619 | nfs_free_fattr(res.dir_attr); | ||
| 2620 | out: | ||
| 2607 | return status; | 2621 | return status; |
| 2608 | } | 2622 | } |
| 2609 | 2623 | ||
| @@ -2638,7 +2652,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 2638 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2652 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
| 2639 | return 0; | 2653 | return 0; |
| 2640 | update_changeattr(dir, &res->cinfo); | 2654 | update_changeattr(dir, &res->cinfo); |
| 2641 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2655 | nfs_post_op_update_inode(dir, res->dir_attr); |
| 2642 | return 1; | 2656 | return 1; |
| 2643 | } | 2657 | } |
| 2644 | 2658 | ||
| @@ -2653,29 +2667,31 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
| 2653 | .new_name = new_name, | 2667 | .new_name = new_name, |
| 2654 | .bitmask = server->attr_bitmask, | 2668 | .bitmask = server->attr_bitmask, |
| 2655 | }; | 2669 | }; |
| 2656 | struct nfs_fattr old_fattr, new_fattr; | ||
| 2657 | struct nfs4_rename_res res = { | 2670 | struct nfs4_rename_res res = { |
| 2658 | .server = server, | 2671 | .server = server, |
| 2659 | .old_fattr = &old_fattr, | ||
| 2660 | .new_fattr = &new_fattr, | ||
| 2661 | }; | 2672 | }; |
| 2662 | struct rpc_message msg = { | 2673 | struct rpc_message msg = { |
| 2663 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], | 2674 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], |
| 2664 | .rpc_argp = &arg, | 2675 | .rpc_argp = &arg, |
| 2665 | .rpc_resp = &res, | 2676 | .rpc_resp = &res, |
| 2666 | }; | 2677 | }; |
| 2667 | int status; | 2678 | int status = -ENOMEM; |
| 2668 | 2679 | ||
| 2669 | nfs_fattr_init(res.old_fattr); | 2680 | res.old_fattr = nfs_alloc_fattr(); |
| 2670 | nfs_fattr_init(res.new_fattr); | 2681 | res.new_fattr = nfs_alloc_fattr(); |
| 2671 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2682 | if (res.old_fattr == NULL || res.new_fattr == NULL) |
| 2683 | goto out; | ||
| 2672 | 2684 | ||
| 2685 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | ||
| 2673 | if (!status) { | 2686 | if (!status) { |
| 2674 | update_changeattr(old_dir, &res.old_cinfo); | 2687 | update_changeattr(old_dir, &res.old_cinfo); |
| 2675 | nfs_post_op_update_inode(old_dir, res.old_fattr); | 2688 | nfs_post_op_update_inode(old_dir, res.old_fattr); |
| 2676 | update_changeattr(new_dir, &res.new_cinfo); | 2689 | update_changeattr(new_dir, &res.new_cinfo); |
| 2677 | nfs_post_op_update_inode(new_dir, res.new_fattr); | 2690 | nfs_post_op_update_inode(new_dir, res.new_fattr); |
| 2678 | } | 2691 | } |
| 2692 | out: | ||
| 2693 | nfs_free_fattr(res.new_fattr); | ||
| 2694 | nfs_free_fattr(res.old_fattr); | ||
| 2679 | return status; | 2695 | return status; |
| 2680 | } | 2696 | } |
| 2681 | 2697 | ||
| @@ -2702,28 +2718,30 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
| 2702 | .name = name, | 2718 | .name = name, |
| 2703 | .bitmask = server->attr_bitmask, | 2719 | .bitmask = server->attr_bitmask, |
| 2704 | }; | 2720 | }; |
| 2705 | struct nfs_fattr fattr, dir_attr; | ||
| 2706 | struct nfs4_link_res res = { | 2721 | struct nfs4_link_res res = { |
| 2707 | .server = server, | 2722 | .server = server, |
| 2708 | .fattr = &fattr, | ||
| 2709 | .dir_attr = &dir_attr, | ||
| 2710 | }; | 2723 | }; |
| 2711 | struct rpc_message msg = { | 2724 | struct rpc_message msg = { |
| 2712 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], | 2725 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], |
| 2713 | .rpc_argp = &arg, | 2726 | .rpc_argp = &arg, |
| 2714 | .rpc_resp = &res, | 2727 | .rpc_resp = &res, |
| 2715 | }; | 2728 | }; |
| 2716 | int status; | 2729 | int status = -ENOMEM; |
| 2730 | |||
| 2731 | res.fattr = nfs_alloc_fattr(); | ||
| 2732 | res.dir_attr = nfs_alloc_fattr(); | ||
| 2733 | if (res.fattr == NULL || res.dir_attr == NULL) | ||
| 2734 | goto out; | ||
| 2717 | 2735 | ||
| 2718 | nfs_fattr_init(res.fattr); | ||
| 2719 | nfs_fattr_init(res.dir_attr); | ||
| 2720 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2736 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 2721 | if (!status) { | 2737 | if (!status) { |
| 2722 | update_changeattr(dir, &res.cinfo); | 2738 | update_changeattr(dir, &res.cinfo); |
| 2723 | nfs_post_op_update_inode(dir, res.dir_attr); | 2739 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 2724 | nfs_post_op_update_inode(inode, res.fattr); | 2740 | nfs_post_op_update_inode(inode, res.fattr); |
| 2725 | } | 2741 | } |
| 2726 | 2742 | out: | |
| 2743 | nfs_free_fattr(res.dir_attr); | ||
| 2744 | nfs_free_fattr(res.fattr); | ||
| 2727 | return status; | 2745 | return status; |
| 2728 | } | 2746 | } |
| 2729 | 2747 | ||
| @@ -3146,23 +3164,31 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
| 3146 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3164 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
| 3147 | } | 3165 | } |
| 3148 | 3166 | ||
| 3167 | struct nfs4_renewdata { | ||
| 3168 | struct nfs_client *client; | ||
| 3169 | unsigned long timestamp; | ||
| 3170 | }; | ||
| 3171 | |||
| 3149 | /* | 3172 | /* |
| 3150 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3173 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
| 3151 | * standalone procedure for queueing an asynchronous RENEW. | 3174 | * standalone procedure for queueing an asynchronous RENEW. |
| 3152 | */ | 3175 | */ |
| 3153 | static void nfs4_renew_release(void *data) | 3176 | static void nfs4_renew_release(void *calldata) |
| 3154 | { | 3177 | { |
| 3155 | struct nfs_client *clp = data; | 3178 | struct nfs4_renewdata *data = calldata; |
| 3179 | struct nfs_client *clp = data->client; | ||
| 3156 | 3180 | ||
| 3157 | if (atomic_read(&clp->cl_count) > 1) | 3181 | if (atomic_read(&clp->cl_count) > 1) |
| 3158 | nfs4_schedule_state_renewal(clp); | 3182 | nfs4_schedule_state_renewal(clp); |
| 3159 | nfs_put_client(clp); | 3183 | nfs_put_client(clp); |
| 3184 | kfree(data); | ||
| 3160 | } | 3185 | } |
| 3161 | 3186 | ||
| 3162 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3187 | static void nfs4_renew_done(struct rpc_task *task, void *calldata) |
| 3163 | { | 3188 | { |
| 3164 | struct nfs_client *clp = data; | 3189 | struct nfs4_renewdata *data = calldata; |
| 3165 | unsigned long timestamp = task->tk_start; | 3190 | struct nfs_client *clp = data->client; |
| 3191 | unsigned long timestamp = data->timestamp; | ||
| 3166 | 3192 | ||
| 3167 | if (task->tk_status < 0) { | 3193 | if (task->tk_status < 0) { |
| 3168 | /* Unless we're shutting down, schedule state recovery! */ | 3194 | /* Unless we're shutting down, schedule state recovery! */ |
| @@ -3188,11 +3214,17 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 3188 | .rpc_argp = clp, | 3214 | .rpc_argp = clp, |
| 3189 | .rpc_cred = cred, | 3215 | .rpc_cred = cred, |
| 3190 | }; | 3216 | }; |
| 3217 | struct nfs4_renewdata *data; | ||
| 3191 | 3218 | ||
| 3192 | if (!atomic_inc_not_zero(&clp->cl_count)) | 3219 | if (!atomic_inc_not_zero(&clp->cl_count)) |
| 3193 | return -EIO; | 3220 | return -EIO; |
| 3221 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
| 3222 | if (data == NULL) | ||
| 3223 | return -ENOMEM; | ||
| 3224 | data->client = clp; | ||
| 3225 | data->timestamp = jiffies; | ||
| 3194 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3226 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
| 3195 | &nfs4_renew_ops, clp); | 3227 | &nfs4_renew_ops, data); |
| 3196 | } | 3228 | } |
| 3197 | 3229 | ||
| 3198 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3230 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
| @@ -3494,7 +3526,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 3494 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | 3526 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); |
| 3495 | } | 3527 | } |
| 3496 | 3528 | ||
| 3497 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3529 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
| 3530 | unsigned short port, struct rpc_cred *cred, | ||
| 3531 | struct nfs4_setclientid_res *res) | ||
| 3498 | { | 3532 | { |
| 3499 | nfs4_verifier sc_verifier; | 3533 | nfs4_verifier sc_verifier; |
| 3500 | struct nfs4_setclientid setclientid = { | 3534 | struct nfs4_setclientid setclientid = { |
| @@ -3504,7 +3538,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
| 3504 | struct rpc_message msg = { | 3538 | struct rpc_message msg = { |
| 3505 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 3539 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
| 3506 | .rpc_argp = &setclientid, | 3540 | .rpc_argp = &setclientid, |
| 3507 | .rpc_resp = clp, | 3541 | .rpc_resp = res, |
| 3508 | .rpc_cred = cred, | 3542 | .rpc_cred = cred, |
| 3509 | }; | 3543 | }; |
| 3510 | __be32 *p; | 3544 | __be32 *p; |
| @@ -3547,12 +3581,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
| 3547 | return status; | 3581 | return status; |
| 3548 | } | 3582 | } |
| 3549 | 3583 | ||
| 3550 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3584 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
| 3585 | struct nfs4_setclientid_res *arg, | ||
| 3586 | struct rpc_cred *cred) | ||
| 3551 | { | 3587 | { |
| 3552 | struct nfs_fsinfo fsinfo; | 3588 | struct nfs_fsinfo fsinfo; |
| 3553 | struct rpc_message msg = { | 3589 | struct rpc_message msg = { |
| 3554 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 3590 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
| 3555 | .rpc_argp = clp, | 3591 | .rpc_argp = arg, |
| 3556 | .rpc_resp = &fsinfo, | 3592 | .rpc_resp = &fsinfo, |
| 3557 | .rpc_cred = cred, | 3593 | .rpc_cred = cred, |
| 3558 | }; | 3594 | }; |
| @@ -3570,12 +3606,14 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre | |||
| 3570 | return status; | 3606 | return status; |
| 3571 | } | 3607 | } |
| 3572 | 3608 | ||
| 3573 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3609 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
| 3610 | struct nfs4_setclientid_res *arg, | ||
| 3611 | struct rpc_cred *cred) | ||
| 3574 | { | 3612 | { |
| 3575 | long timeout = 0; | 3613 | long timeout = 0; |
| 3576 | int err; | 3614 | int err; |
| 3577 | do { | 3615 | do { |
| 3578 | err = _nfs4_proc_setclientid_confirm(clp, cred); | 3616 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); |
| 3579 | switch (err) { | 3617 | switch (err) { |
| 3580 | case 0: | 3618 | case 0: |
| 3581 | return err; | 3619 | return err; |
| @@ -3667,7 +3705,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3667 | }; | 3705 | }; |
| 3668 | int status = 0; | 3706 | int status = 0; |
| 3669 | 3707 | ||
| 3670 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 3708 | data = kzalloc(sizeof(*data), GFP_NOFS); |
| 3671 | if (data == NULL) | 3709 | if (data == NULL) |
| 3672 | return -ENOMEM; | 3710 | return -ENOMEM; |
| 3673 | data->args.fhandle = &data->fh; | 3711 | data->args.fhandle = &data->fh; |
| @@ -3823,7 +3861,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
| 3823 | struct nfs4_unlockdata *p; | 3861 | struct nfs4_unlockdata *p; |
| 3824 | struct inode *inode = lsp->ls_state->inode; | 3862 | struct inode *inode = lsp->ls_state->inode; |
| 3825 | 3863 | ||
| 3826 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 3864 | p = kzalloc(sizeof(*p), GFP_NOFS); |
| 3827 | if (p == NULL) | 3865 | if (p == NULL) |
| 3828 | return NULL; | 3866 | return NULL; |
| 3829 | p->arg.fh = NFS_FH(inode); | 3867 | p->arg.fh = NFS_FH(inode); |
| @@ -3961,7 +3999,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
| 3961 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 3999 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
| 3962 | goto out; | 4000 | goto out; |
| 3963 | lsp = request->fl_u.nfs4_fl.owner; | 4001 | lsp = request->fl_u.nfs4_fl.owner; |
| 3964 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4002 | seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); |
| 3965 | status = -ENOMEM; | 4003 | status = -ENOMEM; |
| 3966 | if (seqid == NULL) | 4004 | if (seqid == NULL) |
| 3967 | goto out; | 4005 | goto out; |
| @@ -3989,22 +4027,23 @@ struct nfs4_lockdata { | |||
| 3989 | }; | 4027 | }; |
| 3990 | 4028 | ||
| 3991 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 4029 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
| 3992 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | 4030 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp, |
| 4031 | gfp_t gfp_mask) | ||
| 3993 | { | 4032 | { |
| 3994 | struct nfs4_lockdata *p; | 4033 | struct nfs4_lockdata *p; |
| 3995 | struct inode *inode = lsp->ls_state->inode; | 4034 | struct inode *inode = lsp->ls_state->inode; |
| 3996 | struct nfs_server *server = NFS_SERVER(inode); | 4035 | struct nfs_server *server = NFS_SERVER(inode); |
| 3997 | 4036 | ||
| 3998 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 4037 | p = kzalloc(sizeof(*p), gfp_mask); |
| 3999 | if (p == NULL) | 4038 | if (p == NULL) |
| 4000 | return NULL; | 4039 | return NULL; |
| 4001 | 4040 | ||
| 4002 | p->arg.fh = NFS_FH(inode); | 4041 | p->arg.fh = NFS_FH(inode); |
| 4003 | p->arg.fl = &p->fl; | 4042 | p->arg.fl = &p->fl; |
| 4004 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); | 4043 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask); |
| 4005 | if (p->arg.open_seqid == NULL) | 4044 | if (p->arg.open_seqid == NULL) |
| 4006 | goto out_free; | 4045 | goto out_free; |
| 4007 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4046 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask); |
| 4008 | if (p->arg.lock_seqid == NULL) | 4047 | if (p->arg.lock_seqid == NULL) |
| 4009 | goto out_free_seqid; | 4048 | goto out_free_seqid; |
| 4010 | p->arg.lock_stateid = &lsp->ls_stateid; | 4049 | p->arg.lock_stateid = &lsp->ls_stateid; |
| @@ -4158,7 +4197,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 4158 | 4197 | ||
| 4159 | dprintk("%s: begin!\n", __func__); | 4198 | dprintk("%s: begin!\n", __func__); |
| 4160 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), | 4199 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), |
| 4161 | fl->fl_u.nfs4_fl.owner); | 4200 | fl->fl_u.nfs4_fl.owner, |
| 4201 | recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS); | ||
| 4162 | if (data == NULL) | 4202 | if (data == NULL) |
| 4163 | return -ENOMEM; | 4203 | return -ENOMEM; |
| 4164 | if (IS_SETLKW(cmd)) | 4204 | if (IS_SETLKW(cmd)) |
| @@ -4647,7 +4687,7 @@ static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, | |||
| 4647 | if (max_reqs != tbl->max_slots) { | 4687 | if (max_reqs != tbl->max_slots) { |
| 4648 | ret = -ENOMEM; | 4688 | ret = -ENOMEM; |
| 4649 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), | 4689 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
| 4650 | GFP_KERNEL); | 4690 | GFP_NOFS); |
| 4651 | if (!new) | 4691 | if (!new) |
| 4652 | goto out; | 4692 | goto out; |
| 4653 | ret = 0; | 4693 | ret = 0; |
| @@ -4712,7 +4752,7 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
| 4712 | 4752 | ||
| 4713 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | 4753 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); |
| 4714 | 4754 | ||
| 4715 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4755 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); |
| 4716 | if (!slot) | 4756 | if (!slot) |
| 4717 | goto out; | 4757 | goto out; |
| 4718 | ret = 0; | 4758 | ret = 0; |
| @@ -4761,7 +4801,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 4761 | struct nfs4_session *session; | 4801 | struct nfs4_session *session; |
| 4762 | struct nfs4_slot_table *tbl; | 4802 | struct nfs4_slot_table *tbl; |
| 4763 | 4803 | ||
| 4764 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | 4804 | session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); |
| 4765 | if (!session) | 4805 | if (!session) |
| 4766 | return NULL; | 4806 | return NULL; |
| 4767 | 4807 | ||
| @@ -5105,8 +5145,8 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
| 5105 | 5145 | ||
| 5106 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5146 | if (!atomic_inc_not_zero(&clp->cl_count)) |
| 5107 | return -EIO; | 5147 | return -EIO; |
| 5108 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5148 | args = kzalloc(sizeof(*args), GFP_NOFS); |
| 5109 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5149 | res = kzalloc(sizeof(*res), GFP_NOFS); |
| 5110 | if (!args || !res) { | 5150 | if (!args || !res) { |
| 5111 | kfree(args); | 5151 | kfree(args); |
| 5112 | kfree(res); | 5152 | kfree(res); |
| @@ -5207,7 +5247,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
| 5207 | int status = -ENOMEM; | 5247 | int status = -ENOMEM; |
| 5208 | 5248 | ||
| 5209 | dprintk("--> %s\n", __func__); | 5249 | dprintk("--> %s\n", __func__); |
| 5210 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 5250 | calldata = kzalloc(sizeof(*calldata), GFP_NOFS); |
| 5211 | if (calldata == NULL) | 5251 | if (calldata == NULL) |
| 5212 | goto out; | 5252 | goto out; |
| 5213 | calldata->clp = clp; | 5253 | calldata->clp = clp; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6c5ed51f105e..34acf5926fdc 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -62,6 +62,7 @@ static LIST_HEAD(nfs4_clientid_list); | |||
| 62 | 62 | ||
| 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
| 64 | { | 64 | { |
| 65 | struct nfs4_setclientid_res clid; | ||
| 65 | unsigned short port; | 66 | unsigned short port; |
| 66 | int status; | 67 | int status; |
| 67 | 68 | ||
| @@ -69,11 +70,15 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 69 | if (clp->cl_addr.ss_family == AF_INET6) | 70 | if (clp->cl_addr.ss_family == AF_INET6) |
| 70 | port = nfs_callback_tcpport6; | 71 | port = nfs_callback_tcpport6; |
| 71 | 72 | ||
| 72 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred); | 73 | status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid); |
| 73 | if (status == 0) | 74 | if (status != 0) |
| 74 | status = nfs4_proc_setclientid_confirm(clp, cred); | 75 | goto out; |
| 75 | if (status == 0) | 76 | status = nfs4_proc_setclientid_confirm(clp, &clid, cred); |
| 76 | nfs4_schedule_state_renewal(clp); | 77 | if (status != 0) |
| 78 | goto out; | ||
| 79 | clp->cl_clientid = clid.clientid; | ||
| 80 | nfs4_schedule_state_renewal(clp); | ||
| 81 | out: | ||
| 77 | return status; | 82 | return status; |
| 78 | } | 83 | } |
| 79 | 84 | ||
| @@ -361,7 +366,7 @@ nfs4_alloc_state_owner(void) | |||
| 361 | { | 366 | { |
| 362 | struct nfs4_state_owner *sp; | 367 | struct nfs4_state_owner *sp; |
| 363 | 368 | ||
| 364 | sp = kzalloc(sizeof(*sp),GFP_KERNEL); | 369 | sp = kzalloc(sizeof(*sp),GFP_NOFS); |
| 365 | if (!sp) | 370 | if (!sp) |
| 366 | return NULL; | 371 | return NULL; |
| 367 | spin_lock_init(&sp->so_lock); | 372 | spin_lock_init(&sp->so_lock); |
| @@ -435,7 +440,7 @@ nfs4_alloc_open_state(void) | |||
| 435 | { | 440 | { |
| 436 | struct nfs4_state *state; | 441 | struct nfs4_state *state; |
| 437 | 442 | ||
| 438 | state = kzalloc(sizeof(*state), GFP_KERNEL); | 443 | state = kzalloc(sizeof(*state), GFP_NOFS); |
| 439 | if (!state) | 444 | if (!state) |
| 440 | return NULL; | 445 | return NULL; |
| 441 | atomic_set(&state->count, 1); | 446 | atomic_set(&state->count, 1); |
| @@ -537,7 +542,8 @@ void nfs4_put_open_state(struct nfs4_state *state) | |||
| 537 | /* | 542 | /* |
| 538 | * Close the current file. | 543 | * Close the current file. |
| 539 | */ | 544 | */ |
| 540 | static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, int wait) | 545 | static void __nfs4_close(struct path *path, struct nfs4_state *state, |
| 546 | fmode_t fmode, gfp_t gfp_mask, int wait) | ||
| 541 | { | 547 | { |
| 542 | struct nfs4_state_owner *owner = state->owner; | 548 | struct nfs4_state_owner *owner = state->owner; |
| 543 | int call_close = 0; | 549 | int call_close = 0; |
| @@ -578,17 +584,17 @@ static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fm | |||
| 578 | nfs4_put_open_state(state); | 584 | nfs4_put_open_state(state); |
| 579 | nfs4_put_state_owner(owner); | 585 | nfs4_put_state_owner(owner); |
| 580 | } else | 586 | } else |
| 581 | nfs4_do_close(path, state, wait); | 587 | nfs4_do_close(path, state, gfp_mask, wait); |
| 582 | } | 588 | } |
| 583 | 589 | ||
| 584 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) | 590 | void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode) |
| 585 | { | 591 | { |
| 586 | __nfs4_close(path, state, fmode, 0); | 592 | __nfs4_close(path, state, fmode, GFP_NOFS, 0); |
| 587 | } | 593 | } |
| 588 | 594 | ||
| 589 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) | 595 | void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) |
| 590 | { | 596 | { |
| 591 | __nfs4_close(path, state, fmode, 1); | 597 | __nfs4_close(path, state, fmode, GFP_KERNEL, 1); |
| 592 | } | 598 | } |
| 593 | 599 | ||
| 594 | /* | 600 | /* |
| @@ -618,7 +624,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 618 | struct nfs4_lock_state *lsp; | 624 | struct nfs4_lock_state *lsp; |
| 619 | struct nfs_client *clp = state->owner->so_client; | 625 | struct nfs_client *clp = state->owner->so_client; |
| 620 | 626 | ||
| 621 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 627 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
| 622 | if (lsp == NULL) | 628 | if (lsp == NULL) |
| 623 | return NULL; | 629 | return NULL; |
| 624 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); | 630 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); |
| @@ -754,11 +760,11 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
| 754 | nfs4_put_lock_state(lsp); | 760 | nfs4_put_lock_state(lsp); |
| 755 | } | 761 | } |
| 756 | 762 | ||
| 757 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | 763 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) |
| 758 | { | 764 | { |
| 759 | struct nfs_seqid *new; | 765 | struct nfs_seqid *new; |
| 760 | 766 | ||
| 761 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 767 | new = kmalloc(sizeof(*new), gfp_mask); |
| 762 | if (new != NULL) { | 768 | if (new != NULL) { |
| 763 | new->sequence = counter; | 769 | new->sequence = counter; |
| 764 | INIT_LIST_HEAD(&new->list); | 770 | INIT_LIST_HEAD(&new->list); |
| @@ -1347,7 +1353,7 @@ static int nfs4_recall_slot(struct nfs_client *clp) | |||
| 1347 | 1353 | ||
| 1348 | nfs4_begin_drain_session(clp); | 1354 | nfs4_begin_drain_session(clp); |
| 1349 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | 1355 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), |
| 1350 | GFP_KERNEL); | 1356 | GFP_NOFS); |
| 1351 | if (!new) | 1357 | if (!new) |
| 1352 | return -ENOMEM; | 1358 | return -ENOMEM; |
| 1353 | 1359 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 38f3b582e7c2..6bdef28efa33 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -1504,14 +1504,14 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1504 | hdr->replen += decode_setclientid_maxsz; | 1504 | hdr->replen += decode_setclientid_maxsz; |
| 1505 | } | 1505 | } |
| 1506 | 1506 | ||
| 1507 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1507 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) |
| 1508 | { | 1508 | { |
| 1509 | __be32 *p; | 1509 | __be32 *p; |
| 1510 | 1510 | ||
| 1511 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); | 1511 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); |
| 1512 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); | 1512 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); |
| 1513 | p = xdr_encode_hyper(p, client_state->cl_clientid); | 1513 | p = xdr_encode_hyper(p, arg->clientid); |
| 1514 | xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1514 | xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE); |
| 1515 | hdr->nops++; | 1515 | hdr->nops++; |
| 1516 | hdr->replen += decode_setclientid_confirm_maxsz; | 1516 | hdr->replen += decode_setclientid_confirm_maxsz; |
| 1517 | } | 1517 | } |
| @@ -2324,7 +2324,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
| 2324 | /* | 2324 | /* |
| 2325 | * a SETCLIENTID_CONFIRM request | 2325 | * a SETCLIENTID_CONFIRM request |
| 2326 | */ | 2326 | */ |
| 2327 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) | 2327 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg) |
| 2328 | { | 2328 | { |
| 2329 | struct xdr_stream xdr; | 2329 | struct xdr_stream xdr; |
| 2330 | struct compound_hdr hdr = { | 2330 | struct compound_hdr hdr = { |
| @@ -2334,7 +2334,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
| 2334 | 2334 | ||
| 2335 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2335 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2336 | encode_compound_hdr(&xdr, req, &hdr); | 2336 | encode_compound_hdr(&xdr, req, &hdr); |
| 2337 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2337 | encode_setclientid_confirm(&xdr, arg, &hdr); |
| 2338 | encode_putrootfh(&xdr, &hdr); | 2338 | encode_putrootfh(&xdr, &hdr); |
| 2339 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2339 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
| 2340 | encode_nops(&hdr); | 2340 | encode_nops(&hdr); |
| @@ -4397,7 +4397,7 @@ out_overflow: | |||
| 4397 | return -EIO; | 4397 | return -EIO; |
| 4398 | } | 4398 | } |
| 4399 | 4399 | ||
| 4400 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | 4400 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res) |
| 4401 | { | 4401 | { |
| 4402 | __be32 *p; | 4402 | __be32 *p; |
| 4403 | uint32_t opnum; | 4403 | uint32_t opnum; |
| @@ -4417,8 +4417,8 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
| 4417 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); | 4417 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); |
| 4418 | if (unlikely(!p)) | 4418 | if (unlikely(!p)) |
| 4419 | goto out_overflow; | 4419 | goto out_overflow; |
| 4420 | p = xdr_decode_hyper(p, &clp->cl_clientid); | 4420 | p = xdr_decode_hyper(p, &res->clientid); |
| 4421 | memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); | 4421 | memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE); |
| 4422 | } else if (nfserr == NFSERR_CLID_INUSE) { | 4422 | } else if (nfserr == NFSERR_CLID_INUSE) { |
| 4423 | uint32_t len; | 4423 | uint32_t len; |
| 4424 | 4424 | ||
| @@ -4815,7 +4815,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
| 4815 | goto out; | 4815 | goto out; |
| 4816 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4816 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
| 4817 | goto out; | 4817 | goto out; |
| 4818 | decode_getfattr(&xdr, &res->dir_attr, res->server, | 4818 | decode_getfattr(&xdr, res->dir_attr, res->server, |
| 4819 | !RPC_IS_ASYNC(rqstp->rq_task)); | 4819 | !RPC_IS_ASYNC(rqstp->rq_task)); |
| 4820 | out: | 4820 | out: |
| 4821 | return status; | 4821 | return status; |
| @@ -5498,7 +5498,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | |||
| 5498 | * Decode SETCLIENTID response | 5498 | * Decode SETCLIENTID response |
| 5499 | */ | 5499 | */ |
| 5500 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | 5500 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, |
| 5501 | struct nfs_client *clp) | 5501 | struct nfs4_setclientid_res *res) |
| 5502 | { | 5502 | { |
| 5503 | struct xdr_stream xdr; | 5503 | struct xdr_stream xdr; |
| 5504 | struct compound_hdr hdr; | 5504 | struct compound_hdr hdr; |
| @@ -5507,7 +5507,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
| 5507 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5507 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 5508 | status = decode_compound_hdr(&xdr, &hdr); | 5508 | status = decode_compound_hdr(&xdr, &hdr); |
| 5509 | if (!status) | 5509 | if (!status) |
| 5510 | status = decode_setclientid(&xdr, clp); | 5510 | status = decode_setclientid(&xdr, res); |
| 5511 | return status; | 5511 | return status; |
| 5512 | } | 5512 | } |
| 5513 | 5513 | ||
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8c55b27c0de4..6bd19d843af7 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -488,7 +488,6 @@ static int __init root_nfs_ports(void) | |||
| 488 | */ | 488 | */ |
| 489 | static int __init root_nfs_get_handle(void) | 489 | static int __init root_nfs_get_handle(void) |
| 490 | { | 490 | { |
| 491 | struct nfs_fh fh; | ||
| 492 | struct sockaddr_in sin; | 491 | struct sockaddr_in sin; |
| 493 | unsigned int auth_flav_len = 0; | 492 | unsigned int auth_flav_len = 0; |
| 494 | struct nfs_mount_request request = { | 493 | struct nfs_mount_request request = { |
| @@ -499,21 +498,24 @@ static int __init root_nfs_get_handle(void) | |||
| 499 | NFS_MNT3_VERSION : NFS_MNT_VERSION, | 498 | NFS_MNT3_VERSION : NFS_MNT_VERSION, |
| 500 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | 499 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? |
| 501 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | 500 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, |
| 502 | .fh = &fh, | ||
| 503 | .auth_flav_len = &auth_flav_len, | 501 | .auth_flav_len = &auth_flav_len, |
| 504 | }; | 502 | }; |
| 505 | int status; | 503 | int status = -ENOMEM; |
| 506 | 504 | ||
| 505 | request.fh = nfs_alloc_fhandle(); | ||
| 506 | if (!request.fh) | ||
| 507 | goto out; | ||
| 507 | set_sockaddr(&sin, servaddr, htons(mount_port)); | 508 | set_sockaddr(&sin, servaddr, htons(mount_port)); |
| 508 | status = nfs_mount(&request); | 509 | status = nfs_mount(&request); |
| 509 | if (status < 0) | 510 | if (status < 0) |
| 510 | printk(KERN_ERR "Root-NFS: Server returned error %d " | 511 | printk(KERN_ERR "Root-NFS: Server returned error %d " |
| 511 | "while mounting %s\n", status, nfs_export_path); | 512 | "while mounting %s\n", status, nfs_export_path); |
| 512 | else { | 513 | else { |
| 513 | nfs_data.root.size = fh.size; | 514 | nfs_data.root.size = request.fh->size; |
| 514 | memcpy(nfs_data.root.data, fh.data, fh.size); | 515 | memcpy(&nfs_data.root.data, request.fh->data, request.fh->size); |
| 515 | } | 516 | } |
| 516 | 517 | nfs_free_fhandle(request.fh); | |
| 518 | out: | ||
| 517 | return status; | 519 | return status; |
| 518 | } | 520 | } |
| 519 | 521 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 29d9d36cd5f4..a3654e57b589 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -60,16 +60,10 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
| 60 | { | 60 | { |
| 61 | struct nfs_page *req; | 61 | struct nfs_page *req; |
| 62 | 62 | ||
| 63 | for (;;) { | 63 | /* try to allocate the request struct */ |
| 64 | /* try to allocate the request struct */ | 64 | req = nfs_page_alloc(); |
| 65 | req = nfs_page_alloc(); | 65 | if (req == NULL) |
| 66 | if (req != NULL) | 66 | return ERR_PTR(-ENOMEM); |
| 67 | break; | ||
| 68 | |||
| 69 | if (fatal_signal_pending(current)) | ||
| 70 | return ERR_PTR(-ERESTARTSYS); | ||
| 71 | yield(); | ||
| 72 | } | ||
| 73 | 67 | ||
| 74 | /* Initialize the request struct. Initially, we assume a | 68 | /* Initialize the request struct. Initially, we assume a |
| 75 | * long write-back delay. This will be adjusted in | 69 | * long write-back delay. This will be adjusted in |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 0288be80444f..611bec22f552 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
| @@ -224,35 +224,60 @@ static int nfs_proc_readlink(struct inode *inode, struct page *page, | |||
| 224 | return status; | 224 | return status; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | struct nfs_createdata { | ||
| 228 | struct nfs_createargs arg; | ||
| 229 | struct nfs_diropok res; | ||
| 230 | struct nfs_fh fhandle; | ||
| 231 | struct nfs_fattr fattr; | ||
| 232 | }; | ||
| 233 | |||
| 234 | static struct nfs_createdata *nfs_alloc_createdata(struct inode *dir, | ||
| 235 | struct dentry *dentry, struct iattr *sattr) | ||
| 236 | { | ||
| 237 | struct nfs_createdata *data; | ||
| 238 | |||
| 239 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
| 240 | |||
| 241 | if (data != NULL) { | ||
| 242 | data->arg.fh = NFS_FH(dir); | ||
| 243 | data->arg.name = dentry->d_name.name; | ||
| 244 | data->arg.len = dentry->d_name.len; | ||
| 245 | data->arg.sattr = sattr; | ||
| 246 | nfs_fattr_init(&data->fattr); | ||
| 247 | data->fhandle.size = 0; | ||
| 248 | data->res.fh = &data->fhandle; | ||
| 249 | data->res.fattr = &data->fattr; | ||
| 250 | } | ||
| 251 | return data; | ||
| 252 | }; | ||
| 253 | |||
| 254 | static void nfs_free_createdata(const struct nfs_createdata *data) | ||
| 255 | { | ||
| 256 | kfree(data); | ||
| 257 | } | ||
| 258 | |||
| 227 | static int | 259 | static int |
| 228 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 260 | nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
| 229 | int flags, struct nameidata *nd) | 261 | int flags, struct nameidata *nd) |
| 230 | { | 262 | { |
| 231 | struct nfs_fh fhandle; | 263 | struct nfs_createdata *data; |
| 232 | struct nfs_fattr fattr; | ||
| 233 | struct nfs_createargs arg = { | ||
| 234 | .fh = NFS_FH(dir), | ||
| 235 | .name = dentry->d_name.name, | ||
| 236 | .len = dentry->d_name.len, | ||
| 237 | .sattr = sattr | ||
| 238 | }; | ||
| 239 | struct nfs_diropok res = { | ||
| 240 | .fh = &fhandle, | ||
| 241 | .fattr = &fattr | ||
| 242 | }; | ||
| 243 | struct rpc_message msg = { | 264 | struct rpc_message msg = { |
| 244 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | 265 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], |
| 245 | .rpc_argp = &arg, | ||
| 246 | .rpc_resp = &res, | ||
| 247 | }; | 266 | }; |
| 248 | int status; | 267 | int status = -ENOMEM; |
| 249 | 268 | ||
| 250 | nfs_fattr_init(&fattr); | ||
| 251 | dprintk("NFS call create %s\n", dentry->d_name.name); | 269 | dprintk("NFS call create %s\n", dentry->d_name.name); |
| 270 | data = nfs_alloc_createdata(dir, dentry, sattr); | ||
| 271 | if (data == NULL) | ||
| 272 | goto out; | ||
| 273 | msg.rpc_argp = &data->arg; | ||
| 274 | msg.rpc_resp = &data->res; | ||
| 252 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 275 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 253 | nfs_mark_for_revalidate(dir); | 276 | nfs_mark_for_revalidate(dir); |
| 254 | if (status == 0) | 277 | if (status == 0) |
| 255 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 278 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
| 279 | nfs_free_createdata(data); | ||
| 280 | out: | ||
| 256 | dprintk("NFS reply create: %d\n", status); | 281 | dprintk("NFS reply create: %d\n", status); |
| 257 | return status; | 282 | return status; |
| 258 | } | 283 | } |
| @@ -264,24 +289,12 @@ static int | |||
| 264 | nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 289 | nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, |
| 265 | dev_t rdev) | 290 | dev_t rdev) |
| 266 | { | 291 | { |
| 267 | struct nfs_fh fhandle; | 292 | struct nfs_createdata *data; |
| 268 | struct nfs_fattr fattr; | ||
| 269 | struct nfs_createargs arg = { | ||
| 270 | .fh = NFS_FH(dir), | ||
| 271 | .name = dentry->d_name.name, | ||
| 272 | .len = dentry->d_name.len, | ||
| 273 | .sattr = sattr | ||
| 274 | }; | ||
| 275 | struct nfs_diropok res = { | ||
| 276 | .fh = &fhandle, | ||
| 277 | .fattr = &fattr | ||
| 278 | }; | ||
| 279 | struct rpc_message msg = { | 293 | struct rpc_message msg = { |
| 280 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], | 294 | .rpc_proc = &nfs_procedures[NFSPROC_CREATE], |
| 281 | .rpc_argp = &arg, | ||
| 282 | .rpc_resp = &res, | ||
| 283 | }; | 295 | }; |
| 284 | int status, mode; | 296 | umode_t mode; |
| 297 | int status = -ENOMEM; | ||
| 285 | 298 | ||
| 286 | dprintk("NFS call mknod %s\n", dentry->d_name.name); | 299 | dprintk("NFS call mknod %s\n", dentry->d_name.name); |
| 287 | 300 | ||
| @@ -294,17 +307,24 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 294 | sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ | 307 | sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */ |
| 295 | } | 308 | } |
| 296 | 309 | ||
| 297 | nfs_fattr_init(&fattr); | 310 | data = nfs_alloc_createdata(dir, dentry, sattr); |
| 311 | if (data == NULL) | ||
| 312 | goto out; | ||
| 313 | msg.rpc_argp = &data->arg; | ||
| 314 | msg.rpc_resp = &data->res; | ||
| 315 | |||
| 298 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 316 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 299 | nfs_mark_for_revalidate(dir); | 317 | nfs_mark_for_revalidate(dir); |
| 300 | 318 | ||
| 301 | if (status == -EINVAL && S_ISFIFO(mode)) { | 319 | if (status == -EINVAL && S_ISFIFO(mode)) { |
| 302 | sattr->ia_mode = mode; | 320 | sattr->ia_mode = mode; |
| 303 | nfs_fattr_init(&fattr); | 321 | nfs_fattr_init(data->res.fattr); |
| 304 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 322 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 305 | } | 323 | } |
| 306 | if (status == 0) | 324 | if (status == 0) |
| 307 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 325 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
| 326 | nfs_free_createdata(data); | ||
| 327 | out: | ||
| 308 | dprintk("NFS reply mknod: %d\n", status); | 328 | dprintk("NFS reply mknod: %d\n", status); |
| 309 | return status; | 329 | return status; |
| 310 | } | 330 | } |
| @@ -398,8 +418,8 @@ static int | |||
| 398 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | 418 | nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, |
| 399 | unsigned int len, struct iattr *sattr) | 419 | unsigned int len, struct iattr *sattr) |
| 400 | { | 420 | { |
| 401 | struct nfs_fh fhandle; | 421 | struct nfs_fh *fh; |
| 402 | struct nfs_fattr fattr; | 422 | struct nfs_fattr *fattr; |
| 403 | struct nfs_symlinkargs arg = { | 423 | struct nfs_symlinkargs arg = { |
| 404 | .fromfh = NFS_FH(dir), | 424 | .fromfh = NFS_FH(dir), |
| 405 | .fromname = dentry->d_name.name, | 425 | .fromname = dentry->d_name.name, |
| @@ -412,12 +432,18 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
| 412 | .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], | 432 | .rpc_proc = &nfs_procedures[NFSPROC_SYMLINK], |
| 413 | .rpc_argp = &arg, | 433 | .rpc_argp = &arg, |
| 414 | }; | 434 | }; |
| 415 | int status; | 435 | int status = -ENAMETOOLONG; |
| 436 | |||
| 437 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | ||
| 416 | 438 | ||
| 417 | if (len > NFS2_MAXPATHLEN) | 439 | if (len > NFS2_MAXPATHLEN) |
| 418 | return -ENAMETOOLONG; | 440 | goto out; |
| 419 | 441 | ||
| 420 | dprintk("NFS call symlink %s\n", dentry->d_name.name); | 442 | fh = nfs_alloc_fhandle(); |
| 443 | fattr = nfs_alloc_fattr(); | ||
| 444 | status = -ENOMEM; | ||
| 445 | if (fh == NULL || fattr == NULL) | ||
| 446 | goto out; | ||
| 421 | 447 | ||
| 422 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 448 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 423 | nfs_mark_for_revalidate(dir); | 449 | nfs_mark_for_revalidate(dir); |
| @@ -427,12 +453,12 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
| 427 | * filehandle size to zero indicates to nfs_instantiate that it | 453 | * filehandle size to zero indicates to nfs_instantiate that it |
| 428 | * should fill in the data with a LOOKUP call on the wire. | 454 | * should fill in the data with a LOOKUP call on the wire. |
| 429 | */ | 455 | */ |
| 430 | if (status == 0) { | 456 | if (status == 0) |
| 431 | nfs_fattr_init(&fattr); | 457 | status = nfs_instantiate(dentry, fh, fattr); |
| 432 | fhandle.size = 0; | ||
| 433 | status = nfs_instantiate(dentry, &fhandle, &fattr); | ||
| 434 | } | ||
| 435 | 458 | ||
| 459 | nfs_free_fattr(fattr); | ||
| 460 | nfs_free_fhandle(fh); | ||
| 461 | out: | ||
| 436 | dprintk("NFS reply symlink: %d\n", status); | 462 | dprintk("NFS reply symlink: %d\n", status); |
| 437 | return status; | 463 | return status; |
| 438 | } | 464 | } |
| @@ -440,31 +466,25 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, | |||
| 440 | static int | 466 | static int |
| 441 | nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) | 467 | nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) |
| 442 | { | 468 | { |
| 443 | struct nfs_fh fhandle; | 469 | struct nfs_createdata *data; |
| 444 | struct nfs_fattr fattr; | ||
| 445 | struct nfs_createargs arg = { | ||
| 446 | .fh = NFS_FH(dir), | ||
| 447 | .name = dentry->d_name.name, | ||
| 448 | .len = dentry->d_name.len, | ||
| 449 | .sattr = sattr | ||
| 450 | }; | ||
| 451 | struct nfs_diropok res = { | ||
| 452 | .fh = &fhandle, | ||
| 453 | .fattr = &fattr | ||
| 454 | }; | ||
| 455 | struct rpc_message msg = { | 470 | struct rpc_message msg = { |
| 456 | .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], | 471 | .rpc_proc = &nfs_procedures[NFSPROC_MKDIR], |
| 457 | .rpc_argp = &arg, | ||
| 458 | .rpc_resp = &res, | ||
| 459 | }; | 472 | }; |
| 460 | int status; | 473 | int status = -ENOMEM; |
| 461 | 474 | ||
| 462 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); | 475 | dprintk("NFS call mkdir %s\n", dentry->d_name.name); |
| 463 | nfs_fattr_init(&fattr); | 476 | data = nfs_alloc_createdata(dir, dentry, sattr); |
| 477 | if (data == NULL) | ||
| 478 | goto out; | ||
| 479 | msg.rpc_argp = &data->arg; | ||
| 480 | msg.rpc_resp = &data->res; | ||
| 481 | |||
| 464 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 482 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); |
| 465 | nfs_mark_for_revalidate(dir); | 483 | nfs_mark_for_revalidate(dir); |
| 466 | if (status == 0) | 484 | if (status == 0) |
| 467 | status = nfs_instantiate(dentry, &fhandle, &fattr); | 485 | status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); |
| 486 | nfs_free_createdata(data); | ||
| 487 | out: | ||
| 468 | dprintk("NFS reply mkdir: %d\n", status); | 488 | dprintk("NFS reply mkdir: %d\n", status); |
| 469 | return status; | 489 | return status; |
| 470 | } | 490 | } |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index db9b360ae19d..6e2b06e6ca79 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -40,7 +40,7 @@ static mempool_t *nfs_rdata_mempool; | |||
| 40 | 40 | ||
| 41 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | 41 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
| 42 | { | 42 | { |
| 43 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); | 43 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_KERNEL); |
| 44 | 44 | ||
| 45 | if (p) { | 45 | if (p) { |
| 46 | memset(p, 0, sizeof(*p)); | 46 | memset(p, 0, sizeof(*p)); |
| @@ -50,7 +50,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
| 50 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 50 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
| 51 | p->pagevec = p->page_array; | 51 | p->pagevec = p->page_array; |
| 52 | else { | 52 | else { |
| 53 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS); | 53 | p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); |
| 54 | if (!p->pagevec) { | 54 | if (!p->pagevec) { |
| 55 | mempool_free(p, nfs_rdata_mempool); | 55 | mempool_free(p, nfs_rdata_mempool); |
| 56 | p = NULL; | 56 | p = NULL; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b4148fc00f9f..2f8b1157daa2 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -141,7 +141,6 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 141 | { Opt_resvport, "resvport" }, | 141 | { Opt_resvport, "resvport" }, |
| 142 | { Opt_noresvport, "noresvport" }, | 142 | { Opt_noresvport, "noresvport" }, |
| 143 | { Opt_fscache, "fsc" }, | 143 | { Opt_fscache, "fsc" }, |
| 144 | { Opt_fscache_uniq, "fsc=%s" }, | ||
| 145 | { Opt_nofscache, "nofsc" }, | 144 | { Opt_nofscache, "nofsc" }, |
| 146 | 145 | ||
| 147 | { Opt_port, "port=%s" }, | 146 | { Opt_port, "port=%s" }, |
| @@ -171,6 +170,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
| 171 | { Opt_mountaddr, "mountaddr=%s" }, | 170 | { Opt_mountaddr, "mountaddr=%s" }, |
| 172 | 171 | ||
| 173 | { Opt_lookupcache, "lookupcache=%s" }, | 172 | { Opt_lookupcache, "lookupcache=%s" }, |
| 173 | { Opt_fscache_uniq, "fsc=%s" }, | ||
| 174 | 174 | ||
| 175 | { Opt_err, NULL } | 175 | { Opt_err, NULL } |
| 176 | }; | 176 | }; |
| @@ -423,15 +423,19 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 423 | unsigned char blockbits; | 423 | unsigned char blockbits; |
| 424 | unsigned long blockres; | 424 | unsigned long blockres; |
| 425 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); | 425 | struct nfs_fh *fh = NFS_FH(dentry->d_inode); |
| 426 | struct nfs_fattr fattr; | 426 | struct nfs_fsstat res; |
| 427 | struct nfs_fsstat res = { | 427 | int error = -ENOMEM; |
| 428 | .fattr = &fattr, | 428 | |
| 429 | }; | 429 | res.fattr = nfs_alloc_fattr(); |
| 430 | int error; | 430 | if (res.fattr == NULL) |
| 431 | goto out_err; | ||
| 431 | 432 | ||
| 432 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); | 433 | error = server->nfs_client->rpc_ops->statfs(server, fh, &res); |
| 434 | |||
| 435 | nfs_free_fattr(res.fattr); | ||
| 433 | if (error < 0) | 436 | if (error < 0) |
| 434 | goto out_err; | 437 | goto out_err; |
| 438 | |||
| 435 | buf->f_type = NFS_SUPER_MAGIC; | 439 | buf->f_type = NFS_SUPER_MAGIC; |
| 436 | 440 | ||
| 437 | /* | 441 | /* |
| @@ -1046,14 +1050,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1046 | kfree(mnt->fscache_uniq); | 1050 | kfree(mnt->fscache_uniq); |
| 1047 | mnt->fscache_uniq = NULL; | 1051 | mnt->fscache_uniq = NULL; |
| 1048 | break; | 1052 | break; |
| 1049 | case Opt_fscache_uniq: | ||
| 1050 | string = match_strdup(args); | ||
| 1051 | if (!string) | ||
| 1052 | goto out_nomem; | ||
| 1053 | kfree(mnt->fscache_uniq); | ||
| 1054 | mnt->fscache_uniq = string; | ||
| 1055 | mnt->options |= NFS_OPTION_FSCACHE; | ||
| 1056 | break; | ||
| 1057 | 1053 | ||
| 1058 | /* | 1054 | /* |
| 1059 | * options that take numeric values | 1055 | * options that take numeric values |
| @@ -1384,6 +1380,14 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1384 | return 0; | 1380 | return 0; |
| 1385 | }; | 1381 | }; |
| 1386 | break; | 1382 | break; |
| 1383 | case Opt_fscache_uniq: | ||
| 1384 | string = match_strdup(args); | ||
| 1385 | if (string == NULL) | ||
| 1386 | goto out_nomem; | ||
| 1387 | kfree(mnt->fscache_uniq); | ||
| 1388 | mnt->fscache_uniq = string; | ||
| 1389 | mnt->options |= NFS_OPTION_FSCACHE; | ||
| 1390 | break; | ||
| 1387 | 1391 | ||
| 1388 | /* | 1392 | /* |
| 1389 | * Special options | 1393 | * Special options |
| @@ -2172,7 +2176,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2172 | int error = -ENOMEM; | 2176 | int error = -ENOMEM; |
| 2173 | 2177 | ||
| 2174 | data = nfs_alloc_parsed_mount_data(3); | 2178 | data = nfs_alloc_parsed_mount_data(3); |
| 2175 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2179 | mntfh = nfs_alloc_fhandle(); |
| 2176 | if (data == NULL || mntfh == NULL) | 2180 | if (data == NULL || mntfh == NULL) |
| 2177 | goto out_free_fh; | 2181 | goto out_free_fh; |
| 2178 | 2182 | ||
| @@ -2247,7 +2251,7 @@ out: | |||
| 2247 | kfree(data->fscache_uniq); | 2251 | kfree(data->fscache_uniq); |
| 2248 | security_free_mnt_opts(&data->lsm_opts); | 2252 | security_free_mnt_opts(&data->lsm_opts); |
| 2249 | out_free_fh: | 2253 | out_free_fh: |
| 2250 | kfree(mntfh); | 2254 | nfs_free_fhandle(mntfh); |
| 2251 | kfree(data); | 2255 | kfree(data); |
| 2252 | return error; | 2256 | return error; |
| 2253 | 2257 | ||
| @@ -2556,7 +2560,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
| 2556 | }; | 2560 | }; |
| 2557 | int error = -ENOMEM; | 2561 | int error = -ENOMEM; |
| 2558 | 2562 | ||
| 2559 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2563 | mntfh = nfs_alloc_fhandle(); |
| 2560 | if (data == NULL || mntfh == NULL) | 2564 | if (data == NULL || mntfh == NULL) |
| 2561 | goto out_free_fh; | 2565 | goto out_free_fh; |
| 2562 | 2566 | ||
| @@ -2614,7 +2618,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
| 2614 | out: | 2618 | out: |
| 2615 | security_free_mnt_opts(&data->lsm_opts); | 2619 | security_free_mnt_opts(&data->lsm_opts); |
| 2616 | out_free_fh: | 2620 | out_free_fh: |
| 2617 | kfree(mntfh); | 2621 | nfs_free_fhandle(mntfh); |
| 2618 | return error; | 2622 | return error; |
| 2619 | 2623 | ||
| 2620 | out_free: | 2624 | out_free: |
| @@ -2669,41 +2673,120 @@ out_freepage: | |||
| 2669 | free_page((unsigned long)page); | 2673 | free_page((unsigned long)page); |
| 2670 | } | 2674 | } |
| 2671 | 2675 | ||
| 2676 | struct nfs_referral_count { | ||
| 2677 | struct list_head list; | ||
| 2678 | const struct task_struct *task; | ||
| 2679 | unsigned int referral_count; | ||
| 2680 | }; | ||
| 2681 | |||
| 2682 | static LIST_HEAD(nfs_referral_count_list); | ||
| 2683 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
| 2684 | |||
| 2685 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
| 2686 | { | ||
| 2687 | struct nfs_referral_count *p; | ||
| 2688 | |||
| 2689 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
| 2690 | if (p->task == current) | ||
| 2691 | return p; | ||
| 2692 | } | ||
| 2693 | return NULL; | ||
| 2694 | } | ||
| 2695 | |||
| 2696 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
| 2697 | |||
| 2698 | static int nfs_referral_loop_protect(void) | ||
| 2699 | { | ||
| 2700 | struct nfs_referral_count *p, *new; | ||
| 2701 | int ret = -ENOMEM; | ||
| 2702 | |||
| 2703 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
| 2704 | if (!new) | ||
| 2705 | goto out; | ||
| 2706 | new->task = current; | ||
| 2707 | new->referral_count = 1; | ||
| 2708 | |||
| 2709 | ret = 0; | ||
| 2710 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2711 | p = nfs_find_referral_count(); | ||
| 2712 | if (p != NULL) { | ||
| 2713 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
| 2714 | ret = -ELOOP; | ||
| 2715 | else | ||
| 2716 | p->referral_count++; | ||
| 2717 | } else { | ||
| 2718 | list_add(&new->list, &nfs_referral_count_list); | ||
| 2719 | new = NULL; | ||
| 2720 | } | ||
| 2721 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2722 | kfree(new); | ||
| 2723 | out: | ||
| 2724 | return ret; | ||
| 2725 | } | ||
| 2726 | |||
| 2727 | static void nfs_referral_loop_unprotect(void) | ||
| 2728 | { | ||
| 2729 | struct nfs_referral_count *p; | ||
| 2730 | |||
| 2731 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2732 | p = nfs_find_referral_count(); | ||
| 2733 | p->referral_count--; | ||
| 2734 | if (p->referral_count == 0) | ||
| 2735 | list_del(&p->list); | ||
| 2736 | else | ||
| 2737 | p = NULL; | ||
| 2738 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2739 | kfree(p); | ||
| 2740 | } | ||
| 2741 | |||
| 2672 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | 2742 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, |
| 2673 | const char *export_path, struct vfsmount *mnt_target) | 2743 | const char *export_path, struct vfsmount *mnt_target) |
| 2674 | { | 2744 | { |
| 2745 | struct nameidata *nd = NULL; | ||
| 2675 | struct mnt_namespace *ns_private; | 2746 | struct mnt_namespace *ns_private; |
| 2676 | struct nameidata nd; | ||
| 2677 | struct super_block *s; | 2747 | struct super_block *s; |
| 2678 | int ret; | 2748 | int ret; |
| 2679 | 2749 | ||
| 2750 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | ||
| 2751 | if (nd == NULL) | ||
| 2752 | return -ENOMEM; | ||
| 2753 | |||
| 2680 | ns_private = create_mnt_ns(root_mnt); | 2754 | ns_private = create_mnt_ns(root_mnt); |
| 2681 | ret = PTR_ERR(ns_private); | 2755 | ret = PTR_ERR(ns_private); |
| 2682 | if (IS_ERR(ns_private)) | 2756 | if (IS_ERR(ns_private)) |
| 2683 | goto out_mntput; | 2757 | goto out_mntput; |
| 2684 | 2758 | ||
| 2759 | ret = nfs_referral_loop_protect(); | ||
| 2760 | if (ret != 0) | ||
| 2761 | goto out_put_mnt_ns; | ||
| 2762 | |||
| 2685 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | 2763 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, |
| 2686 | export_path, LOOKUP_FOLLOW, &nd); | 2764 | export_path, LOOKUP_FOLLOW, nd); |
| 2687 | 2765 | ||
| 2766 | nfs_referral_loop_unprotect(); | ||
| 2688 | put_mnt_ns(ns_private); | 2767 | put_mnt_ns(ns_private); |
| 2689 | 2768 | ||
| 2690 | if (ret != 0) | 2769 | if (ret != 0) |
| 2691 | goto out_err; | 2770 | goto out_err; |
| 2692 | 2771 | ||
| 2693 | s = nd.path.mnt->mnt_sb; | 2772 | s = nd->path.mnt->mnt_sb; |
| 2694 | atomic_inc(&s->s_active); | 2773 | atomic_inc(&s->s_active); |
| 2695 | mnt_target->mnt_sb = s; | 2774 | mnt_target->mnt_sb = s; |
| 2696 | mnt_target->mnt_root = dget(nd.path.dentry); | 2775 | mnt_target->mnt_root = dget(nd->path.dentry); |
| 2697 | 2776 | ||
| 2698 | /* Correct the device pathname */ | 2777 | /* Correct the device pathname */ |
| 2699 | nfs_fix_devname(&nd.path, mnt_target); | 2778 | nfs_fix_devname(&nd->path, mnt_target); |
| 2700 | 2779 | ||
| 2701 | path_put(&nd.path); | 2780 | path_put(&nd->path); |
| 2781 | kfree(nd); | ||
| 2702 | down_write(&s->s_umount); | 2782 | down_write(&s->s_umount); |
| 2703 | return 0; | 2783 | return 0; |
| 2784 | out_put_mnt_ns: | ||
| 2785 | put_mnt_ns(ns_private); | ||
| 2704 | out_mntput: | 2786 | out_mntput: |
| 2705 | mntput(root_mnt); | 2787 | mntput(root_mnt); |
| 2706 | out_err: | 2788 | out_err: |
| 2789 | kfree(nd); | ||
| 2707 | return ret; | 2790 | return ret; |
| 2708 | } | 2791 | } |
| 2709 | 2792 | ||
| @@ -2874,17 +2957,21 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2874 | struct super_block *s; | 2957 | struct super_block *s; |
| 2875 | struct nfs_server *server; | 2958 | struct nfs_server *server; |
| 2876 | struct dentry *mntroot; | 2959 | struct dentry *mntroot; |
| 2877 | struct nfs_fh mntfh; | 2960 | struct nfs_fh *mntfh; |
| 2878 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2961 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
| 2879 | struct nfs_sb_mountdata sb_mntdata = { | 2962 | struct nfs_sb_mountdata sb_mntdata = { |
| 2880 | .mntflags = flags, | 2963 | .mntflags = flags, |
| 2881 | }; | 2964 | }; |
| 2882 | int error; | 2965 | int error = -ENOMEM; |
| 2883 | 2966 | ||
| 2884 | dprintk("--> nfs4_referral_get_sb()\n"); | 2967 | dprintk("--> nfs4_referral_get_sb()\n"); |
| 2885 | 2968 | ||
| 2969 | mntfh = nfs_alloc_fhandle(); | ||
| 2970 | if (mntfh == NULL) | ||
| 2971 | goto out_err_nofh; | ||
| 2972 | |||
| 2886 | /* create a new volume representation */ | 2973 | /* create a new volume representation */ |
| 2887 | server = nfs4_create_referral_server(data, &mntfh); | 2974 | server = nfs4_create_referral_server(data, mntfh); |
| 2888 | if (IS_ERR(server)) { | 2975 | if (IS_ERR(server)) { |
| 2889 | error = PTR_ERR(server); | 2976 | error = PTR_ERR(server); |
| 2890 | goto out_err_noserver; | 2977 | goto out_err_noserver; |
| @@ -2916,7 +3003,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2916 | nfs_fscache_get_super_cookie(s, NULL, data); | 3003 | nfs_fscache_get_super_cookie(s, NULL, data); |
| 2917 | } | 3004 | } |
| 2918 | 3005 | ||
| 2919 | mntroot = nfs4_get_root(s, &mntfh); | 3006 | mntroot = nfs4_get_root(s, mntfh); |
| 2920 | if (IS_ERR(mntroot)) { | 3007 | if (IS_ERR(mntroot)) { |
| 2921 | error = PTR_ERR(mntroot); | 3008 | error = PTR_ERR(mntroot); |
| 2922 | goto error_splat_super; | 3009 | goto error_splat_super; |
| @@ -2933,12 +3020,15 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2933 | 3020 | ||
| 2934 | security_sb_clone_mnt_opts(data->sb, s); | 3021 | security_sb_clone_mnt_opts(data->sb, s); |
| 2935 | 3022 | ||
| 3023 | nfs_free_fhandle(mntfh); | ||
| 2936 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); | 3024 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
| 2937 | return 0; | 3025 | return 0; |
| 2938 | 3026 | ||
| 2939 | out_err_nosb: | 3027 | out_err_nosb: |
| 2940 | nfs_free_server(server); | 3028 | nfs_free_server(server); |
| 2941 | out_err_noserver: | 3029 | out_err_noserver: |
| 3030 | nfs_free_fhandle(mntfh); | ||
| 3031 | out_err_nofh: | ||
| 2942 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | 3032 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); |
| 2943 | return error; | 3033 | return error; |
| 2944 | 3034 | ||
| @@ -2947,6 +3037,7 @@ error_splat_super: | |||
| 2947 | bdi_unregister(&server->backing_dev_info); | 3037 | bdi_unregister(&server->backing_dev_info); |
| 2948 | error_splat_bdi: | 3038 | error_splat_bdi: |
| 2949 | deactivate_locked_super(s); | 3039 | deactivate_locked_super(s); |
| 3040 | nfs_free_fhandle(mntfh); | ||
| 2950 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | 3041 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); |
| 2951 | return error; | 3042 | return error; |
| 2952 | } | 3043 | } |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 6da3d3ff6edd..a2242af6a17d 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -23,6 +23,7 @@ struct nfs_unlinkdata { | |||
| 23 | struct nfs_removeres res; | 23 | struct nfs_removeres res; |
| 24 | struct inode *dir; | 24 | struct inode *dir; |
| 25 | struct rpc_cred *cred; | 25 | struct rpc_cred *cred; |
| 26 | struct nfs_fattr dir_attr; | ||
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 28 | /** | 29 | /** |
| @@ -169,7 +170,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
| 169 | } | 170 | } |
| 170 | nfs_sb_active(dir->i_sb); | 171 | nfs_sb_active(dir->i_sb); |
| 171 | data->args.fh = NFS_FH(dir); | 172 | data->args.fh = NFS_FH(dir); |
| 172 | nfs_fattr_init(&data->res.dir_attr); | 173 | nfs_fattr_init(data->res.dir_attr); |
| 173 | 174 | ||
| 174 | NFS_PROTO(dir)->unlink_setup(&msg, dir); | 175 | NFS_PROTO(dir)->unlink_setup(&msg, dir); |
| 175 | 176 | ||
| @@ -259,6 +260,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
| 259 | goto out_free; | 260 | goto out_free; |
| 260 | } | 261 | } |
| 261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 262 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 263 | data->res.dir_attr = &data->dir_attr; | ||
| 262 | 264 | ||
| 263 | status = -EBUSY; | 265 | status = -EBUSY; |
| 264 | spin_lock(&dentry->d_lock); | 266 | spin_lock(&dentry->d_lock); |
diff --git a/include/linux/ktime.h b/include/linux/ktime.h index ce5983225be4..e1ceaa9b36bb 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h | |||
| @@ -130,7 +130,7 @@ static inline ktime_t timeval_to_ktime(struct timeval tv) | |||
| 130 | /* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */ | 130 | /* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */ |
| 131 | #define ktime_to_ns(kt) ((kt).tv64) | 131 | #define ktime_to_ns(kt) ((kt).tv64) |
| 132 | 132 | ||
| 133 | #else | 133 | #else /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */ |
| 134 | 134 | ||
| 135 | /* | 135 | /* |
| 136 | * Helper macros/inlines to get the ktime_t math right in the timespec | 136 | * Helper macros/inlines to get the ktime_t math right in the timespec |
| @@ -275,7 +275,7 @@ static inline s64 ktime_to_ns(const ktime_t kt) | |||
| 275 | return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec; | 275 | return (s64) kt.tv.sec * NSEC_PER_SEC + kt.tv.nsec; |
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | #endif | 278 | #endif /* !((BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR)) */ |
| 279 | 279 | ||
| 280 | /** | 280 | /** |
| 281 | * ktime_equal - Compares two ktime_t variables to see if they are equal | 281 | * ktime_equal - Compares two ktime_t variables to see if they are equal |
| @@ -295,6 +295,12 @@ static inline s64 ktime_to_us(const ktime_t kt) | |||
| 295 | return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; | 295 | return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | static inline s64 ktime_to_ms(const ktime_t kt) | ||
| 299 | { | ||
| 300 | struct timeval tv = ktime_to_timeval(kt); | ||
| 301 | return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; | ||
| 302 | } | ||
| 303 | |||
| 298 | static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) | 304 | static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) |
| 299 | { | 305 | { |
| 300 | return ktime_to_us(ktime_sub(later, earlier)); | 306 | return ktime_to_us(ktime_sub(later, earlier)); |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 07ce4609fe50..77c2ae53431c 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -356,6 +356,20 @@ extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struc | |||
| 356 | extern u64 nfs_compat_user_ino64(u64 fileid); | 356 | extern u64 nfs_compat_user_ino64(u64 fileid); |
| 357 | extern void nfs_fattr_init(struct nfs_fattr *fattr); | 357 | extern void nfs_fattr_init(struct nfs_fattr *fattr); |
| 358 | 358 | ||
| 359 | extern struct nfs_fattr *nfs_alloc_fattr(void); | ||
| 360 | |||
| 361 | static inline void nfs_free_fattr(const struct nfs_fattr *fattr) | ||
| 362 | { | ||
| 363 | kfree(fattr); | ||
| 364 | } | ||
| 365 | |||
| 366 | extern struct nfs_fh *nfs_alloc_fhandle(void); | ||
| 367 | |||
| 368 | static inline void nfs_free_fhandle(const struct nfs_fh *fh) | ||
| 369 | { | ||
| 370 | kfree(fh); | ||
| 371 | } | ||
| 372 | |||
| 359 | /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ | 373 | /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ |
| 360 | extern __be32 root_nfs_parse_addr(char *name); /*__init*/ | 374 | extern __be32 root_nfs_parse_addr(char *name); /*__init*/ |
| 361 | extern unsigned long nfs_inc_attr_generation_counter(void); | 375 | extern unsigned long nfs_inc_attr_generation_counter(void); |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index e82957acea56..d6e10a4c06e5 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -44,7 +44,6 @@ struct nfs_client { | |||
| 44 | 44 | ||
| 45 | #ifdef CONFIG_NFS_V4 | 45 | #ifdef CONFIG_NFS_V4 |
| 46 | u64 cl_clientid; /* constant */ | 46 | u64 cl_clientid; /* constant */ |
| 47 | nfs4_verifier cl_confirm; | ||
| 48 | unsigned long cl_state; | 47 | unsigned long cl_state; |
| 49 | 48 | ||
| 50 | struct rb_root cl_openowner_id; | 49 | struct rb_root cl_openowner_id; |
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 89b28812ec24..51914d7d6cc4 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -386,8 +386,8 @@ struct nfs_removeargs { | |||
| 386 | 386 | ||
| 387 | struct nfs_removeres { | 387 | struct nfs_removeres { |
| 388 | const struct nfs_server *server; | 388 | const struct nfs_server *server; |
| 389 | struct nfs_fattr *dir_attr; | ||
| 389 | struct nfs4_change_info cinfo; | 390 | struct nfs4_change_info cinfo; |
| 390 | struct nfs_fattr dir_attr; | ||
| 391 | struct nfs4_sequence_res seq_res; | 391 | struct nfs4_sequence_res seq_res; |
| 392 | }; | 392 | }; |
| 393 | 393 | ||
| @@ -824,6 +824,11 @@ struct nfs4_setclientid { | |||
| 824 | u32 sc_cb_ident; | 824 | u32 sc_cb_ident; |
| 825 | }; | 825 | }; |
| 826 | 826 | ||
| 827 | struct nfs4_setclientid_res { | ||
| 828 | u64 clientid; | ||
| 829 | nfs4_verifier confirm; | ||
| 830 | }; | ||
| 831 | |||
| 827 | struct nfs4_statfs_arg { | 832 | struct nfs4_statfs_arg { |
| 828 | const struct nfs_fh * fh; | 833 | const struct nfs_fh * fh; |
| 829 | const u32 * bitmask; | 834 | const u32 * bitmask; |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 996df4dac7d4..87d7ec0bf779 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
| @@ -54,6 +54,7 @@ struct rpc_cred { | |||
| 54 | #define RPCAUTH_CRED_NEW 0 | 54 | #define RPCAUTH_CRED_NEW 0 |
| 55 | #define RPCAUTH_CRED_UPTODATE 1 | 55 | #define RPCAUTH_CRED_UPTODATE 1 |
| 56 | #define RPCAUTH_CRED_HASHED 2 | 56 | #define RPCAUTH_CRED_HASHED 2 |
| 57 | #define RPCAUTH_CRED_NEGATIVE 3 | ||
| 57 | 58 | ||
| 58 | #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 | 59 | #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 |
| 59 | 60 | ||
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index d48d4e605f74..671538d25bc1 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h | |||
| @@ -82,6 +82,7 @@ struct gss_cred { | |||
| 82 | enum rpc_gss_svc gc_service; | 82 | enum rpc_gss_svc gc_service; |
| 83 | struct gss_cl_ctx *gc_ctx; | 83 | struct gss_cl_ctx *gc_ctx; |
| 84 | struct gss_upcall_msg *gc_upcall; | 84 | struct gss_upcall_msg *gc_upcall; |
| 85 | unsigned long gc_upcall_timestamp; | ||
| 85 | unsigned char gc_machine_cred : 1; | 86 | unsigned char gc_machine_cred : 1; |
| 86 | }; | 87 | }; |
| 87 | 88 | ||
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 03f33330ece2..5d8048beb051 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h | |||
| @@ -35,7 +35,8 @@ int gss_import_sec_context( | |||
| 35 | const void* input_token, | 35 | const void* input_token, |
| 36 | size_t bufsize, | 36 | size_t bufsize, |
| 37 | struct gss_api_mech *mech, | 37 | struct gss_api_mech *mech, |
| 38 | struct gss_ctx **ctx_id); | 38 | struct gss_ctx **ctx_id, |
| 39 | gfp_t gfp_mask); | ||
| 39 | u32 gss_get_mic( | 40 | u32 gss_get_mic( |
| 40 | struct gss_ctx *ctx_id, | 41 | struct gss_ctx *ctx_id, |
| 41 | struct xdr_buf *message, | 42 | struct xdr_buf *message, |
| @@ -80,6 +81,8 @@ struct gss_api_mech { | |||
| 80 | /* pseudoflavors supported by this mechanism: */ | 81 | /* pseudoflavors supported by this mechanism: */ |
| 81 | int gm_pf_num; | 82 | int gm_pf_num; |
| 82 | struct pf_desc * gm_pfs; | 83 | struct pf_desc * gm_pfs; |
| 84 | /* Should the following be a callback operation instead? */ | ||
| 85 | const char *gm_upcall_enctypes; | ||
| 83 | }; | 86 | }; |
| 84 | 87 | ||
| 85 | /* and must provide the following operations: */ | 88 | /* and must provide the following operations: */ |
| @@ -87,7 +90,8 @@ struct gss_api_ops { | |||
| 87 | int (*gss_import_sec_context)( | 90 | int (*gss_import_sec_context)( |
| 88 | const void *input_token, | 91 | const void *input_token, |
| 89 | size_t bufsize, | 92 | size_t bufsize, |
| 90 | struct gss_ctx *ctx_id); | 93 | struct gss_ctx *ctx_id, |
| 94 | gfp_t gfp_mask); | ||
| 91 | u32 (*gss_get_mic)( | 95 | u32 (*gss_get_mic)( |
| 92 | struct gss_ctx *ctx_id, | 96 | struct gss_ctx *ctx_id, |
| 93 | struct xdr_buf *message, | 97 | struct xdr_buf *message, |
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index e7bbdba474d5..5af2931cf58d 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h, | 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/include/krb5.h, |
| 5 | * lib/gssapi/krb5/gssapiP_krb5.h, and others | 5 | * lib/gssapi/krb5/gssapiP_krb5.h, and others |
| 6 | * | 6 | * |
| 7 | * Copyright (c) 2000 The Regents of the University of Michigan. | 7 | * Copyright (c) 2000-2008 The Regents of the University of Michigan. |
| 8 | * All rights reserved. | 8 | * All rights reserved. |
| 9 | * | 9 | * |
| 10 | * Andy Adamson <andros@umich.edu> | 10 | * Andy Adamson <andros@umich.edu> |
| @@ -36,17 +36,86 @@ | |||
| 36 | * | 36 | * |
| 37 | */ | 37 | */ |
| 38 | 38 | ||
| 39 | #include <linux/crypto.h> | ||
| 39 | #include <linux/sunrpc/auth_gss.h> | 40 | #include <linux/sunrpc/auth_gss.h> |
| 40 | #include <linux/sunrpc/gss_err.h> | 41 | #include <linux/sunrpc/gss_err.h> |
| 41 | #include <linux/sunrpc/gss_asn1.h> | 42 | #include <linux/sunrpc/gss_asn1.h> |
| 42 | 43 | ||
| 44 | /* Length of constant used in key derivation */ | ||
| 45 | #define GSS_KRB5_K5CLENGTH (5) | ||
| 46 | |||
| 47 | /* Maximum key length (in bytes) for the supported crypto algorithms*/ | ||
| 48 | #define GSS_KRB5_MAX_KEYLEN (32) | ||
| 49 | |||
| 50 | /* Maximum checksum function output for the supported crypto algorithms */ | ||
| 51 | #define GSS_KRB5_MAX_CKSUM_LEN (20) | ||
| 52 | |||
| 53 | /* Maximum blocksize for the supported crypto algorithms */ | ||
| 54 | #define GSS_KRB5_MAX_BLOCKSIZE (16) | ||
| 55 | |||
| 56 | struct krb5_ctx; | ||
| 57 | |||
| 58 | struct gss_krb5_enctype { | ||
| 59 | const u32 etype; /* encryption (key) type */ | ||
| 60 | const u32 ctype; /* checksum type */ | ||
| 61 | const char *name; /* "friendly" name */ | ||
| 62 | const char *encrypt_name; /* crypto encrypt name */ | ||
| 63 | const char *cksum_name; /* crypto checksum name */ | ||
| 64 | const u16 signalg; /* signing algorithm */ | ||
| 65 | const u16 sealalg; /* sealing algorithm */ | ||
| 66 | const u32 blocksize; /* encryption blocksize */ | ||
| 67 | const u32 conflen; /* confounder length | ||
| 68 | (normally the same as | ||
| 69 | the blocksize) */ | ||
| 70 | const u32 cksumlength; /* checksum length */ | ||
| 71 | const u32 keyed_cksum; /* is it a keyed cksum? */ | ||
| 72 | const u32 keybytes; /* raw key len, in bytes */ | ||
| 73 | const u32 keylength; /* final key len, in bytes */ | ||
| 74 | u32 (*encrypt) (struct crypto_blkcipher *tfm, | ||
| 75 | void *iv, void *in, void *out, | ||
| 76 | int length); /* encryption function */ | ||
| 77 | u32 (*decrypt) (struct crypto_blkcipher *tfm, | ||
| 78 | void *iv, void *in, void *out, | ||
| 79 | int length); /* decryption function */ | ||
| 80 | u32 (*mk_key) (const struct gss_krb5_enctype *gk5e, | ||
| 81 | struct xdr_netobj *in, | ||
| 82 | struct xdr_netobj *out); /* complete key generation */ | ||
| 83 | u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset, | ||
| 84 | struct xdr_buf *buf, int ec, | ||
| 85 | struct page **pages); /* v2 encryption function */ | ||
| 86 | u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, | ||
| 87 | struct xdr_buf *buf, u32 *headskip, | ||
| 88 | u32 *tailskip); /* v2 decryption function */ | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* krb5_ctx flags definitions */ | ||
| 92 | #define KRB5_CTX_FLAG_INITIATOR 0x00000001 | ||
| 93 | #define KRB5_CTX_FLAG_CFX 0x00000002 | ||
| 94 | #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004 | ||
| 95 | |||
| 43 | struct krb5_ctx { | 96 | struct krb5_ctx { |
| 44 | int initiate; /* 1 = initiating, 0 = accepting */ | 97 | int initiate; /* 1 = initiating, 0 = accepting */ |
| 98 | u32 enctype; | ||
| 99 | u32 flags; | ||
| 100 | const struct gss_krb5_enctype *gk5e; /* enctype-specific info */ | ||
| 45 | struct crypto_blkcipher *enc; | 101 | struct crypto_blkcipher *enc; |
| 46 | struct crypto_blkcipher *seq; | 102 | struct crypto_blkcipher *seq; |
| 103 | struct crypto_blkcipher *acceptor_enc; | ||
| 104 | struct crypto_blkcipher *initiator_enc; | ||
| 105 | struct crypto_blkcipher *acceptor_enc_aux; | ||
| 106 | struct crypto_blkcipher *initiator_enc_aux; | ||
| 107 | u8 Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */ | ||
| 108 | u8 cksum[GSS_KRB5_MAX_KEYLEN]; | ||
| 47 | s32 endtime; | 109 | s32 endtime; |
| 48 | u32 seq_send; | 110 | u32 seq_send; |
| 111 | u64 seq_send64; | ||
| 49 | struct xdr_netobj mech_used; | 112 | struct xdr_netobj mech_used; |
| 113 | u8 initiator_sign[GSS_KRB5_MAX_KEYLEN]; | ||
| 114 | u8 acceptor_sign[GSS_KRB5_MAX_KEYLEN]; | ||
| 115 | u8 initiator_seal[GSS_KRB5_MAX_KEYLEN]; | ||
| 116 | u8 acceptor_seal[GSS_KRB5_MAX_KEYLEN]; | ||
| 117 | u8 initiator_integ[GSS_KRB5_MAX_KEYLEN]; | ||
| 118 | u8 acceptor_integ[GSS_KRB5_MAX_KEYLEN]; | ||
| 50 | }; | 119 | }; |
| 51 | 120 | ||
| 52 | extern spinlock_t krb5_seq_lock; | 121 | extern spinlock_t krb5_seq_lock; |
| @@ -57,6 +126,18 @@ extern spinlock_t krb5_seq_lock; | |||
| 57 | #define KG_TOK_MIC_MSG 0x0101 | 126 | #define KG_TOK_MIC_MSG 0x0101 |
| 58 | #define KG_TOK_WRAP_MSG 0x0201 | 127 | #define KG_TOK_WRAP_MSG 0x0201 |
| 59 | 128 | ||
| 129 | #define KG2_TOK_INITIAL 0x0101 | ||
| 130 | #define KG2_TOK_RESPONSE 0x0202 | ||
| 131 | #define KG2_TOK_MIC 0x0404 | ||
| 132 | #define KG2_TOK_WRAP 0x0504 | ||
| 133 | |||
| 134 | #define KG2_TOKEN_FLAG_SENTBYACCEPTOR 0x01 | ||
| 135 | #define KG2_TOKEN_FLAG_SEALED 0x02 | ||
| 136 | #define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04 | ||
| 137 | |||
| 138 | #define KG2_RESP_FLAG_ERROR 0x0001 | ||
| 139 | #define KG2_RESP_FLAG_DELEG_OK 0x0002 | ||
| 140 | |||
| 60 | enum sgn_alg { | 141 | enum sgn_alg { |
| 61 | SGN_ALG_DES_MAC_MD5 = 0x0000, | 142 | SGN_ALG_DES_MAC_MD5 = 0x0000, |
| 62 | SGN_ALG_MD2_5 = 0x0001, | 143 | SGN_ALG_MD2_5 = 0x0001, |
| @@ -81,6 +162,9 @@ enum seal_alg { | |||
| 81 | #define CKSUMTYPE_RSA_MD5_DES 0x0008 | 162 | #define CKSUMTYPE_RSA_MD5_DES 0x0008 |
| 82 | #define CKSUMTYPE_NIST_SHA 0x0009 | 163 | #define CKSUMTYPE_NIST_SHA 0x0009 |
| 83 | #define CKSUMTYPE_HMAC_SHA1_DES3 0x000c | 164 | #define CKSUMTYPE_HMAC_SHA1_DES3 0x000c |
| 165 | #define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f | ||
| 166 | #define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010 | ||
| 167 | #define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */ | ||
| 84 | 168 | ||
| 85 | /* from gssapi_err_krb5.h */ | 169 | /* from gssapi_err_krb5.h */ |
| 86 | #define KG_CCACHE_NOMATCH (39756032L) | 170 | #define KG_CCACHE_NOMATCH (39756032L) |
| @@ -111,11 +195,56 @@ enum seal_alg { | |||
| 111 | #define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ | 195 | #define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */ |
| 112 | #define ENCTYPE_DES_HMAC_SHA1 0x0008 | 196 | #define ENCTYPE_DES_HMAC_SHA1 0x0008 |
| 113 | #define ENCTYPE_DES3_CBC_SHA1 0x0010 | 197 | #define ENCTYPE_DES3_CBC_SHA1 0x0010 |
| 198 | #define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011 | ||
| 199 | #define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012 | ||
| 200 | #define ENCTYPE_ARCFOUR_HMAC 0x0017 | ||
| 201 | #define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018 | ||
| 114 | #define ENCTYPE_UNKNOWN 0x01ff | 202 | #define ENCTYPE_UNKNOWN 0x01ff |
| 115 | 203 | ||
| 116 | s32 | 204 | /* |
| 117 | make_checksum(char *, char *header, int hdrlen, struct xdr_buf *body, | 205 | * Constants used for key derivation |
| 118 | int body_offset, struct xdr_netobj *cksum); | 206 | */ |
| 207 | /* for 3DES */ | ||
| 208 | #define KG_USAGE_SEAL (22) | ||
| 209 | #define KG_USAGE_SIGN (23) | ||
| 210 | #define KG_USAGE_SEQ (24) | ||
| 211 | |||
| 212 | /* from rfc3961 */ | ||
| 213 | #define KEY_USAGE_SEED_CHECKSUM (0x99) | ||
| 214 | #define KEY_USAGE_SEED_ENCRYPTION (0xAA) | ||
| 215 | #define KEY_USAGE_SEED_INTEGRITY (0x55) | ||
| 216 | |||
| 217 | /* from rfc4121 */ | ||
| 218 | #define KG_USAGE_ACCEPTOR_SEAL (22) | ||
| 219 | #define KG_USAGE_ACCEPTOR_SIGN (23) | ||
| 220 | #define KG_USAGE_INITIATOR_SEAL (24) | ||
| 221 | #define KG_USAGE_INITIATOR_SIGN (25) | ||
| 222 | |||
| 223 | /* | ||
| 224 | * This compile-time check verifies that we will not exceed the | ||
| 225 | * slack space allotted by the client and server auth_gss code | ||
| 226 | * before they call gss_wrap(). | ||
| 227 | */ | ||
| 228 | #define GSS_KRB5_MAX_SLACK_NEEDED \ | ||
| 229 | (GSS_KRB5_TOK_HDR_LEN /* gss token header */ \ | ||
| 230 | + GSS_KRB5_MAX_CKSUM_LEN /* gss token checksum */ \ | ||
| 231 | + GSS_KRB5_MAX_BLOCKSIZE /* confounder */ \ | ||
| 232 | + GSS_KRB5_MAX_BLOCKSIZE /* possible padding */ \ | ||
| 233 | + GSS_KRB5_TOK_HDR_LEN /* encrypted hdr in v2 token */\ | ||
| 234 | + GSS_KRB5_MAX_CKSUM_LEN /* encryption hmac */ \ | ||
| 235 | + 4 + 4 /* RPC verifier */ \ | ||
| 236 | + GSS_KRB5_TOK_HDR_LEN \ | ||
| 237 | + GSS_KRB5_MAX_CKSUM_LEN) | ||
| 238 | |||
| 239 | u32 | ||
| 240 | make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
| 241 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
| 242 | unsigned int usage, struct xdr_netobj *cksumout); | ||
| 243 | |||
| 244 | u32 | ||
| 245 | make_checksum_v2(struct krb5_ctx *, char *header, int hdrlen, | ||
| 246 | struct xdr_buf *body, int body_offset, u8 *key, | ||
| 247 | unsigned int usage, struct xdr_netobj *cksum); | ||
| 119 | 248 | ||
| 120 | u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, | 249 | u32 gss_get_mic_kerberos(struct gss_ctx *, struct xdr_buf *, |
| 121 | struct xdr_netobj *); | 250 | struct xdr_netobj *); |
| @@ -149,11 +278,54 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *inbuf, | |||
| 149 | int offset); | 278 | int offset); |
| 150 | 279 | ||
| 151 | s32 | 280 | s32 |
| 152 | krb5_make_seq_num(struct crypto_blkcipher *key, | 281 | krb5_make_seq_num(struct krb5_ctx *kctx, |
| 282 | struct crypto_blkcipher *key, | ||
| 153 | int direction, | 283 | int direction, |
| 154 | u32 seqnum, unsigned char *cksum, unsigned char *buf); | 284 | u32 seqnum, unsigned char *cksum, unsigned char *buf); |
| 155 | 285 | ||
| 156 | s32 | 286 | s32 |
| 157 | krb5_get_seq_num(struct crypto_blkcipher *key, | 287 | krb5_get_seq_num(struct krb5_ctx *kctx, |
| 158 | unsigned char *cksum, | 288 | unsigned char *cksum, |
| 159 | unsigned char *buf, int *direction, u32 *seqnum); | 289 | unsigned char *buf, int *direction, u32 *seqnum); |
| 290 | |||
| 291 | int | ||
| 292 | xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen); | ||
| 293 | |||
| 294 | u32 | ||
| 295 | krb5_derive_key(const struct gss_krb5_enctype *gk5e, | ||
| 296 | const struct xdr_netobj *inkey, | ||
| 297 | struct xdr_netobj *outkey, | ||
| 298 | const struct xdr_netobj *in_constant, | ||
| 299 | gfp_t gfp_mask); | ||
| 300 | |||
| 301 | u32 | ||
| 302 | gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, | ||
| 303 | struct xdr_netobj *randombits, | ||
| 304 | struct xdr_netobj *key); | ||
| 305 | |||
| 306 | u32 | ||
| 307 | gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | ||
| 308 | struct xdr_netobj *randombits, | ||
| 309 | struct xdr_netobj *key); | ||
| 310 | |||
| 311 | u32 | ||
| 312 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | ||
| 313 | struct xdr_buf *buf, int ec, | ||
| 314 | struct page **pages); | ||
| 315 | |||
| 316 | u32 | ||
| 317 | gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, | ||
| 318 | struct xdr_buf *buf, u32 *plainoffset, | ||
| 319 | u32 *plainlen); | ||
| 320 | |||
| 321 | int | ||
| 322 | krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, | ||
| 323 | struct crypto_blkcipher *cipher, | ||
| 324 | unsigned char *cksum); | ||
| 325 | |||
| 326 | int | ||
| 327 | krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, | ||
| 328 | struct crypto_blkcipher *cipher, | ||
| 329 | s32 seqnum); | ||
| 330 | void | ||
| 331 | gss_krb5_make_confounder(char *p, u32 conflen); | ||
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h index 77f78e56c481..b6edbc0ea83d 100644 --- a/include/linux/sunrpc/metrics.h +++ b/include/linux/sunrpc/metrics.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #define _LINUX_SUNRPC_METRICS_H | 26 | #define _LINUX_SUNRPC_METRICS_H |
| 27 | 27 | ||
| 28 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
| 29 | #include <linux/ktime.h> | ||
| 29 | 30 | ||
| 30 | #define RPC_IOSTATS_VERS "1.0" | 31 | #define RPC_IOSTATS_VERS "1.0" |
| 31 | 32 | ||
| @@ -58,9 +59,9 @@ struct rpc_iostats { | |||
| 58 | * and the total time the request spent from init to release | 59 | * and the total time the request spent from init to release |
| 59 | * are measured. | 60 | * are measured. |
| 60 | */ | 61 | */ |
| 61 | unsigned long long om_queue, /* jiffies queued for xmit */ | 62 | ktime_t om_queue, /* queued for xmit */ |
| 62 | om_rtt, /* jiffies for RPC RTT */ | 63 | om_rtt, /* RPC RTT */ |
| 63 | om_execute; /* jiffies for RPC execution */ | 64 | om_execute; /* RPC execution */ |
| 64 | } ____cacheline_aligned; | 65 | } ____cacheline_aligned; |
| 65 | 66 | ||
| 66 | struct rpc_task; | 67 | struct rpc_task; |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 7bc7fd5291ce..7be4f3a6d246 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #define _LINUX_SUNRPC_SCHED_H_ | 10 | #define _LINUX_SUNRPC_SCHED_H_ |
| 11 | 11 | ||
| 12 | #include <linux/timer.h> | 12 | #include <linux/timer.h> |
| 13 | #include <linux/ktime.h> | ||
| 13 | #include <linux/sunrpc/types.h> | 14 | #include <linux/sunrpc/types.h> |
| 14 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| 15 | #include <linux/wait.h> | 16 | #include <linux/wait.h> |
| @@ -40,21 +41,15 @@ struct rpc_wait { | |||
| 40 | * This is the RPC task struct | 41 | * This is the RPC task struct |
| 41 | */ | 42 | */ |
| 42 | struct rpc_task { | 43 | struct rpc_task { |
| 43 | #ifdef RPC_DEBUG | ||
| 44 | unsigned long tk_magic; /* 0xf00baa */ | ||
| 45 | #endif | ||
| 46 | atomic_t tk_count; /* Reference count */ | 44 | atomic_t tk_count; /* Reference count */ |
| 47 | struct list_head tk_task; /* global list of tasks */ | 45 | struct list_head tk_task; /* global list of tasks */ |
| 48 | struct rpc_clnt * tk_client; /* RPC client */ | 46 | struct rpc_clnt * tk_client; /* RPC client */ |
| 49 | struct rpc_rqst * tk_rqstp; /* RPC request */ | 47 | struct rpc_rqst * tk_rqstp; /* RPC request */ |
| 50 | int tk_status; /* result of last operation */ | ||
| 51 | 48 | ||
| 52 | /* | 49 | /* |
| 53 | * RPC call state | 50 | * RPC call state |
| 54 | */ | 51 | */ |
| 55 | struct rpc_message tk_msg; /* RPC call info */ | 52 | struct rpc_message tk_msg; /* RPC call info */ |
| 56 | __u8 tk_garb_retry; | ||
| 57 | __u8 tk_cred_retry; | ||
| 58 | 53 | ||
| 59 | /* | 54 | /* |
| 60 | * callback to be executed after waking up | 55 | * callback to be executed after waking up |
| @@ -67,7 +62,6 @@ struct rpc_task { | |||
| 67 | void * tk_calldata; | 62 | void * tk_calldata; |
| 68 | 63 | ||
| 69 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ | 64 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ |
| 70 | unsigned short tk_flags; /* misc flags */ | ||
| 71 | unsigned long tk_runstate; /* Task run status */ | 65 | unsigned long tk_runstate; /* Task run status */ |
| 72 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could | 66 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could |
| 73 | * be any workqueue | 67 | * be any workqueue |
| @@ -78,17 +72,19 @@ struct rpc_task { | |||
| 78 | struct rpc_wait tk_wait; /* RPC wait */ | 72 | struct rpc_wait tk_wait; /* RPC wait */ |
| 79 | } u; | 73 | } u; |
| 80 | 74 | ||
| 81 | unsigned short tk_timeouts; /* maj timeouts */ | 75 | ktime_t tk_start; /* RPC task init timestamp */ |
| 82 | size_t tk_bytes_sent; /* total bytes sent */ | ||
| 83 | unsigned long tk_start; /* RPC task init timestamp */ | ||
| 84 | long tk_rtt; /* round-trip time (jiffies) */ | ||
| 85 | 76 | ||
| 86 | pid_t tk_owner; /* Process id for batching tasks */ | 77 | pid_t tk_owner; /* Process id for batching tasks */ |
| 87 | unsigned char tk_priority : 2;/* Task priority */ | 78 | int tk_status; /* result of last operation */ |
| 79 | unsigned short tk_flags; /* misc flags */ | ||
| 80 | unsigned short tk_timeouts; /* maj timeouts */ | ||
| 88 | 81 | ||
| 89 | #ifdef RPC_DEBUG | 82 | #ifdef RPC_DEBUG |
| 90 | unsigned short tk_pid; /* debugging aid */ | 83 | unsigned short tk_pid; /* debugging aid */ |
| 91 | #endif | 84 | #endif |
| 85 | unsigned char tk_priority : 2,/* Task priority */ | ||
| 86 | tk_garb_retry : 2, | ||
| 87 | tk_cred_retry : 2; | ||
| 92 | }; | 88 | }; |
| 93 | #define tk_xprt tk_client->cl_xprt | 89 | #define tk_xprt tk_client->cl_xprt |
| 94 | 90 | ||
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index f5cc0898bc53..35cf2e8cd7c6 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * include/linux/sunrpc/xdr.h | 2 | * XDR standard data types and function declarations |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> | 4 | * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> |
| 5 | * | ||
| 6 | * Based on: | ||
| 7 | * RFC 4506 "XDR: External Data Representation Standard", May 2006 | ||
| 5 | */ | 8 | */ |
| 6 | 9 | ||
| 7 | #ifndef _SUNRPC_XDR_H_ | 10 | #ifndef _SUNRPC_XDR_H_ |
| @@ -62,7 +65,6 @@ struct xdr_buf { | |||
| 62 | 65 | ||
| 63 | unsigned int buflen, /* Total length of storage buffer */ | 66 | unsigned int buflen, /* Total length of storage buffer */ |
| 64 | len; /* Length of XDR encoded message */ | 67 | len; /* Length of XDR encoded message */ |
| 65 | |||
| 66 | }; | 68 | }; |
| 67 | 69 | ||
| 68 | /* | 70 | /* |
| @@ -178,7 +180,7 @@ struct xdr_array2_desc { | |||
| 178 | }; | 180 | }; |
| 179 | 181 | ||
| 180 | extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base, | 182 | extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base, |
| 181 | struct xdr_array2_desc *desc); | 183 | struct xdr_array2_desc *desc); |
| 182 | extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, | 184 | extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, |
| 183 | struct xdr_array2_desc *desc); | 185 | struct xdr_array2_desc *desc); |
| 184 | 186 | ||
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 6f9457a75b8f..b51470302399 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/socket.h> | 13 | #include <linux/socket.h> |
| 14 | #include <linux/in.h> | 14 | #include <linux/in.h> |
| 15 | #include <linux/kref.h> | 15 | #include <linux/kref.h> |
| 16 | #include <linux/ktime.h> | ||
| 16 | #include <linux/sunrpc/sched.h> | 17 | #include <linux/sunrpc/sched.h> |
| 17 | #include <linux/sunrpc/xdr.h> | 18 | #include <linux/sunrpc/xdr.h> |
| 18 | #include <linux/sunrpc/msg_prot.h> | 19 | #include <linux/sunrpc/msg_prot.h> |
| @@ -65,8 +66,6 @@ struct rpc_rqst { | |||
| 65 | struct rpc_task * rq_task; /* RPC task data */ | 66 | struct rpc_task * rq_task; /* RPC task data */ |
| 66 | __be32 rq_xid; /* request XID */ | 67 | __be32 rq_xid; /* request XID */ |
| 67 | int rq_cong; /* has incremented xprt->cong */ | 68 | int rq_cong; /* has incremented xprt->cong */ |
| 68 | int rq_reply_bytes_recvd; /* number of reply */ | ||
| 69 | /* bytes received */ | ||
| 70 | u32 rq_seqno; /* gss seq no. used on req. */ | 69 | u32 rq_seqno; /* gss seq no. used on req. */ |
| 71 | int rq_enc_pages_num; | 70 | int rq_enc_pages_num; |
| 72 | struct page **rq_enc_pages; /* scratch pages for use by | 71 | struct page **rq_enc_pages; /* scratch pages for use by |
| @@ -77,12 +76,16 @@ struct rpc_rqst { | |||
| 77 | __u32 * rq_buffer; /* XDR encode buffer */ | 76 | __u32 * rq_buffer; /* XDR encode buffer */ |
| 78 | size_t rq_callsize, | 77 | size_t rq_callsize, |
| 79 | rq_rcvsize; | 78 | rq_rcvsize; |
| 79 | size_t rq_xmit_bytes_sent; /* total bytes sent */ | ||
| 80 | size_t rq_reply_bytes_recvd; /* total reply bytes */ | ||
| 81 | /* received */ | ||
| 80 | 82 | ||
| 81 | struct xdr_buf rq_private_buf; /* The receive buffer | 83 | struct xdr_buf rq_private_buf; /* The receive buffer |
| 82 | * used in the softirq. | 84 | * used in the softirq. |
| 83 | */ | 85 | */ |
| 84 | unsigned long rq_majortimeo; /* major timeout alarm */ | 86 | unsigned long rq_majortimeo; /* major timeout alarm */ |
| 85 | unsigned long rq_timeout; /* Current timeout value */ | 87 | unsigned long rq_timeout; /* Current timeout value */ |
| 88 | ktime_t rq_rtt; /* round-trip time */ | ||
| 86 | unsigned int rq_retries; /* # of retries */ | 89 | unsigned int rq_retries; /* # of retries */ |
| 87 | unsigned int rq_connect_cookie; | 90 | unsigned int rq_connect_cookie; |
| 88 | /* A cookie used to track the | 91 | /* A cookie used to track the |
| @@ -94,7 +97,7 @@ struct rpc_rqst { | |||
| 94 | */ | 97 | */ |
| 95 | u32 rq_bytes_sent; /* Bytes we have sent */ | 98 | u32 rq_bytes_sent; /* Bytes we have sent */ |
| 96 | 99 | ||
| 97 | unsigned long rq_xtime; /* when transmitted */ | 100 | ktime_t rq_xtime; /* transmit time stamp */ |
| 98 | int rq_ntrans; | 101 | int rq_ntrans; |
| 99 | 102 | ||
| 100 | #if defined(CONFIG_NFS_V4_1) | 103 | #if defined(CONFIG_NFS_V4_1) |
| @@ -174,8 +177,7 @@ struct rpc_xprt { | |||
| 174 | /* | 177 | /* |
| 175 | * Connection of transports | 178 | * Connection of transports |
| 176 | */ | 179 | */ |
| 177 | unsigned long connect_timeout, | 180 | unsigned long bind_timeout, |
| 178 | bind_timeout, | ||
| 179 | reestablish_timeout; | 181 | reestablish_timeout; |
| 180 | unsigned int connect_cookie; /* A cookie that gets bumped | 182 | unsigned int connect_cookie; /* A cookie that gets bumped |
| 181 | every time the transport | 183 | every time the transport |
| @@ -294,7 +296,6 @@ void xprt_set_retrans_timeout_rtt(struct rpc_task *task); | |||
| 294 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); | 296 | void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); |
| 295 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); | 297 | void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); |
| 296 | void xprt_write_space(struct rpc_xprt *xprt); | 298 | void xprt_write_space(struct rpc_xprt *xprt); |
| 297 | void xprt_update_rtt(struct rpc_task *task); | ||
| 298 | void xprt_adjust_cwnd(struct rpc_task *task, int result); | 299 | void xprt_adjust_cwnd(struct rpc_task *task, int result); |
| 299 | struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); | 300 | struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); |
| 300 | void xprt_complete_rqst(struct rpc_task *task, int copied); | 301 | void xprt_complete_rqst(struct rpc_task *task, int copied); |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index 95afe79dd9d7..73affb8624fa 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -236,10 +236,15 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
| 236 | 236 | ||
| 237 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { | 237 | list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) { |
| 238 | 238 | ||
| 239 | /* Enforce a 60 second garbage collection moratorium */ | 239 | if (nr_to_scan-- == 0) |
| 240 | break; | ||
| 241 | /* | ||
| 242 | * Enforce a 60 second garbage collection moratorium | ||
| 243 | * Note that the cred_unused list must be time-ordered. | ||
| 244 | */ | ||
| 240 | if (time_in_range(cred->cr_expire, expired, jiffies) && | 245 | if (time_in_range(cred->cr_expire, expired, jiffies) && |
| 241 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) | 246 | test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) |
| 242 | continue; | 247 | return 0; |
| 243 | 248 | ||
| 244 | list_del_init(&cred->cr_lru); | 249 | list_del_init(&cred->cr_lru); |
| 245 | number_cred_unused--; | 250 | number_cred_unused--; |
| @@ -252,13 +257,10 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
| 252 | get_rpccred(cred); | 257 | get_rpccred(cred); |
| 253 | list_add_tail(&cred->cr_lru, free); | 258 | list_add_tail(&cred->cr_lru, free); |
| 254 | rpcauth_unhash_cred_locked(cred); | 259 | rpcauth_unhash_cred_locked(cred); |
| 255 | nr_to_scan--; | ||
| 256 | } | 260 | } |
| 257 | spin_unlock(cache_lock); | 261 | spin_unlock(cache_lock); |
| 258 | if (nr_to_scan == 0) | ||
| 259 | break; | ||
| 260 | } | 262 | } |
| 261 | return nr_to_scan; | 263 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; |
| 262 | } | 264 | } |
| 263 | 265 | ||
| 264 | /* | 266 | /* |
| @@ -270,11 +272,12 @@ rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | |||
| 270 | LIST_HEAD(free); | 272 | LIST_HEAD(free); |
| 271 | int res; | 273 | int res; |
| 272 | 274 | ||
| 275 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) | ||
| 276 | return (nr_to_scan == 0) ? 0 : -1; | ||
| 273 | if (list_empty(&cred_unused)) | 277 | if (list_empty(&cred_unused)) |
| 274 | return 0; | 278 | return 0; |
| 275 | spin_lock(&rpc_credcache_lock); | 279 | spin_lock(&rpc_credcache_lock); |
| 276 | nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan); | 280 | res = rpcauth_prune_expired(&free, nr_to_scan); |
| 277 | res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | ||
| 278 | spin_unlock(&rpc_credcache_lock); | 281 | spin_unlock(&rpc_credcache_lock); |
| 279 | rpcauth_destroy_credlist(&free); | 282 | rpcauth_destroy_credlist(&free); |
| 280 | return res; | 283 | return res; |
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile index 4de8bcf26fa7..74a231735f67 100644 --- a/net/sunrpc/auth_gss/Makefile +++ b/net/sunrpc/auth_gss/Makefile | |||
| @@ -10,7 +10,7 @@ auth_rpcgss-objs := auth_gss.o gss_generic_token.o \ | |||
| 10 | obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o | 10 | obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o |
| 11 | 11 | ||
| 12 | rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ | 12 | rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \ |
| 13 | gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o | 13 | gss_krb5_seqnum.o gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o |
| 14 | 14 | ||
| 15 | obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o | 15 | obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o |
| 16 | 16 | ||
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index c389ccf6437d..8da2a0e68574 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -57,11 +57,14 @@ static const struct rpc_authops authgss_ops; | |||
| 57 | static const struct rpc_credops gss_credops; | 57 | static const struct rpc_credops gss_credops; |
| 58 | static const struct rpc_credops gss_nullops; | 58 | static const struct rpc_credops gss_nullops; |
| 59 | 59 | ||
| 60 | #define GSS_RETRY_EXPIRED 5 | ||
| 61 | static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED; | ||
| 62 | |||
| 60 | #ifdef RPC_DEBUG | 63 | #ifdef RPC_DEBUG |
| 61 | # define RPCDBG_FACILITY RPCDBG_AUTH | 64 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| 62 | #endif | 65 | #endif |
| 63 | 66 | ||
| 64 | #define GSS_CRED_SLACK 1024 | 67 | #define GSS_CRED_SLACK (RPC_MAX_AUTH_SIZE * 2) |
| 65 | /* length of a krb5 verifier (48), plus data added before arguments when | 68 | /* length of a krb5 verifier (48), plus data added before arguments when |
| 66 | * using integrity (two 4-byte integers): */ | 69 | * using integrity (two 4-byte integers): */ |
| 67 | #define GSS_VERF_SLACK 100 | 70 | #define GSS_VERF_SLACK 100 |
| @@ -229,7 +232,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct | |||
| 229 | p = ERR_PTR(-EFAULT); | 232 | p = ERR_PTR(-EFAULT); |
| 230 | goto err; | 233 | goto err; |
| 231 | } | 234 | } |
| 232 | ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx); | 235 | ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, GFP_NOFS); |
| 233 | if (ret < 0) { | 236 | if (ret < 0) { |
| 234 | p = ERR_PTR(ret); | 237 | p = ERR_PTR(ret); |
| 235 | goto err; | 238 | goto err; |
| @@ -350,6 +353,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg) | |||
| 350 | } | 353 | } |
| 351 | 354 | ||
| 352 | static void | 355 | static void |
| 356 | gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg) | ||
| 357 | { | ||
| 358 | switch (gss_msg->msg.errno) { | ||
| 359 | case 0: | ||
| 360 | if (gss_msg->ctx == NULL) | ||
| 361 | break; | ||
| 362 | clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags); | ||
| 363 | gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx); | ||
| 364 | break; | ||
| 365 | case -EKEYEXPIRED: | ||
| 366 | set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags); | ||
| 367 | } | ||
| 368 | gss_cred->gc_upcall_timestamp = jiffies; | ||
| 369 | gss_cred->gc_upcall = NULL; | ||
| 370 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
| 371 | } | ||
| 372 | |||
| 373 | static void | ||
| 353 | gss_upcall_callback(struct rpc_task *task) | 374 | gss_upcall_callback(struct rpc_task *task) |
| 354 | { | 375 | { |
| 355 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | 376 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, |
| @@ -358,13 +379,9 @@ gss_upcall_callback(struct rpc_task *task) | |||
| 358 | struct inode *inode = &gss_msg->inode->vfs_inode; | 379 | struct inode *inode = &gss_msg->inode->vfs_inode; |
| 359 | 380 | ||
| 360 | spin_lock(&inode->i_lock); | 381 | spin_lock(&inode->i_lock); |
| 361 | if (gss_msg->ctx) | 382 | gss_handle_downcall_result(gss_cred, gss_msg); |
| 362 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); | ||
| 363 | else | ||
| 364 | task->tk_status = gss_msg->msg.errno; | ||
| 365 | gss_cred->gc_upcall = NULL; | ||
| 366 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
| 367 | spin_unlock(&inode->i_lock); | 383 | spin_unlock(&inode->i_lock); |
| 384 | task->tk_status = gss_msg->msg.errno; | ||
| 368 | gss_release_msg(gss_msg); | 385 | gss_release_msg(gss_msg); |
| 369 | } | 386 | } |
| 370 | 387 | ||
| @@ -377,11 +394,12 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | |||
| 377 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | 394 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, |
| 378 | struct rpc_clnt *clnt, int machine_cred) | 395 | struct rpc_clnt *clnt, int machine_cred) |
| 379 | { | 396 | { |
| 397 | struct gss_api_mech *mech = gss_msg->auth->mech; | ||
| 380 | char *p = gss_msg->databuf; | 398 | char *p = gss_msg->databuf; |
| 381 | int len = 0; | 399 | int len = 0; |
| 382 | 400 | ||
| 383 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", | 401 | gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", |
| 384 | gss_msg->auth->mech->gm_name, | 402 | mech->gm_name, |
| 385 | gss_msg->uid); | 403 | gss_msg->uid); |
| 386 | p += gss_msg->msg.len; | 404 | p += gss_msg->msg.len; |
| 387 | if (clnt->cl_principal) { | 405 | if (clnt->cl_principal) { |
| @@ -398,6 +416,11 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | |||
| 398 | p += len; | 416 | p += len; |
| 399 | gss_msg->msg.len += len; | 417 | gss_msg->msg.len += len; |
| 400 | } | 418 | } |
| 419 | if (mech->gm_upcall_enctypes) { | ||
| 420 | len = sprintf(p, mech->gm_upcall_enctypes); | ||
| 421 | p += len; | ||
| 422 | gss_msg->msg.len += len; | ||
| 423 | } | ||
| 401 | len = sprintf(p, "\n"); | 424 | len = sprintf(p, "\n"); |
| 402 | gss_msg->msg.len += len; | 425 | gss_msg->msg.len += len; |
| 403 | 426 | ||
| @@ -507,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task) | |||
| 507 | spin_lock(&inode->i_lock); | 530 | spin_lock(&inode->i_lock); |
| 508 | if (gss_cred->gc_upcall != NULL) | 531 | if (gss_cred->gc_upcall != NULL) |
| 509 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); | 532 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); |
| 510 | else if (gss_msg->ctx != NULL) { | 533 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { |
| 511 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx); | ||
| 512 | gss_cred->gc_upcall = NULL; | ||
| 513 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | ||
| 514 | } else if (gss_msg->msg.errno >= 0) { | ||
| 515 | task->tk_timeout = 0; | 534 | task->tk_timeout = 0; |
| 516 | gss_cred->gc_upcall = gss_msg; | 535 | gss_cred->gc_upcall = gss_msg; |
| 517 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ | 536 | /* gss_upcall_callback will release the reference to gss_upcall_msg */ |
| 518 | atomic_inc(&gss_msg->count); | 537 | atomic_inc(&gss_msg->count); |
| 519 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); | 538 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); |
| 520 | } else | 539 | } else { |
| 540 | gss_handle_downcall_result(gss_cred, gss_msg); | ||
| 521 | err = gss_msg->msg.errno; | 541 | err = gss_msg->msg.errno; |
| 542 | } | ||
| 522 | spin_unlock(&inode->i_lock); | 543 | spin_unlock(&inode->i_lock); |
| 523 | gss_release_msg(gss_msg); | 544 | gss_release_msg(gss_msg); |
| 524 | out: | 545 | out: |
| @@ -1117,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task) | |||
| 1117 | return 0; | 1138 | return 0; |
| 1118 | } | 1139 | } |
| 1119 | 1140 | ||
| 1141 | static int gss_cred_is_negative_entry(struct rpc_cred *cred) | ||
| 1142 | { | ||
| 1143 | if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) { | ||
| 1144 | unsigned long now = jiffies; | ||
| 1145 | unsigned long begin, expire; | ||
| 1146 | struct gss_cred *gss_cred; | ||
| 1147 | |||
| 1148 | gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
| 1149 | begin = gss_cred->gc_upcall_timestamp; | ||
| 1150 | expire = begin + gss_expired_cred_retry_delay * HZ; | ||
| 1151 | |||
| 1152 | if (time_in_range_open(now, begin, expire)) | ||
| 1153 | return 1; | ||
| 1154 | } | ||
| 1155 | return 0; | ||
| 1156 | } | ||
| 1157 | |||
| 1120 | /* | 1158 | /* |
| 1121 | * Refresh credentials. XXX - finish | 1159 | * Refresh credentials. XXX - finish |
| 1122 | */ | 1160 | */ |
| @@ -1126,6 +1164,9 @@ gss_refresh(struct rpc_task *task) | |||
| 1126 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 1164 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
| 1127 | int ret = 0; | 1165 | int ret = 0; |
| 1128 | 1166 | ||
| 1167 | if (gss_cred_is_negative_entry(cred)) | ||
| 1168 | return -EKEYEXPIRED; | ||
| 1169 | |||
| 1129 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | 1170 | if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && |
| 1130 | !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { | 1171 | !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { |
| 1131 | ret = gss_renew_cred(task); | 1172 | ret = gss_renew_cred(task); |
| @@ -1316,15 +1357,21 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
| 1316 | inpages = snd_buf->pages + first; | 1357 | inpages = snd_buf->pages + first; |
| 1317 | snd_buf->pages = rqstp->rq_enc_pages; | 1358 | snd_buf->pages = rqstp->rq_enc_pages; |
| 1318 | snd_buf->page_base -= first << PAGE_CACHE_SHIFT; | 1359 | snd_buf->page_base -= first << PAGE_CACHE_SHIFT; |
| 1319 | /* Give the tail its own page, in case we need extra space in the | 1360 | /* |
| 1320 | * head when wrapping: */ | 1361 | * Give the tail its own page, in case we need extra space in the |
| 1362 | * head when wrapping: | ||
| 1363 | * | ||
| 1364 | * call_allocate() allocates twice the slack space required | ||
| 1365 | * by the authentication flavor to rq_callsize. | ||
| 1366 | * For GSS, slack is GSS_CRED_SLACK. | ||
| 1367 | */ | ||
| 1321 | if (snd_buf->page_len || snd_buf->tail[0].iov_len) { | 1368 | if (snd_buf->page_len || snd_buf->tail[0].iov_len) { |
| 1322 | tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]); | 1369 | tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]); |
| 1323 | memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); | 1370 | memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); |
| 1324 | snd_buf->tail[0].iov_base = tmp; | 1371 | snd_buf->tail[0].iov_base = tmp; |
| 1325 | } | 1372 | } |
| 1326 | maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages); | 1373 | maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages); |
| 1327 | /* RPC_SLACK_SPACE should prevent this ever happening: */ | 1374 | /* slack space should prevent this ever happening: */ |
| 1328 | BUG_ON(snd_buf->len > snd_buf->buflen); | 1375 | BUG_ON(snd_buf->len > snd_buf->buflen); |
| 1329 | status = -EIO; | 1376 | status = -EIO; |
| 1330 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was | 1377 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was |
| @@ -1573,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void) | |||
| 1573 | } | 1620 | } |
| 1574 | 1621 | ||
| 1575 | MODULE_LICENSE("GPL"); | 1622 | MODULE_LICENSE("GPL"); |
| 1623 | module_param_named(expired_cred_retry_delay, | ||
| 1624 | gss_expired_cred_retry_delay, | ||
| 1625 | uint, 0644); | ||
| 1626 | MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until " | ||
| 1627 | "the RPC engine retries an expired credential"); | ||
| 1628 | |||
| 1576 | module_init(init_rpcsec_gss) | 1629 | module_init(init_rpcsec_gss) |
| 1577 | module_exit(exit_rpcsec_gss) | 1630 | module_exit(exit_rpcsec_gss) |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index e9b636176687..75ee993ea057 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/net/sunrpc/gss_krb5_crypto.c | 2 | * linux/net/sunrpc/gss_krb5_crypto.c |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2000 The Regents of the University of Michigan. | 4 | * Copyright (c) 2000-2008 The Regents of the University of Michigan. |
| 5 | * All rights reserved. | 5 | * All rights reserved. |
| 6 | * | 6 | * |
| 7 | * Andy Adamson <andros@umich.edu> | 7 | * Andy Adamson <andros@umich.edu> |
| @@ -41,6 +41,7 @@ | |||
| 41 | #include <linux/crypto.h> | 41 | #include <linux/crypto.h> |
| 42 | #include <linux/highmem.h> | 42 | #include <linux/highmem.h> |
| 43 | #include <linux/pagemap.h> | 43 | #include <linux/pagemap.h> |
| 44 | #include <linux/random.h> | ||
| 44 | #include <linux/sunrpc/gss_krb5.h> | 45 | #include <linux/sunrpc/gss_krb5.h> |
| 45 | #include <linux/sunrpc/xdr.h> | 46 | #include <linux/sunrpc/xdr.h> |
| 46 | 47 | ||
| @@ -58,13 +59,13 @@ krb5_encrypt( | |||
| 58 | { | 59 | { |
| 59 | u32 ret = -EINVAL; | 60 | u32 ret = -EINVAL; |
| 60 | struct scatterlist sg[1]; | 61 | struct scatterlist sg[1]; |
| 61 | u8 local_iv[16] = {0}; | 62 | u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; |
| 62 | struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; | 63 | struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; |
| 63 | 64 | ||
| 64 | if (length % crypto_blkcipher_blocksize(tfm) != 0) | 65 | if (length % crypto_blkcipher_blocksize(tfm) != 0) |
| 65 | goto out; | 66 | goto out; |
| 66 | 67 | ||
| 67 | if (crypto_blkcipher_ivsize(tfm) > 16) { | 68 | if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { |
| 68 | dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n", | 69 | dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n", |
| 69 | crypto_blkcipher_ivsize(tfm)); | 70 | crypto_blkcipher_ivsize(tfm)); |
| 70 | goto out; | 71 | goto out; |
| @@ -92,13 +93,13 @@ krb5_decrypt( | |||
| 92 | { | 93 | { |
| 93 | u32 ret = -EINVAL; | 94 | u32 ret = -EINVAL; |
| 94 | struct scatterlist sg[1]; | 95 | struct scatterlist sg[1]; |
| 95 | u8 local_iv[16] = {0}; | 96 | u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; |
| 96 | struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; | 97 | struct blkcipher_desc desc = { .tfm = tfm, .info = local_iv }; |
| 97 | 98 | ||
| 98 | if (length % crypto_blkcipher_blocksize(tfm) != 0) | 99 | if (length % crypto_blkcipher_blocksize(tfm) != 0) |
| 99 | goto out; | 100 | goto out; |
| 100 | 101 | ||
| 101 | if (crypto_blkcipher_ivsize(tfm) > 16) { | 102 | if (crypto_blkcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { |
| 102 | dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n", | 103 | dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n", |
| 103 | crypto_blkcipher_ivsize(tfm)); | 104 | crypto_blkcipher_ivsize(tfm)); |
| 104 | goto out; | 105 | goto out; |
| @@ -123,21 +124,155 @@ checksummer(struct scatterlist *sg, void *data) | |||
| 123 | return crypto_hash_update(desc, sg, sg->length); | 124 | return crypto_hash_update(desc, sg, sg->length); |
| 124 | } | 125 | } |
| 125 | 126 | ||
| 126 | /* checksum the plaintext data and hdrlen bytes of the token header */ | 127 | static int |
| 127 | s32 | 128 | arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4]) |
| 128 | make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body, | 129 | { |
| 129 | int body_offset, struct xdr_netobj *cksum) | 130 | unsigned int ms_usage; |
| 131 | |||
| 132 | switch (usage) { | ||
| 133 | case KG_USAGE_SIGN: | ||
| 134 | ms_usage = 15; | ||
| 135 | break; | ||
| 136 | case KG_USAGE_SEAL: | ||
| 137 | ms_usage = 13; | ||
| 138 | break; | ||
| 139 | default: | ||
| 140 | return EINVAL;; | ||
| 141 | } | ||
| 142 | salt[0] = (ms_usage >> 0) & 0xff; | ||
| 143 | salt[1] = (ms_usage >> 8) & 0xff; | ||
| 144 | salt[2] = (ms_usage >> 16) & 0xff; | ||
| 145 | salt[3] = (ms_usage >> 24) & 0xff; | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | static u32 | ||
| 151 | make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
| 152 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
| 153 | unsigned int usage, struct xdr_netobj *cksumout) | ||
| 130 | { | 154 | { |
| 131 | struct hash_desc desc; /* XXX add to ctx? */ | 155 | struct hash_desc desc; |
| 132 | struct scatterlist sg[1]; | 156 | struct scatterlist sg[1]; |
| 133 | int err; | 157 | int err; |
| 158 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 159 | u8 rc4salt[4]; | ||
| 160 | struct crypto_hash *md5; | ||
| 161 | struct crypto_hash *hmac_md5; | ||
| 162 | |||
| 163 | if (cksumkey == NULL) | ||
| 164 | return GSS_S_FAILURE; | ||
| 165 | |||
| 166 | if (cksumout->len < kctx->gk5e->cksumlength) { | ||
| 167 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | ||
| 168 | __func__, cksumout->len, kctx->gk5e->name); | ||
| 169 | return GSS_S_FAILURE; | ||
| 170 | } | ||
| 171 | |||
| 172 | if (arcfour_hmac_md5_usage_to_salt(usage, rc4salt)) { | ||
| 173 | dprintk("%s: invalid usage value %u\n", __func__, usage); | ||
| 174 | return GSS_S_FAILURE; | ||
| 175 | } | ||
| 176 | |||
| 177 | md5 = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | ||
| 178 | if (IS_ERR(md5)) | ||
| 179 | return GSS_S_FAILURE; | ||
| 180 | |||
| 181 | hmac_md5 = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, | ||
| 182 | CRYPTO_ALG_ASYNC); | ||
| 183 | if (IS_ERR(hmac_md5)) { | ||
| 184 | crypto_free_hash(md5); | ||
| 185 | return GSS_S_FAILURE; | ||
| 186 | } | ||
| 187 | |||
| 188 | desc.tfm = md5; | ||
| 189 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 190 | |||
| 191 | err = crypto_hash_init(&desc); | ||
| 192 | if (err) | ||
| 193 | goto out; | ||
| 194 | sg_init_one(sg, rc4salt, 4); | ||
| 195 | err = crypto_hash_update(&desc, sg, 4); | ||
| 196 | if (err) | ||
| 197 | goto out; | ||
| 198 | |||
| 199 | sg_init_one(sg, header, hdrlen); | ||
| 200 | err = crypto_hash_update(&desc, sg, hdrlen); | ||
| 201 | if (err) | ||
| 202 | goto out; | ||
| 203 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | ||
| 204 | checksummer, &desc); | ||
| 205 | if (err) | ||
| 206 | goto out; | ||
| 207 | err = crypto_hash_final(&desc, checksumdata); | ||
| 208 | if (err) | ||
| 209 | goto out; | ||
| 210 | |||
| 211 | desc.tfm = hmac_md5; | ||
| 212 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 213 | |||
| 214 | err = crypto_hash_init(&desc); | ||
| 215 | if (err) | ||
| 216 | goto out; | ||
| 217 | err = crypto_hash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength); | ||
| 218 | if (err) | ||
| 219 | goto out; | ||
| 220 | |||
| 221 | sg_init_one(sg, checksumdata, crypto_hash_digestsize(md5)); | ||
| 222 | err = crypto_hash_digest(&desc, sg, crypto_hash_digestsize(md5), | ||
| 223 | checksumdata); | ||
| 224 | if (err) | ||
| 225 | goto out; | ||
| 226 | |||
| 227 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | ||
| 228 | cksumout->len = kctx->gk5e->cksumlength; | ||
| 229 | out: | ||
| 230 | crypto_free_hash(md5); | ||
| 231 | crypto_free_hash(hmac_md5); | ||
| 232 | return err ? GSS_S_FAILURE : 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | ||
| 236 | * checksum the plaintext data and hdrlen bytes of the token header | ||
| 237 | * The checksum is performed over the first 8 bytes of the | ||
| 238 | * gss token header and then over the data body | ||
| 239 | */ | ||
| 240 | u32 | ||
| 241 | make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
| 242 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
| 243 | unsigned int usage, struct xdr_netobj *cksumout) | ||
| 244 | { | ||
| 245 | struct hash_desc desc; | ||
| 246 | struct scatterlist sg[1]; | ||
| 247 | int err; | ||
| 248 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 249 | unsigned int checksumlen; | ||
| 250 | |||
| 251 | if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR) | ||
| 252 | return make_checksum_hmac_md5(kctx, header, hdrlen, | ||
| 253 | body, body_offset, | ||
| 254 | cksumkey, usage, cksumout); | ||
| 255 | |||
| 256 | if (cksumout->len < kctx->gk5e->cksumlength) { | ||
| 257 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | ||
| 258 | __func__, cksumout->len, kctx->gk5e->name); | ||
| 259 | return GSS_S_FAILURE; | ||
| 260 | } | ||
| 134 | 261 | ||
| 135 | desc.tfm = crypto_alloc_hash(cksumname, 0, CRYPTO_ALG_ASYNC); | 262 | desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); |
| 136 | if (IS_ERR(desc.tfm)) | 263 | if (IS_ERR(desc.tfm)) |
| 137 | return GSS_S_FAILURE; | 264 | return GSS_S_FAILURE; |
| 138 | cksum->len = crypto_hash_digestsize(desc.tfm); | ||
| 139 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | 265 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; |
| 140 | 266 | ||
| 267 | checksumlen = crypto_hash_digestsize(desc.tfm); | ||
| 268 | |||
| 269 | if (cksumkey != NULL) { | ||
| 270 | err = crypto_hash_setkey(desc.tfm, cksumkey, | ||
| 271 | kctx->gk5e->keylength); | ||
| 272 | if (err) | ||
| 273 | goto out; | ||
| 274 | } | ||
| 275 | |||
| 141 | err = crypto_hash_init(&desc); | 276 | err = crypto_hash_init(&desc); |
| 142 | if (err) | 277 | if (err) |
| 143 | goto out; | 278 | goto out; |
| @@ -149,15 +284,109 @@ make_checksum(char *cksumname, char *header, int hdrlen, struct xdr_buf *body, | |||
| 149 | checksummer, &desc); | 284 | checksummer, &desc); |
| 150 | if (err) | 285 | if (err) |
| 151 | goto out; | 286 | goto out; |
| 152 | err = crypto_hash_final(&desc, cksum->data); | 287 | err = crypto_hash_final(&desc, checksumdata); |
| 288 | if (err) | ||
| 289 | goto out; | ||
| 153 | 290 | ||
| 291 | switch (kctx->gk5e->ctype) { | ||
| 292 | case CKSUMTYPE_RSA_MD5: | ||
| 293 | err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata, | ||
| 294 | checksumdata, checksumlen); | ||
| 295 | if (err) | ||
| 296 | goto out; | ||
| 297 | memcpy(cksumout->data, | ||
| 298 | checksumdata + checksumlen - kctx->gk5e->cksumlength, | ||
| 299 | kctx->gk5e->cksumlength); | ||
| 300 | break; | ||
| 301 | case CKSUMTYPE_HMAC_SHA1_DES3: | ||
| 302 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | ||
| 303 | break; | ||
| 304 | default: | ||
| 305 | BUG(); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | cksumout->len = kctx->gk5e->cksumlength; | ||
| 309 | out: | ||
| 310 | crypto_free_hash(desc.tfm); | ||
| 311 | return err ? GSS_S_FAILURE : 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* | ||
| 315 | * checksum the plaintext data and hdrlen bytes of the token header | ||
| 316 | * Per rfc4121, sec. 4.2.4, the checksum is performed over the data | ||
| 317 | * body then over the first 16 octets of the MIC token | ||
| 318 | * Inclusion of the header data in the calculation of the | ||
| 319 | * checksum is optional. | ||
| 320 | */ | ||
| 321 | u32 | ||
| 322 | make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen, | ||
| 323 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | ||
| 324 | unsigned int usage, struct xdr_netobj *cksumout) | ||
| 325 | { | ||
| 326 | struct hash_desc desc; | ||
| 327 | struct scatterlist sg[1]; | ||
| 328 | int err; | ||
| 329 | u8 checksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 330 | unsigned int checksumlen; | ||
| 331 | |||
| 332 | if (kctx->gk5e->keyed_cksum == 0) { | ||
| 333 | dprintk("%s: expected keyed hash for %s\n", | ||
| 334 | __func__, kctx->gk5e->name); | ||
| 335 | return GSS_S_FAILURE; | ||
| 336 | } | ||
| 337 | if (cksumkey == NULL) { | ||
| 338 | dprintk("%s: no key supplied for %s\n", | ||
| 339 | __func__, kctx->gk5e->name); | ||
| 340 | return GSS_S_FAILURE; | ||
| 341 | } | ||
| 342 | |||
| 343 | desc.tfm = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, | ||
| 344 | CRYPTO_ALG_ASYNC); | ||
| 345 | if (IS_ERR(desc.tfm)) | ||
| 346 | return GSS_S_FAILURE; | ||
| 347 | checksumlen = crypto_hash_digestsize(desc.tfm); | ||
| 348 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
| 349 | |||
| 350 | err = crypto_hash_setkey(desc.tfm, cksumkey, kctx->gk5e->keylength); | ||
| 351 | if (err) | ||
| 352 | goto out; | ||
| 353 | |||
| 354 | err = crypto_hash_init(&desc); | ||
| 355 | if (err) | ||
| 356 | goto out; | ||
| 357 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | ||
| 358 | checksummer, &desc); | ||
| 359 | if (err) | ||
| 360 | goto out; | ||
| 361 | if (header != NULL) { | ||
| 362 | sg_init_one(sg, header, hdrlen); | ||
| 363 | err = crypto_hash_update(&desc, sg, hdrlen); | ||
| 364 | if (err) | ||
| 365 | goto out; | ||
| 366 | } | ||
| 367 | err = crypto_hash_final(&desc, checksumdata); | ||
| 368 | if (err) | ||
| 369 | goto out; | ||
| 370 | |||
| 371 | cksumout->len = kctx->gk5e->cksumlength; | ||
| 372 | |||
| 373 | switch (kctx->gk5e->ctype) { | ||
| 374 | case CKSUMTYPE_HMAC_SHA1_96_AES128: | ||
| 375 | case CKSUMTYPE_HMAC_SHA1_96_AES256: | ||
| 376 | /* note that this truncates the hash */ | ||
| 377 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | ||
| 378 | break; | ||
| 379 | default: | ||
| 380 | BUG(); | ||
| 381 | break; | ||
| 382 | } | ||
| 154 | out: | 383 | out: |
| 155 | crypto_free_hash(desc.tfm); | 384 | crypto_free_hash(desc.tfm); |
| 156 | return err ? GSS_S_FAILURE : 0; | 385 | return err ? GSS_S_FAILURE : 0; |
| 157 | } | 386 | } |
| 158 | 387 | ||
| 159 | struct encryptor_desc { | 388 | struct encryptor_desc { |
| 160 | u8 iv[8]; /* XXX hard-coded blocksize */ | 389 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; |
| 161 | struct blkcipher_desc desc; | 390 | struct blkcipher_desc desc; |
| 162 | int pos; | 391 | int pos; |
| 163 | struct xdr_buf *outbuf; | 392 | struct xdr_buf *outbuf; |
| @@ -198,7 +427,7 @@ encryptor(struct scatterlist *sg, void *data) | |||
| 198 | desc->fraglen += sg->length; | 427 | desc->fraglen += sg->length; |
| 199 | desc->pos += sg->length; | 428 | desc->pos += sg->length; |
| 200 | 429 | ||
| 201 | fraglen = thislen & 7; /* XXX hardcoded blocksize */ | 430 | fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1); |
| 202 | thislen -= fraglen; | 431 | thislen -= fraglen; |
| 203 | 432 | ||
| 204 | if (thislen == 0) | 433 | if (thislen == 0) |
| @@ -256,7 +485,7 @@ gss_encrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, | |||
| 256 | } | 485 | } |
| 257 | 486 | ||
| 258 | struct decryptor_desc { | 487 | struct decryptor_desc { |
| 259 | u8 iv[8]; /* XXX hard-coded blocksize */ | 488 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; |
| 260 | struct blkcipher_desc desc; | 489 | struct blkcipher_desc desc; |
| 261 | struct scatterlist frags[4]; | 490 | struct scatterlist frags[4]; |
| 262 | int fragno; | 491 | int fragno; |
| @@ -278,7 +507,7 @@ decryptor(struct scatterlist *sg, void *data) | |||
| 278 | desc->fragno++; | 507 | desc->fragno++; |
| 279 | desc->fraglen += sg->length; | 508 | desc->fraglen += sg->length; |
| 280 | 509 | ||
| 281 | fraglen = thislen & 7; /* XXX hardcoded blocksize */ | 510 | fraglen = thislen & (crypto_blkcipher_blocksize(desc->desc.tfm) - 1); |
| 282 | thislen -= fraglen; | 511 | thislen -= fraglen; |
| 283 | 512 | ||
| 284 | if (thislen == 0) | 513 | if (thislen == 0) |
| @@ -325,3 +554,437 @@ gss_decrypt_xdr_buf(struct crypto_blkcipher *tfm, struct xdr_buf *buf, | |||
| 325 | 554 | ||
| 326 | return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); | 555 | return xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); |
| 327 | } | 556 | } |
| 557 | |||
| 558 | /* | ||
| 559 | * This function makes the assumption that it was ultimately called | ||
| 560 | * from gss_wrap(). | ||
| 561 | * | ||
| 562 | * The client auth_gss code moves any existing tail data into a | ||
| 563 | * separate page before calling gss_wrap. | ||
| 564 | * The server svcauth_gss code ensures that both the head and the | ||
| 565 | * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap. | ||
| 566 | * | ||
| 567 | * Even with that guarantee, this function may be called more than | ||
| 568 | * once in the processing of gss_wrap(). The best we can do is | ||
| 569 | * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the | ||
| 570 | * largest expected shift will fit within RPC_MAX_AUTH_SIZE. | ||
| 571 | * At run-time we can verify that a single invocation of this | ||
| 572 | * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE. | ||
| 573 | */ | ||
| 574 | |||
| 575 | int | ||
| 576 | xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen) | ||
| 577 | { | ||
| 578 | u8 *p; | ||
| 579 | |||
| 580 | if (shiftlen == 0) | ||
| 581 | return 0; | ||
| 582 | |||
| 583 | BUILD_BUG_ON(GSS_KRB5_MAX_SLACK_NEEDED > RPC_MAX_AUTH_SIZE); | ||
| 584 | BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE); | ||
| 585 | |||
| 586 | p = buf->head[0].iov_base + base; | ||
| 587 | |||
| 588 | memmove(p + shiftlen, p, buf->head[0].iov_len - base); | ||
| 589 | |||
| 590 | buf->head[0].iov_len += shiftlen; | ||
| 591 | buf->len += shiftlen; | ||
| 592 | |||
| 593 | return 0; | ||
| 594 | } | ||
| 595 | |||
| 596 | static u32 | ||
| 597 | gss_krb5_cts_crypt(struct crypto_blkcipher *cipher, struct xdr_buf *buf, | ||
| 598 | u32 offset, u8 *iv, struct page **pages, int encrypt) | ||
| 599 | { | ||
| 600 | u32 ret; | ||
| 601 | struct scatterlist sg[1]; | ||
| 602 | struct blkcipher_desc desc = { .tfm = cipher, .info = iv }; | ||
| 603 | u8 data[crypto_blkcipher_blocksize(cipher) * 2]; | ||
| 604 | struct page **save_pages; | ||
| 605 | u32 len = buf->len - offset; | ||
| 606 | |||
| 607 | BUG_ON(len > crypto_blkcipher_blocksize(cipher) * 2); | ||
| 608 | |||
| 609 | /* | ||
| 610 | * For encryption, we want to read from the cleartext | ||
| 611 | * page cache pages, and write the encrypted data to | ||
| 612 | * the supplied xdr_buf pages. | ||
| 613 | */ | ||
| 614 | save_pages = buf->pages; | ||
| 615 | if (encrypt) | ||
| 616 | buf->pages = pages; | ||
| 617 | |||
| 618 | ret = read_bytes_from_xdr_buf(buf, offset, data, len); | ||
| 619 | buf->pages = save_pages; | ||
| 620 | if (ret) | ||
| 621 | goto out; | ||
| 622 | |||
| 623 | sg_init_one(sg, data, len); | ||
| 624 | |||
| 625 | if (encrypt) | ||
| 626 | ret = crypto_blkcipher_encrypt_iv(&desc, sg, sg, len); | ||
| 627 | else | ||
| 628 | ret = crypto_blkcipher_decrypt_iv(&desc, sg, sg, len); | ||
| 629 | |||
| 630 | if (ret) | ||
| 631 | goto out; | ||
| 632 | |||
| 633 | ret = write_bytes_to_xdr_buf(buf, offset, data, len); | ||
| 634 | |||
| 635 | out: | ||
| 636 | return ret; | ||
| 637 | } | ||
| 638 | |||
| 639 | u32 | ||
| 640 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | ||
| 641 | struct xdr_buf *buf, int ec, struct page **pages) | ||
| 642 | { | ||
| 643 | u32 err; | ||
| 644 | struct xdr_netobj hmac; | ||
| 645 | u8 *cksumkey; | ||
| 646 | u8 *ecptr; | ||
| 647 | struct crypto_blkcipher *cipher, *aux_cipher; | ||
| 648 | int blocksize; | ||
| 649 | struct page **save_pages; | ||
| 650 | int nblocks, nbytes; | ||
| 651 | struct encryptor_desc desc; | ||
| 652 | u32 cbcbytes; | ||
| 653 | unsigned int usage; | ||
| 654 | |||
| 655 | if (kctx->initiate) { | ||
| 656 | cipher = kctx->initiator_enc; | ||
| 657 | aux_cipher = kctx->initiator_enc_aux; | ||
| 658 | cksumkey = kctx->initiator_integ; | ||
| 659 | usage = KG_USAGE_INITIATOR_SEAL; | ||
| 660 | } else { | ||
| 661 | cipher = kctx->acceptor_enc; | ||
| 662 | aux_cipher = kctx->acceptor_enc_aux; | ||
| 663 | cksumkey = kctx->acceptor_integ; | ||
| 664 | usage = KG_USAGE_ACCEPTOR_SEAL; | ||
| 665 | } | ||
| 666 | blocksize = crypto_blkcipher_blocksize(cipher); | ||
| 667 | |||
| 668 | /* hide the gss token header and insert the confounder */ | ||
| 669 | offset += GSS_KRB5_TOK_HDR_LEN; | ||
| 670 | if (xdr_extend_head(buf, offset, kctx->gk5e->conflen)) | ||
| 671 | return GSS_S_FAILURE; | ||
| 672 | gss_krb5_make_confounder(buf->head[0].iov_base + offset, kctx->gk5e->conflen); | ||
| 673 | offset -= GSS_KRB5_TOK_HDR_LEN; | ||
| 674 | |||
| 675 | if (buf->tail[0].iov_base != NULL) { | ||
| 676 | ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len; | ||
| 677 | } else { | ||
| 678 | buf->tail[0].iov_base = buf->head[0].iov_base | ||
| 679 | + buf->head[0].iov_len; | ||
| 680 | buf->tail[0].iov_len = 0; | ||
| 681 | ecptr = buf->tail[0].iov_base; | ||
| 682 | } | ||
| 683 | |||
| 684 | memset(ecptr, 'X', ec); | ||
| 685 | buf->tail[0].iov_len += ec; | ||
| 686 | buf->len += ec; | ||
| 687 | |||
| 688 | /* copy plaintext gss token header after filler (if any) */ | ||
| 689 | memcpy(ecptr + ec, buf->head[0].iov_base + offset, | ||
| 690 | GSS_KRB5_TOK_HDR_LEN); | ||
| 691 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; | ||
| 692 | buf->len += GSS_KRB5_TOK_HDR_LEN; | ||
| 693 | |||
| 694 | /* Do the HMAC */ | ||
| 695 | hmac.len = GSS_KRB5_MAX_CKSUM_LEN; | ||
| 696 | hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len; | ||
| 697 | |||
| 698 | /* | ||
| 699 | * When we are called, pages points to the real page cache | ||
| 700 | * data -- which we can't go and encrypt! buf->pages points | ||
| 701 | * to scratch pages which we are going to send off to the | ||
| 702 | * client/server. Swap in the plaintext pages to calculate | ||
| 703 | * the hmac. | ||
| 704 | */ | ||
| 705 | save_pages = buf->pages; | ||
| 706 | buf->pages = pages; | ||
| 707 | |||
| 708 | err = make_checksum_v2(kctx, NULL, 0, buf, | ||
| 709 | offset + GSS_KRB5_TOK_HDR_LEN, | ||
| 710 | cksumkey, usage, &hmac); | ||
| 711 | buf->pages = save_pages; | ||
| 712 | if (err) | ||
| 713 | return GSS_S_FAILURE; | ||
| 714 | |||
| 715 | nbytes = buf->len - offset - GSS_KRB5_TOK_HDR_LEN; | ||
| 716 | nblocks = (nbytes + blocksize - 1) / blocksize; | ||
| 717 | cbcbytes = 0; | ||
| 718 | if (nblocks > 2) | ||
| 719 | cbcbytes = (nblocks - 2) * blocksize; | ||
| 720 | |||
| 721 | memset(desc.iv, 0, sizeof(desc.iv)); | ||
| 722 | |||
| 723 | if (cbcbytes) { | ||
| 724 | desc.pos = offset + GSS_KRB5_TOK_HDR_LEN; | ||
| 725 | desc.fragno = 0; | ||
| 726 | desc.fraglen = 0; | ||
| 727 | desc.pages = pages; | ||
| 728 | desc.outbuf = buf; | ||
| 729 | desc.desc.info = desc.iv; | ||
| 730 | desc.desc.flags = 0; | ||
| 731 | desc.desc.tfm = aux_cipher; | ||
| 732 | |||
| 733 | sg_init_table(desc.infrags, 4); | ||
| 734 | sg_init_table(desc.outfrags, 4); | ||
| 735 | |||
| 736 | err = xdr_process_buf(buf, offset + GSS_KRB5_TOK_HDR_LEN, | ||
| 737 | cbcbytes, encryptor, &desc); | ||
| 738 | if (err) | ||
| 739 | goto out_err; | ||
| 740 | } | ||
| 741 | |||
| 742 | /* Make sure IV carries forward from any CBC results. */ | ||
| 743 | err = gss_krb5_cts_crypt(cipher, buf, | ||
| 744 | offset + GSS_KRB5_TOK_HDR_LEN + cbcbytes, | ||
| 745 | desc.iv, pages, 1); | ||
| 746 | if (err) { | ||
| 747 | err = GSS_S_FAILURE; | ||
| 748 | goto out_err; | ||
| 749 | } | ||
| 750 | |||
| 751 | /* Now update buf to account for HMAC */ | ||
| 752 | buf->tail[0].iov_len += kctx->gk5e->cksumlength; | ||
| 753 | buf->len += kctx->gk5e->cksumlength; | ||
| 754 | |||
| 755 | out_err: | ||
| 756 | if (err) | ||
| 757 | err = GSS_S_FAILURE; | ||
| 758 | return err; | ||
| 759 | } | ||
| 760 | |||
| 761 | u32 | ||
| 762 | gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, | ||
| 763 | u32 *headskip, u32 *tailskip) | ||
| 764 | { | ||
| 765 | struct xdr_buf subbuf; | ||
| 766 | u32 ret = 0; | ||
| 767 | u8 *cksum_key; | ||
| 768 | struct crypto_blkcipher *cipher, *aux_cipher; | ||
| 769 | struct xdr_netobj our_hmac_obj; | ||
| 770 | u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 771 | u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 772 | int nblocks, blocksize, cbcbytes; | ||
| 773 | struct decryptor_desc desc; | ||
| 774 | unsigned int usage; | ||
| 775 | |||
| 776 | if (kctx->initiate) { | ||
| 777 | cipher = kctx->acceptor_enc; | ||
| 778 | aux_cipher = kctx->acceptor_enc_aux; | ||
| 779 | cksum_key = kctx->acceptor_integ; | ||
| 780 | usage = KG_USAGE_ACCEPTOR_SEAL; | ||
| 781 | } else { | ||
| 782 | cipher = kctx->initiator_enc; | ||
| 783 | aux_cipher = kctx->initiator_enc_aux; | ||
| 784 | cksum_key = kctx->initiator_integ; | ||
| 785 | usage = KG_USAGE_INITIATOR_SEAL; | ||
| 786 | } | ||
| 787 | blocksize = crypto_blkcipher_blocksize(cipher); | ||
| 788 | |||
| 789 | |||
| 790 | /* create a segment skipping the header and leaving out the checksum */ | ||
| 791 | xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN, | ||
| 792 | (buf->len - offset - GSS_KRB5_TOK_HDR_LEN - | ||
| 793 | kctx->gk5e->cksumlength)); | ||
| 794 | |||
| 795 | nblocks = (subbuf.len + blocksize - 1) / blocksize; | ||
| 796 | |||
| 797 | cbcbytes = 0; | ||
| 798 | if (nblocks > 2) | ||
| 799 | cbcbytes = (nblocks - 2) * blocksize; | ||
| 800 | |||
| 801 | memset(desc.iv, 0, sizeof(desc.iv)); | ||
| 802 | |||
| 803 | if (cbcbytes) { | ||
| 804 | desc.fragno = 0; | ||
| 805 | desc.fraglen = 0; | ||
| 806 | desc.desc.info = desc.iv; | ||
| 807 | desc.desc.flags = 0; | ||
| 808 | desc.desc.tfm = aux_cipher; | ||
| 809 | |||
| 810 | sg_init_table(desc.frags, 4); | ||
| 811 | |||
| 812 | ret = xdr_process_buf(&subbuf, 0, cbcbytes, decryptor, &desc); | ||
| 813 | if (ret) | ||
| 814 | goto out_err; | ||
| 815 | } | ||
| 816 | |||
| 817 | /* Make sure IV carries forward from any CBC results. */ | ||
| 818 | ret = gss_krb5_cts_crypt(cipher, &subbuf, cbcbytes, desc.iv, NULL, 0); | ||
| 819 | if (ret) | ||
| 820 | goto out_err; | ||
| 821 | |||
| 822 | |||
| 823 | /* Calculate our hmac over the plaintext data */ | ||
| 824 | our_hmac_obj.len = sizeof(our_hmac); | ||
| 825 | our_hmac_obj.data = our_hmac; | ||
| 826 | |||
| 827 | ret = make_checksum_v2(kctx, NULL, 0, &subbuf, 0, | ||
| 828 | cksum_key, usage, &our_hmac_obj); | ||
| 829 | if (ret) | ||
| 830 | goto out_err; | ||
| 831 | |||
| 832 | /* Get the packet's hmac value */ | ||
| 833 | ret = read_bytes_from_xdr_buf(buf, buf->len - kctx->gk5e->cksumlength, | ||
| 834 | pkt_hmac, kctx->gk5e->cksumlength); | ||
| 835 | if (ret) | ||
| 836 | goto out_err; | ||
| 837 | |||
| 838 | if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) { | ||
| 839 | ret = GSS_S_BAD_SIG; | ||
| 840 | goto out_err; | ||
| 841 | } | ||
| 842 | *headskip = kctx->gk5e->conflen; | ||
| 843 | *tailskip = kctx->gk5e->cksumlength; | ||
| 844 | out_err: | ||
| 845 | if (ret && ret != GSS_S_BAD_SIG) | ||
| 846 | ret = GSS_S_FAILURE; | ||
| 847 | return ret; | ||
| 848 | } | ||
| 849 | |||
| 850 | /* | ||
| 851 | * Compute Kseq given the initial session key and the checksum. | ||
| 852 | * Set the key of the given cipher. | ||
| 853 | */ | ||
| 854 | int | ||
| 855 | krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher, | ||
| 856 | unsigned char *cksum) | ||
| 857 | { | ||
| 858 | struct crypto_hash *hmac; | ||
| 859 | struct hash_desc desc; | ||
| 860 | struct scatterlist sg[1]; | ||
| 861 | u8 Kseq[GSS_KRB5_MAX_KEYLEN]; | ||
| 862 | u32 zeroconstant = 0; | ||
| 863 | int err; | ||
| 864 | |||
| 865 | dprintk("%s: entered\n", __func__); | ||
| 866 | |||
| 867 | hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
| 868 | if (IS_ERR(hmac)) { | ||
| 869 | dprintk("%s: error %ld, allocating hash '%s'\n", | ||
| 870 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | ||
| 871 | return PTR_ERR(hmac); | ||
| 872 | } | ||
| 873 | |||
| 874 | desc.tfm = hmac; | ||
| 875 | desc.flags = 0; | ||
| 876 | |||
| 877 | err = crypto_hash_init(&desc); | ||
| 878 | if (err) | ||
| 879 | goto out_err; | ||
| 880 | |||
| 881 | /* Compute intermediate Kseq from session key */ | ||
| 882 | err = crypto_hash_setkey(hmac, kctx->Ksess, kctx->gk5e->keylength); | ||
| 883 | if (err) | ||
| 884 | goto out_err; | ||
| 885 | |||
| 886 | sg_init_table(sg, 1); | ||
| 887 | sg_set_buf(sg, &zeroconstant, 4); | ||
| 888 | |||
| 889 | err = crypto_hash_digest(&desc, sg, 4, Kseq); | ||
| 890 | if (err) | ||
| 891 | goto out_err; | ||
| 892 | |||
| 893 | /* Compute final Kseq from the checksum and intermediate Kseq */ | ||
| 894 | err = crypto_hash_setkey(hmac, Kseq, kctx->gk5e->keylength); | ||
| 895 | if (err) | ||
| 896 | goto out_err; | ||
| 897 | |||
| 898 | sg_set_buf(sg, cksum, 8); | ||
| 899 | |||
| 900 | err = crypto_hash_digest(&desc, sg, 8, Kseq); | ||
| 901 | if (err) | ||
| 902 | goto out_err; | ||
| 903 | |||
| 904 | err = crypto_blkcipher_setkey(cipher, Kseq, kctx->gk5e->keylength); | ||
| 905 | if (err) | ||
| 906 | goto out_err; | ||
| 907 | |||
| 908 | err = 0; | ||
| 909 | |||
| 910 | out_err: | ||
| 911 | crypto_free_hash(hmac); | ||
| 912 | dprintk("%s: returning %d\n", __func__, err); | ||
| 913 | return err; | ||
| 914 | } | ||
| 915 | |||
| 916 | /* | ||
| 917 | * Compute Kcrypt given the initial session key and the plaintext seqnum. | ||
| 918 | * Set the key of cipher kctx->enc. | ||
| 919 | */ | ||
| 920 | int | ||
| 921 | krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, struct crypto_blkcipher *cipher, | ||
| 922 | s32 seqnum) | ||
| 923 | { | ||
| 924 | struct crypto_hash *hmac; | ||
| 925 | struct hash_desc desc; | ||
| 926 | struct scatterlist sg[1]; | ||
| 927 | u8 Kcrypt[GSS_KRB5_MAX_KEYLEN]; | ||
| 928 | u8 zeroconstant[4] = {0}; | ||
| 929 | u8 seqnumarray[4]; | ||
| 930 | int err, i; | ||
| 931 | |||
| 932 | dprintk("%s: entered, seqnum %u\n", __func__, seqnum); | ||
| 933 | |||
| 934 | hmac = crypto_alloc_hash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
| 935 | if (IS_ERR(hmac)) { | ||
| 936 | dprintk("%s: error %ld, allocating hash '%s'\n", | ||
| 937 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | ||
| 938 | return PTR_ERR(hmac); | ||
| 939 | } | ||
| 940 | |||
| 941 | desc.tfm = hmac; | ||
| 942 | desc.flags = 0; | ||
| 943 | |||
| 944 | err = crypto_hash_init(&desc); | ||
| 945 | if (err) | ||
| 946 | goto out_err; | ||
| 947 | |||
| 948 | /* Compute intermediate Kcrypt from session key */ | ||
| 949 | for (i = 0; i < kctx->gk5e->keylength; i++) | ||
| 950 | Kcrypt[i] = kctx->Ksess[i] ^ 0xf0; | ||
| 951 | |||
| 952 | err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); | ||
| 953 | if (err) | ||
| 954 | goto out_err; | ||
| 955 | |||
| 956 | sg_init_table(sg, 1); | ||
| 957 | sg_set_buf(sg, zeroconstant, 4); | ||
| 958 | |||
| 959 | err = crypto_hash_digest(&desc, sg, 4, Kcrypt); | ||
| 960 | if (err) | ||
| 961 | goto out_err; | ||
| 962 | |||
| 963 | /* Compute final Kcrypt from the seqnum and intermediate Kcrypt */ | ||
| 964 | err = crypto_hash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); | ||
| 965 | if (err) | ||
| 966 | goto out_err; | ||
| 967 | |||
| 968 | seqnumarray[0] = (unsigned char) ((seqnum >> 24) & 0xff); | ||
| 969 | seqnumarray[1] = (unsigned char) ((seqnum >> 16) & 0xff); | ||
| 970 | seqnumarray[2] = (unsigned char) ((seqnum >> 8) & 0xff); | ||
| 971 | seqnumarray[3] = (unsigned char) ((seqnum >> 0) & 0xff); | ||
| 972 | |||
| 973 | sg_set_buf(sg, seqnumarray, 4); | ||
| 974 | |||
| 975 | err = crypto_hash_digest(&desc, sg, 4, Kcrypt); | ||
| 976 | if (err) | ||
| 977 | goto out_err; | ||
| 978 | |||
| 979 | err = crypto_blkcipher_setkey(cipher, Kcrypt, kctx->gk5e->keylength); | ||
| 980 | if (err) | ||
| 981 | goto out_err; | ||
| 982 | |||
| 983 | err = 0; | ||
| 984 | |||
| 985 | out_err: | ||
| 986 | crypto_free_hash(hmac); | ||
| 987 | dprintk("%s: returning %d\n", __func__, err); | ||
| 988 | return err; | ||
| 989 | } | ||
| 990 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c new file mode 100644 index 000000000000..76e42e6be755 --- /dev/null +++ b/net/sunrpc/auth_gss/gss_krb5_keys.c | |||
| @@ -0,0 +1,336 @@ | |||
| 1 | /* | ||
| 2 | * COPYRIGHT (c) 2008 | ||
| 3 | * The Regents of the University of Michigan | ||
| 4 | * ALL RIGHTS RESERVED | ||
| 5 | * | ||
| 6 | * Permission is granted to use, copy, create derivative works | ||
| 7 | * and redistribute this software and such derivative works | ||
| 8 | * for any purpose, so long as the name of The University of | ||
| 9 | * Michigan is not used in any advertising or publicity | ||
| 10 | * pertaining to the use of distribution of this software | ||
| 11 | * without specific, written prior authorization. If the | ||
| 12 | * above copyright notice or any other identification of the | ||
| 13 | * University of Michigan is included in any copy of any | ||
| 14 | * portion of this software, then the disclaimer below must | ||
| 15 | * also be included. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION | ||
| 18 | * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY | ||
| 19 | * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF | ||
| 20 | * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING | ||
| 21 | * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF | ||
| 22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | ||
| 23 | * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE | ||
| 24 | * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR | ||
| 25 | * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING | ||
| 26 | * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN | ||
| 27 | * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF | ||
| 28 | * SUCH DAMAGES. | ||
| 29 | */ | ||
| 30 | |||
| 31 | /* | ||
| 32 | * Copyright (C) 1998 by the FundsXpress, INC. | ||
| 33 | * | ||
| 34 | * All rights reserved. | ||
| 35 | * | ||
| 36 | * Export of this software from the United States of America may require | ||
| 37 | * a specific license from the United States Government. It is the | ||
| 38 | * responsibility of any person or organization contemplating export to | ||
| 39 | * obtain such a license before exporting. | ||
| 40 | * | ||
| 41 | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and | ||
| 42 | * distribute this software and its documentation for any purpose and | ||
| 43 | * without fee is hereby granted, provided that the above copyright | ||
| 44 | * notice appear in all copies and that both that copyright notice and | ||
| 45 | * this permission notice appear in supporting documentation, and that | ||
| 46 | * the name of FundsXpress. not be used in advertising or publicity pertaining | ||
| 47 | * to distribution of the software without specific, written prior | ||
| 48 | * permission. FundsXpress makes no representations about the suitability of | ||
| 49 | * this software for any purpose. It is provided "as is" without express | ||
| 50 | * or implied warranty. | ||
| 51 | * | ||
| 52 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
| 53 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
| 54 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
| 55 | */ | ||
| 56 | |||
| 57 | #include <linux/err.h> | ||
| 58 | #include <linux/types.h> | ||
| 59 | #include <linux/crypto.h> | ||
| 60 | #include <linux/sunrpc/gss_krb5.h> | ||
| 61 | #include <linux/sunrpc/xdr.h> | ||
| 62 | |||
| 63 | #ifdef RPC_DEBUG | ||
| 64 | # define RPCDBG_FACILITY RPCDBG_AUTH | ||
| 65 | #endif | ||
| 66 | |||
| 67 | /* | ||
| 68 | * This is the n-fold function as described in rfc3961, sec 5.1 | ||
| 69 | * Taken from MIT Kerberos and modified. | ||
| 70 | */ | ||
| 71 | |||
| 72 | static void krb5_nfold(u32 inbits, const u8 *in, | ||
| 73 | u32 outbits, u8 *out) | ||
| 74 | { | ||
| 75 | int a, b, c, lcm; | ||
| 76 | int byte, i, msbit; | ||
| 77 | |||
| 78 | /* the code below is more readable if I make these bytes | ||
| 79 | instead of bits */ | ||
| 80 | |||
| 81 | inbits >>= 3; | ||
| 82 | outbits >>= 3; | ||
| 83 | |||
| 84 | /* first compute lcm(n,k) */ | ||
| 85 | |||
| 86 | a = outbits; | ||
| 87 | b = inbits; | ||
| 88 | |||
| 89 | while (b != 0) { | ||
| 90 | c = b; | ||
| 91 | b = a%b; | ||
| 92 | a = c; | ||
| 93 | } | ||
| 94 | |||
| 95 | lcm = outbits*inbits/a; | ||
| 96 | |||
| 97 | /* now do the real work */ | ||
| 98 | |||
| 99 | memset(out, 0, outbits); | ||
| 100 | byte = 0; | ||
| 101 | |||
| 102 | /* this will end up cycling through k lcm(k,n)/k times, which | ||
| 103 | is correct */ | ||
| 104 | for (i = lcm-1; i >= 0; i--) { | ||
| 105 | /* compute the msbit in k which gets added into this byte */ | ||
| 106 | msbit = ( | ||
| 107 | /* first, start with the msbit in the first, | ||
| 108 | * unrotated byte */ | ||
| 109 | ((inbits << 3) - 1) | ||
| 110 | /* then, for each byte, shift to the right | ||
| 111 | * for each repetition */ | ||
| 112 | + (((inbits << 3) + 13) * (i/inbits)) | ||
| 113 | /* last, pick out the correct byte within | ||
| 114 | * that shifted repetition */ | ||
| 115 | + ((inbits - (i % inbits)) << 3) | ||
| 116 | ) % (inbits << 3); | ||
| 117 | |||
| 118 | /* pull out the byte value itself */ | ||
| 119 | byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| | ||
| 120 | (in[((inbits) - (msbit >> 3)) % inbits])) | ||
| 121 | >> ((msbit & 7) + 1)) & 0xff; | ||
| 122 | |||
| 123 | /* do the addition */ | ||
| 124 | byte += out[i % outbits]; | ||
| 125 | out[i % outbits] = byte & 0xff; | ||
| 126 | |||
| 127 | /* keep around the carry bit, if any */ | ||
| 128 | byte >>= 8; | ||
| 129 | |||
| 130 | } | ||
| 131 | |||
| 132 | /* if there's a carry bit left over, add it back in */ | ||
| 133 | if (byte) { | ||
| 134 | for (i = outbits - 1; i >= 0; i--) { | ||
| 135 | /* do the addition */ | ||
| 136 | byte += out[i]; | ||
| 137 | out[i] = byte & 0xff; | ||
| 138 | |||
| 139 | /* keep around the carry bit, if any */ | ||
| 140 | byte >>= 8; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | /* | ||
| 146 | * This is the DK (derive_key) function as described in rfc3961, sec 5.1 | ||
| 147 | * Taken from MIT Kerberos and modified. | ||
| 148 | */ | ||
| 149 | |||
| 150 | u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, | ||
| 151 | const struct xdr_netobj *inkey, | ||
| 152 | struct xdr_netobj *outkey, | ||
| 153 | const struct xdr_netobj *in_constant, | ||
| 154 | gfp_t gfp_mask) | ||
| 155 | { | ||
| 156 | size_t blocksize, keybytes, keylength, n; | ||
| 157 | unsigned char *inblockdata, *outblockdata, *rawkey; | ||
| 158 | struct xdr_netobj inblock, outblock; | ||
| 159 | struct crypto_blkcipher *cipher; | ||
| 160 | u32 ret = EINVAL; | ||
| 161 | |||
| 162 | blocksize = gk5e->blocksize; | ||
| 163 | keybytes = gk5e->keybytes; | ||
| 164 | keylength = gk5e->keylength; | ||
| 165 | |||
| 166 | if ((inkey->len != keylength) || (outkey->len != keylength)) | ||
| 167 | goto err_return; | ||
| 168 | |||
| 169 | cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0, | ||
| 170 | CRYPTO_ALG_ASYNC); | ||
| 171 | if (IS_ERR(cipher)) | ||
| 172 | goto err_return; | ||
| 173 | if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len)) | ||
| 174 | goto err_return; | ||
| 175 | |||
| 176 | /* allocate and set up buffers */ | ||
| 177 | |||
| 178 | ret = ENOMEM; | ||
| 179 | inblockdata = kmalloc(blocksize, gfp_mask); | ||
| 180 | if (inblockdata == NULL) | ||
| 181 | goto err_free_cipher; | ||
| 182 | |||
| 183 | outblockdata = kmalloc(blocksize, gfp_mask); | ||
| 184 | if (outblockdata == NULL) | ||
| 185 | goto err_free_in; | ||
| 186 | |||
| 187 | rawkey = kmalloc(keybytes, gfp_mask); | ||
| 188 | if (rawkey == NULL) | ||
| 189 | goto err_free_out; | ||
| 190 | |||
| 191 | inblock.data = (char *) inblockdata; | ||
| 192 | inblock.len = blocksize; | ||
| 193 | |||
| 194 | outblock.data = (char *) outblockdata; | ||
| 195 | outblock.len = blocksize; | ||
| 196 | |||
| 197 | /* initialize the input block */ | ||
| 198 | |||
| 199 | if (in_constant->len == inblock.len) { | ||
| 200 | memcpy(inblock.data, in_constant->data, inblock.len); | ||
| 201 | } else { | ||
| 202 | krb5_nfold(in_constant->len * 8, in_constant->data, | ||
| 203 | inblock.len * 8, inblock.data); | ||
| 204 | } | ||
| 205 | |||
| 206 | /* loop encrypting the blocks until enough key bytes are generated */ | ||
| 207 | |||
| 208 | n = 0; | ||
| 209 | while (n < keybytes) { | ||
| 210 | (*(gk5e->encrypt))(cipher, NULL, inblock.data, | ||
| 211 | outblock.data, inblock.len); | ||
| 212 | |||
| 213 | if ((keybytes - n) <= outblock.len) { | ||
| 214 | memcpy(rawkey + n, outblock.data, (keybytes - n)); | ||
| 215 | break; | ||
| 216 | } | ||
| 217 | |||
| 218 | memcpy(rawkey + n, outblock.data, outblock.len); | ||
| 219 | memcpy(inblock.data, outblock.data, outblock.len); | ||
| 220 | n += outblock.len; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* postprocess the key */ | ||
| 224 | |||
| 225 | inblock.data = (char *) rawkey; | ||
| 226 | inblock.len = keybytes; | ||
| 227 | |||
| 228 | BUG_ON(gk5e->mk_key == NULL); | ||
| 229 | ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey); | ||
| 230 | if (ret) { | ||
| 231 | dprintk("%s: got %d from mk_key function for '%s'\n", | ||
| 232 | __func__, ret, gk5e->encrypt_name); | ||
| 233 | goto err_free_raw; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* clean memory, free resources and exit */ | ||
| 237 | |||
| 238 | ret = 0; | ||
| 239 | |||
| 240 | err_free_raw: | ||
| 241 | memset(rawkey, 0, keybytes); | ||
| 242 | kfree(rawkey); | ||
| 243 | err_free_out: | ||
| 244 | memset(outblockdata, 0, blocksize); | ||
| 245 | kfree(outblockdata); | ||
| 246 | err_free_in: | ||
| 247 | memset(inblockdata, 0, blocksize); | ||
| 248 | kfree(inblockdata); | ||
| 249 | err_free_cipher: | ||
| 250 | crypto_free_blkcipher(cipher); | ||
| 251 | err_return: | ||
| 252 | return ret; | ||
| 253 | } | ||
| 254 | |||
| 255 | #define smask(step) ((1<<step)-1) | ||
| 256 | #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) | ||
| 257 | #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) | ||
| 258 | |||
| 259 | static void mit_des_fixup_key_parity(u8 key[8]) | ||
| 260 | { | ||
| 261 | int i; | ||
| 262 | for (i = 0; i < 8; i++) { | ||
| 263 | key[i] &= 0xfe; | ||
| 264 | key[i] |= 1^parity_char(key[i]); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | /* | ||
| 269 | * This is the des3 key derivation postprocess function | ||
| 270 | */ | ||
| 271 | u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, | ||
| 272 | struct xdr_netobj *randombits, | ||
| 273 | struct xdr_netobj *key) | ||
| 274 | { | ||
| 275 | int i; | ||
| 276 | u32 ret = EINVAL; | ||
| 277 | |||
| 278 | if (key->len != 24) { | ||
| 279 | dprintk("%s: key->len is %d\n", __func__, key->len); | ||
| 280 | goto err_out; | ||
| 281 | } | ||
| 282 | if (randombits->len != 21) { | ||
| 283 | dprintk("%s: randombits->len is %d\n", | ||
| 284 | __func__, randombits->len); | ||
| 285 | goto err_out; | ||
| 286 | } | ||
| 287 | |||
| 288 | /* take the seven bytes, move them around into the top 7 bits of the | ||
| 289 | 8 key bytes, then compute the parity bits. Do this three times. */ | ||
| 290 | |||
| 291 | for (i = 0; i < 3; i++) { | ||
| 292 | memcpy(key->data + i*8, randombits->data + i*7, 7); | ||
| 293 | key->data[i*8+7] = (((key->data[i*8]&1)<<1) | | ||
| 294 | ((key->data[i*8+1]&1)<<2) | | ||
| 295 | ((key->data[i*8+2]&1)<<3) | | ||
| 296 | ((key->data[i*8+3]&1)<<4) | | ||
| 297 | ((key->data[i*8+4]&1)<<5) | | ||
| 298 | ((key->data[i*8+5]&1)<<6) | | ||
| 299 | ((key->data[i*8+6]&1)<<7)); | ||
| 300 | |||
| 301 | mit_des_fixup_key_parity(key->data + i*8); | ||
| 302 | } | ||
| 303 | ret = 0; | ||
| 304 | err_out: | ||
| 305 | return ret; | ||
| 306 | } | ||
| 307 | |||
| 308 | /* | ||
| 309 | * This is the aes key derivation postprocess function | ||
| 310 | */ | ||
| 311 | u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | ||
| 312 | struct xdr_netobj *randombits, | ||
| 313 | struct xdr_netobj *key) | ||
| 314 | { | ||
| 315 | u32 ret = EINVAL; | ||
| 316 | |||
| 317 | if (key->len != 16 && key->len != 32) { | ||
| 318 | dprintk("%s: key->len is %d\n", __func__, key->len); | ||
| 319 | goto err_out; | ||
| 320 | } | ||
| 321 | if (randombits->len != 16 && randombits->len != 32) { | ||
| 322 | dprintk("%s: randombits->len is %d\n", | ||
| 323 | __func__, randombits->len); | ||
| 324 | goto err_out; | ||
| 325 | } | ||
| 326 | if (randombits->len != key->len) { | ||
| 327 | dprintk("%s: randombits->len is %d, key->len is %d\n", | ||
| 328 | __func__, randombits->len, key->len); | ||
| 329 | goto err_out; | ||
| 330 | } | ||
| 331 | memcpy(key->data, randombits->data, key->len); | ||
| 332 | ret = 0; | ||
| 333 | err_out: | ||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index 2deb0ed72ff4..032644610524 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/net/sunrpc/gss_krb5_mech.c | 2 | * linux/net/sunrpc/gss_krb5_mech.c |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2001 The Regents of the University of Michigan. | 4 | * Copyright (c) 2001-2008 The Regents of the University of Michigan. |
| 5 | * All rights reserved. | 5 | * All rights reserved. |
| 6 | * | 6 | * |
| 7 | * Andy Adamson <andros@umich.edu> | 7 | * Andy Adamson <andros@umich.edu> |
| @@ -48,6 +48,143 @@ | |||
| 48 | # define RPCDBG_FACILITY RPCDBG_AUTH | 48 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| 49 | #endif | 49 | #endif |
| 50 | 50 | ||
| 51 | static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ | ||
| 52 | |||
| 53 | static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { | ||
| 54 | /* | ||
| 55 | * DES (All DES enctypes are mapped to the same gss functionality) | ||
| 56 | */ | ||
| 57 | { | ||
| 58 | .etype = ENCTYPE_DES_CBC_RAW, | ||
| 59 | .ctype = CKSUMTYPE_RSA_MD5, | ||
| 60 | .name = "des-cbc-crc", | ||
| 61 | .encrypt_name = "cbc(des)", | ||
| 62 | .cksum_name = "md5", | ||
| 63 | .encrypt = krb5_encrypt, | ||
| 64 | .decrypt = krb5_decrypt, | ||
| 65 | .mk_key = NULL, | ||
| 66 | .signalg = SGN_ALG_DES_MAC_MD5, | ||
| 67 | .sealalg = SEAL_ALG_DES, | ||
| 68 | .keybytes = 7, | ||
| 69 | .keylength = 8, | ||
| 70 | .blocksize = 8, | ||
| 71 | .conflen = 8, | ||
| 72 | .cksumlength = 8, | ||
| 73 | .keyed_cksum = 0, | ||
| 74 | }, | ||
| 75 | /* | ||
| 76 | * RC4-HMAC | ||
| 77 | */ | ||
| 78 | { | ||
| 79 | .etype = ENCTYPE_ARCFOUR_HMAC, | ||
| 80 | .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR, | ||
| 81 | .name = "rc4-hmac", | ||
| 82 | .encrypt_name = "ecb(arc4)", | ||
| 83 | .cksum_name = "hmac(md5)", | ||
| 84 | .encrypt = krb5_encrypt, | ||
| 85 | .decrypt = krb5_decrypt, | ||
| 86 | .mk_key = NULL, | ||
| 87 | .signalg = SGN_ALG_HMAC_MD5, | ||
| 88 | .sealalg = SEAL_ALG_MICROSOFT_RC4, | ||
| 89 | .keybytes = 16, | ||
| 90 | .keylength = 16, | ||
| 91 | .blocksize = 1, | ||
| 92 | .conflen = 8, | ||
| 93 | .cksumlength = 8, | ||
| 94 | .keyed_cksum = 1, | ||
| 95 | }, | ||
| 96 | /* | ||
| 97 | * 3DES | ||
| 98 | */ | ||
| 99 | { | ||
| 100 | .etype = ENCTYPE_DES3_CBC_RAW, | ||
| 101 | .ctype = CKSUMTYPE_HMAC_SHA1_DES3, | ||
| 102 | .name = "des3-hmac-sha1", | ||
| 103 | .encrypt_name = "cbc(des3_ede)", | ||
| 104 | .cksum_name = "hmac(sha1)", | ||
| 105 | .encrypt = krb5_encrypt, | ||
| 106 | .decrypt = krb5_decrypt, | ||
| 107 | .mk_key = gss_krb5_des3_make_key, | ||
| 108 | .signalg = SGN_ALG_HMAC_SHA1_DES3_KD, | ||
| 109 | .sealalg = SEAL_ALG_DES3KD, | ||
| 110 | .keybytes = 21, | ||
| 111 | .keylength = 24, | ||
| 112 | .blocksize = 8, | ||
| 113 | .conflen = 8, | ||
| 114 | .cksumlength = 20, | ||
| 115 | .keyed_cksum = 1, | ||
| 116 | }, | ||
| 117 | /* | ||
| 118 | * AES128 | ||
| 119 | */ | ||
| 120 | { | ||
| 121 | .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, | ||
| 122 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, | ||
| 123 | .name = "aes128-cts", | ||
| 124 | .encrypt_name = "cts(cbc(aes))", | ||
| 125 | .cksum_name = "hmac(sha1)", | ||
| 126 | .encrypt = krb5_encrypt, | ||
| 127 | .decrypt = krb5_decrypt, | ||
| 128 | .mk_key = gss_krb5_aes_make_key, | ||
| 129 | .encrypt_v2 = gss_krb5_aes_encrypt, | ||
| 130 | .decrypt_v2 = gss_krb5_aes_decrypt, | ||
| 131 | .signalg = -1, | ||
| 132 | .sealalg = -1, | ||
| 133 | .keybytes = 16, | ||
| 134 | .keylength = 16, | ||
| 135 | .blocksize = 16, | ||
| 136 | .conflen = 16, | ||
| 137 | .cksumlength = 12, | ||
| 138 | .keyed_cksum = 1, | ||
| 139 | }, | ||
| 140 | /* | ||
| 141 | * AES256 | ||
| 142 | */ | ||
| 143 | { | ||
| 144 | .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, | ||
| 145 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, | ||
| 146 | .name = "aes256-cts", | ||
| 147 | .encrypt_name = "cts(cbc(aes))", | ||
| 148 | .cksum_name = "hmac(sha1)", | ||
| 149 | .encrypt = krb5_encrypt, | ||
| 150 | .decrypt = krb5_decrypt, | ||
| 151 | .mk_key = gss_krb5_aes_make_key, | ||
| 152 | .encrypt_v2 = gss_krb5_aes_encrypt, | ||
| 153 | .decrypt_v2 = gss_krb5_aes_decrypt, | ||
| 154 | .signalg = -1, | ||
| 155 | .sealalg = -1, | ||
| 156 | .keybytes = 32, | ||
| 157 | .keylength = 32, | ||
| 158 | .blocksize = 16, | ||
| 159 | .conflen = 16, | ||
| 160 | .cksumlength = 12, | ||
| 161 | .keyed_cksum = 1, | ||
| 162 | }, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static const int num_supported_enctypes = | ||
| 166 | ARRAY_SIZE(supported_gss_krb5_enctypes); | ||
| 167 | |||
| 168 | static int | ||
| 169 | supported_gss_krb5_enctype(int etype) | ||
| 170 | { | ||
| 171 | int i; | ||
| 172 | for (i = 0; i < num_supported_enctypes; i++) | ||
| 173 | if (supported_gss_krb5_enctypes[i].etype == etype) | ||
| 174 | return 1; | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | static const struct gss_krb5_enctype * | ||
| 179 | get_gss_krb5_enctype(int etype) | ||
| 180 | { | ||
| 181 | int i; | ||
| 182 | for (i = 0; i < num_supported_enctypes; i++) | ||
| 183 | if (supported_gss_krb5_enctypes[i].etype == etype) | ||
| 184 | return &supported_gss_krb5_enctypes[i]; | ||
| 185 | return NULL; | ||
| 186 | } | ||
| 187 | |||
| 51 | static const void * | 188 | static const void * |
| 52 | simple_get_bytes(const void *p, const void *end, void *res, int len) | 189 | simple_get_bytes(const void *p, const void *end, void *res, int len) |
| 53 | { | 190 | { |
| @@ -78,35 +215,45 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) | |||
| 78 | } | 215 | } |
| 79 | 216 | ||
| 80 | static inline const void * | 217 | static inline const void * |
| 81 | get_key(const void *p, const void *end, struct crypto_blkcipher **res) | 218 | get_key(const void *p, const void *end, |
| 219 | struct krb5_ctx *ctx, struct crypto_blkcipher **res) | ||
| 82 | { | 220 | { |
| 83 | struct xdr_netobj key; | 221 | struct xdr_netobj key; |
| 84 | int alg; | 222 | int alg; |
| 85 | char *alg_name; | ||
| 86 | 223 | ||
| 87 | p = simple_get_bytes(p, end, &alg, sizeof(alg)); | 224 | p = simple_get_bytes(p, end, &alg, sizeof(alg)); |
| 88 | if (IS_ERR(p)) | 225 | if (IS_ERR(p)) |
| 89 | goto out_err; | 226 | goto out_err; |
| 227 | |||
| 228 | switch (alg) { | ||
| 229 | case ENCTYPE_DES_CBC_CRC: | ||
| 230 | case ENCTYPE_DES_CBC_MD4: | ||
| 231 | case ENCTYPE_DES_CBC_MD5: | ||
| 232 | /* Map all these key types to ENCTYPE_DES_CBC_RAW */ | ||
| 233 | alg = ENCTYPE_DES_CBC_RAW; | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | |||
| 237 | if (!supported_gss_krb5_enctype(alg)) { | ||
| 238 | printk(KERN_WARNING "gss_kerberos_mech: unsupported " | ||
| 239 | "encryption key algorithm %d\n", alg); | ||
| 240 | goto out_err; | ||
| 241 | } | ||
| 90 | p = simple_get_netobj(p, end, &key); | 242 | p = simple_get_netobj(p, end, &key); |
| 91 | if (IS_ERR(p)) | 243 | if (IS_ERR(p)) |
| 92 | goto out_err; | 244 | goto out_err; |
| 93 | 245 | ||
| 94 | switch (alg) { | 246 | *res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, |
| 95 | case ENCTYPE_DES_CBC_RAW: | 247 | CRYPTO_ALG_ASYNC); |
| 96 | alg_name = "cbc(des)"; | ||
| 97 | break; | ||
| 98 | default: | ||
| 99 | printk("gss_kerberos_mech: unsupported algorithm %d\n", alg); | ||
| 100 | goto out_err_free_key; | ||
| 101 | } | ||
| 102 | *res = crypto_alloc_blkcipher(alg_name, 0, CRYPTO_ALG_ASYNC); | ||
| 103 | if (IS_ERR(*res)) { | 248 | if (IS_ERR(*res)) { |
| 104 | printk("gss_kerberos_mech: unable to initialize crypto algorithm %s\n", alg_name); | 249 | printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " |
| 250 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | ||
| 105 | *res = NULL; | 251 | *res = NULL; |
| 106 | goto out_err_free_key; | 252 | goto out_err_free_key; |
| 107 | } | 253 | } |
| 108 | if (crypto_blkcipher_setkey(*res, key.data, key.len)) { | 254 | if (crypto_blkcipher_setkey(*res, key.data, key.len)) { |
| 109 | printk("gss_kerberos_mech: error setting key for crypto algorithm %s\n", alg_name); | 255 | printk(KERN_WARNING "gss_kerberos_mech: error setting key for " |
| 256 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | ||
| 110 | goto out_err_free_tfm; | 257 | goto out_err_free_tfm; |
| 111 | } | 258 | } |
| 112 | 259 | ||
| @@ -123,56 +270,55 @@ out_err: | |||
| 123 | } | 270 | } |
| 124 | 271 | ||
| 125 | static int | 272 | static int |
| 126 | gss_import_sec_context_kerberos(const void *p, | 273 | gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) |
| 127 | size_t len, | ||
| 128 | struct gss_ctx *ctx_id) | ||
| 129 | { | 274 | { |
| 130 | const void *end = (const void *)((const char *)p + len); | ||
| 131 | struct krb5_ctx *ctx; | ||
| 132 | int tmp; | 275 | int tmp; |
| 133 | 276 | ||
| 134 | if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) { | ||
| 135 | p = ERR_PTR(-ENOMEM); | ||
| 136 | goto out_err; | ||
| 137 | } | ||
| 138 | |||
| 139 | p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); | 277 | p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); |
| 140 | if (IS_ERR(p)) | 278 | if (IS_ERR(p)) |
| 141 | goto out_err_free_ctx; | 279 | goto out_err; |
| 280 | |||
| 281 | /* Old format supports only DES! Any other enctype uses new format */ | ||
| 282 | ctx->enctype = ENCTYPE_DES_CBC_RAW; | ||
| 283 | |||
| 284 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); | ||
| 285 | if (ctx->gk5e == NULL) | ||
| 286 | goto out_err; | ||
| 287 | |||
| 142 | /* The downcall format was designed before we completely understood | 288 | /* The downcall format was designed before we completely understood |
| 143 | * the uses of the context fields; so it includes some stuff we | 289 | * the uses of the context fields; so it includes some stuff we |
| 144 | * just give some minimal sanity-checking, and some we ignore | 290 | * just give some minimal sanity-checking, and some we ignore |
| 145 | * completely (like the next twenty bytes): */ | 291 | * completely (like the next twenty bytes): */ |
| 146 | if (unlikely(p + 20 > end || p + 20 < p)) | 292 | if (unlikely(p + 20 > end || p + 20 < p)) |
| 147 | goto out_err_free_ctx; | 293 | goto out_err; |
| 148 | p += 20; | 294 | p += 20; |
| 149 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); | 295 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
| 150 | if (IS_ERR(p)) | 296 | if (IS_ERR(p)) |
| 151 | goto out_err_free_ctx; | 297 | goto out_err; |
| 152 | if (tmp != SGN_ALG_DES_MAC_MD5) { | 298 | if (tmp != SGN_ALG_DES_MAC_MD5) { |
| 153 | p = ERR_PTR(-ENOSYS); | 299 | p = ERR_PTR(-ENOSYS); |
| 154 | goto out_err_free_ctx; | 300 | goto out_err; |
| 155 | } | 301 | } |
| 156 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); | 302 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
| 157 | if (IS_ERR(p)) | 303 | if (IS_ERR(p)) |
| 158 | goto out_err_free_ctx; | 304 | goto out_err; |
| 159 | if (tmp != SEAL_ALG_DES) { | 305 | if (tmp != SEAL_ALG_DES) { |
| 160 | p = ERR_PTR(-ENOSYS); | 306 | p = ERR_PTR(-ENOSYS); |
| 161 | goto out_err_free_ctx; | 307 | goto out_err; |
| 162 | } | 308 | } |
| 163 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); | 309 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); |
| 164 | if (IS_ERR(p)) | 310 | if (IS_ERR(p)) |
| 165 | goto out_err_free_ctx; | 311 | goto out_err; |
| 166 | p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); | 312 | p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); |
| 167 | if (IS_ERR(p)) | 313 | if (IS_ERR(p)) |
| 168 | goto out_err_free_ctx; | 314 | goto out_err; |
| 169 | p = simple_get_netobj(p, end, &ctx->mech_used); | 315 | p = simple_get_netobj(p, end, &ctx->mech_used); |
| 170 | if (IS_ERR(p)) | 316 | if (IS_ERR(p)) |
| 171 | goto out_err_free_ctx; | 317 | goto out_err; |
| 172 | p = get_key(p, end, &ctx->enc); | 318 | p = get_key(p, end, ctx, &ctx->enc); |
| 173 | if (IS_ERR(p)) | 319 | if (IS_ERR(p)) |
| 174 | goto out_err_free_mech; | 320 | goto out_err_free_mech; |
| 175 | p = get_key(p, end, &ctx->seq); | 321 | p = get_key(p, end, ctx, &ctx->seq); |
| 176 | if (IS_ERR(p)) | 322 | if (IS_ERR(p)) |
| 177 | goto out_err_free_key1; | 323 | goto out_err_free_key1; |
| 178 | if (p != end) { | 324 | if (p != end) { |
| @@ -180,9 +326,6 @@ gss_import_sec_context_kerberos(const void *p, | |||
| 180 | goto out_err_free_key2; | 326 | goto out_err_free_key2; |
| 181 | } | 327 | } |
| 182 | 328 | ||
| 183 | ctx_id->internal_ctx_id = ctx; | ||
| 184 | |||
| 185 | dprintk("RPC: Successfully imported new context.\n"); | ||
| 186 | return 0; | 329 | return 0; |
| 187 | 330 | ||
| 188 | out_err_free_key2: | 331 | out_err_free_key2: |
| @@ -191,18 +334,378 @@ out_err_free_key1: | |||
| 191 | crypto_free_blkcipher(ctx->enc); | 334 | crypto_free_blkcipher(ctx->enc); |
| 192 | out_err_free_mech: | 335 | out_err_free_mech: |
| 193 | kfree(ctx->mech_used.data); | 336 | kfree(ctx->mech_used.data); |
| 194 | out_err_free_ctx: | ||
| 195 | kfree(ctx); | ||
| 196 | out_err: | 337 | out_err: |
| 197 | return PTR_ERR(p); | 338 | return PTR_ERR(p); |
| 198 | } | 339 | } |
| 199 | 340 | ||
| 341 | struct crypto_blkcipher * | ||
| 342 | context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) | ||
| 343 | { | ||
| 344 | struct crypto_blkcipher *cp; | ||
| 345 | |||
| 346 | cp = crypto_alloc_blkcipher(cname, 0, CRYPTO_ALG_ASYNC); | ||
| 347 | if (IS_ERR(cp)) { | ||
| 348 | dprintk("gss_kerberos_mech: unable to initialize " | ||
| 349 | "crypto algorithm %s\n", cname); | ||
| 350 | return NULL; | ||
| 351 | } | ||
| 352 | if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) { | ||
| 353 | dprintk("gss_kerberos_mech: error setting key for " | ||
| 354 | "crypto algorithm %s\n", cname); | ||
| 355 | crypto_free_blkcipher(cp); | ||
| 356 | return NULL; | ||
| 357 | } | ||
| 358 | return cp; | ||
| 359 | } | ||
| 360 | |||
| 361 | static inline void | ||
| 362 | set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) | ||
| 363 | { | ||
| 364 | cdata[0] = (usage>>24)&0xff; | ||
| 365 | cdata[1] = (usage>>16)&0xff; | ||
| 366 | cdata[2] = (usage>>8)&0xff; | ||
| 367 | cdata[3] = usage&0xff; | ||
| 368 | cdata[4] = seed; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int | ||
| 372 | context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) | ||
| 373 | { | ||
| 374 | struct xdr_netobj c, keyin, keyout; | ||
| 375 | u8 cdata[GSS_KRB5_K5CLENGTH]; | ||
| 376 | u32 err; | ||
| 377 | |||
| 378 | c.len = GSS_KRB5_K5CLENGTH; | ||
| 379 | c.data = cdata; | ||
| 380 | |||
| 381 | keyin.data = ctx->Ksess; | ||
| 382 | keyin.len = ctx->gk5e->keylength; | ||
| 383 | keyout.len = ctx->gk5e->keylength; | ||
| 384 | |||
| 385 | /* seq uses the raw key */ | ||
| 386 | ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, | ||
| 387 | ctx->Ksess); | ||
| 388 | if (ctx->seq == NULL) | ||
| 389 | goto out_err; | ||
| 390 | |||
| 391 | ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, | ||
| 392 | ctx->Ksess); | ||
| 393 | if (ctx->enc == NULL) | ||
| 394 | goto out_free_seq; | ||
| 395 | |||
| 396 | /* derive cksum */ | ||
| 397 | set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); | ||
| 398 | keyout.data = ctx->cksum; | ||
| 399 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 400 | if (err) { | ||
| 401 | dprintk("%s: Error %d deriving cksum key\n", | ||
| 402 | __func__, err); | ||
| 403 | goto out_free_enc; | ||
| 404 | } | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | |||
| 408 | out_free_enc: | ||
| 409 | crypto_free_blkcipher(ctx->enc); | ||
| 410 | out_free_seq: | ||
| 411 | crypto_free_blkcipher(ctx->seq); | ||
| 412 | out_err: | ||
| 413 | return -EINVAL; | ||
| 414 | } | ||
| 415 | |||
| 416 | /* | ||
| 417 | * Note that RC4 depends on deriving keys using the sequence | ||
| 418 | * number or the checksum of a token. Therefore, the final keys | ||
| 419 | * cannot be calculated until the token is being constructed! | ||
| 420 | */ | ||
| 421 | static int | ||
| 422 | context_derive_keys_rc4(struct krb5_ctx *ctx) | ||
| 423 | { | ||
| 424 | struct crypto_hash *hmac; | ||
| 425 | char sigkeyconstant[] = "signaturekey"; | ||
| 426 | int slen = strlen(sigkeyconstant) + 1; /* include null terminator */ | ||
| 427 | struct hash_desc desc; | ||
| 428 | struct scatterlist sg[1]; | ||
| 429 | int err; | ||
| 430 | |||
| 431 | dprintk("RPC: %s: entered\n", __func__); | ||
| 432 | /* | ||
| 433 | * derive cksum (aka Ksign) key | ||
| 434 | */ | ||
| 435 | hmac = crypto_alloc_hash(ctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | ||
| 436 | if (IS_ERR(hmac)) { | ||
| 437 | dprintk("%s: error %ld allocating hash '%s'\n", | ||
| 438 | __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name); | ||
| 439 | err = PTR_ERR(hmac); | ||
| 440 | goto out_err; | ||
| 441 | } | ||
| 442 | |||
| 443 | err = crypto_hash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength); | ||
| 444 | if (err) | ||
| 445 | goto out_err_free_hmac; | ||
| 446 | |||
| 447 | sg_init_table(sg, 1); | ||
| 448 | sg_set_buf(sg, sigkeyconstant, slen); | ||
| 449 | |||
| 450 | desc.tfm = hmac; | ||
| 451 | desc.flags = 0; | ||
| 452 | |||
| 453 | err = crypto_hash_init(&desc); | ||
| 454 | if (err) | ||
| 455 | goto out_err_free_hmac; | ||
| 456 | |||
| 457 | err = crypto_hash_digest(&desc, sg, slen, ctx->cksum); | ||
| 458 | if (err) | ||
| 459 | goto out_err_free_hmac; | ||
| 460 | /* | ||
| 461 | * allocate hash, and blkciphers for data and seqnum encryption | ||
| 462 | */ | ||
| 463 | ctx->enc = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | ||
| 464 | CRYPTO_ALG_ASYNC); | ||
| 465 | if (IS_ERR(ctx->enc)) { | ||
| 466 | err = PTR_ERR(ctx->enc); | ||
| 467 | goto out_err_free_hmac; | ||
| 468 | } | ||
| 469 | |||
| 470 | ctx->seq = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | ||
| 471 | CRYPTO_ALG_ASYNC); | ||
| 472 | if (IS_ERR(ctx->seq)) { | ||
| 473 | crypto_free_blkcipher(ctx->enc); | ||
| 474 | err = PTR_ERR(ctx->seq); | ||
| 475 | goto out_err_free_hmac; | ||
| 476 | } | ||
| 477 | |||
| 478 | dprintk("RPC: %s: returning success\n", __func__); | ||
| 479 | |||
| 480 | err = 0; | ||
| 481 | |||
| 482 | out_err_free_hmac: | ||
| 483 | crypto_free_hash(hmac); | ||
| 484 | out_err: | ||
| 485 | dprintk("RPC: %s: returning %d\n", __func__, err); | ||
| 486 | return err; | ||
| 487 | } | ||
| 488 | |||
| 489 | static int | ||
| 490 | context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) | ||
| 491 | { | ||
| 492 | struct xdr_netobj c, keyin, keyout; | ||
| 493 | u8 cdata[GSS_KRB5_K5CLENGTH]; | ||
| 494 | u32 err; | ||
| 495 | |||
| 496 | c.len = GSS_KRB5_K5CLENGTH; | ||
| 497 | c.data = cdata; | ||
| 498 | |||
| 499 | keyin.data = ctx->Ksess; | ||
| 500 | keyin.len = ctx->gk5e->keylength; | ||
| 501 | keyout.len = ctx->gk5e->keylength; | ||
| 502 | |||
| 503 | /* initiator seal encryption */ | ||
| 504 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | ||
| 505 | keyout.data = ctx->initiator_seal; | ||
| 506 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 507 | if (err) { | ||
| 508 | dprintk("%s: Error %d deriving initiator_seal key\n", | ||
| 509 | __func__, err); | ||
| 510 | goto out_err; | ||
| 511 | } | ||
| 512 | ctx->initiator_enc = context_v2_alloc_cipher(ctx, | ||
| 513 | ctx->gk5e->encrypt_name, | ||
| 514 | ctx->initiator_seal); | ||
| 515 | if (ctx->initiator_enc == NULL) | ||
| 516 | goto out_err; | ||
| 517 | |||
| 518 | /* acceptor seal encryption */ | ||
| 519 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | ||
| 520 | keyout.data = ctx->acceptor_seal; | ||
| 521 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 522 | if (err) { | ||
| 523 | dprintk("%s: Error %d deriving acceptor_seal key\n", | ||
| 524 | __func__, err); | ||
| 525 | goto out_free_initiator_enc; | ||
| 526 | } | ||
| 527 | ctx->acceptor_enc = context_v2_alloc_cipher(ctx, | ||
| 528 | ctx->gk5e->encrypt_name, | ||
| 529 | ctx->acceptor_seal); | ||
| 530 | if (ctx->acceptor_enc == NULL) | ||
| 531 | goto out_free_initiator_enc; | ||
| 532 | |||
| 533 | /* initiator sign checksum */ | ||
| 534 | set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | ||
| 535 | keyout.data = ctx->initiator_sign; | ||
| 536 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 537 | if (err) { | ||
| 538 | dprintk("%s: Error %d deriving initiator_sign key\n", | ||
| 539 | __func__, err); | ||
| 540 | goto out_free_acceptor_enc; | ||
| 541 | } | ||
| 542 | |||
| 543 | /* acceptor sign checksum */ | ||
| 544 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | ||
| 545 | keyout.data = ctx->acceptor_sign; | ||
| 546 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 547 | if (err) { | ||
| 548 | dprintk("%s: Error %d deriving acceptor_sign key\n", | ||
| 549 | __func__, err); | ||
| 550 | goto out_free_acceptor_enc; | ||
| 551 | } | ||
| 552 | |||
| 553 | /* initiator seal integrity */ | ||
| 554 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | ||
| 555 | keyout.data = ctx->initiator_integ; | ||
| 556 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 557 | if (err) { | ||
| 558 | dprintk("%s: Error %d deriving initiator_integ key\n", | ||
| 559 | __func__, err); | ||
| 560 | goto out_free_acceptor_enc; | ||
| 561 | } | ||
| 562 | |||
| 563 | /* acceptor seal integrity */ | ||
| 564 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | ||
| 565 | keyout.data = ctx->acceptor_integ; | ||
| 566 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); | ||
| 567 | if (err) { | ||
| 568 | dprintk("%s: Error %d deriving acceptor_integ key\n", | ||
| 569 | __func__, err); | ||
| 570 | goto out_free_acceptor_enc; | ||
| 571 | } | ||
| 572 | |||
| 573 | switch (ctx->enctype) { | ||
| 574 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 575 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 576 | ctx->initiator_enc_aux = | ||
| 577 | context_v2_alloc_cipher(ctx, "cbc(aes)", | ||
| 578 | ctx->initiator_seal); | ||
| 579 | if (ctx->initiator_enc_aux == NULL) | ||
| 580 | goto out_free_acceptor_enc; | ||
| 581 | ctx->acceptor_enc_aux = | ||
| 582 | context_v2_alloc_cipher(ctx, "cbc(aes)", | ||
| 583 | ctx->acceptor_seal); | ||
| 584 | if (ctx->acceptor_enc_aux == NULL) { | ||
| 585 | crypto_free_blkcipher(ctx->initiator_enc_aux); | ||
| 586 | goto out_free_acceptor_enc; | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | return 0; | ||
| 591 | |||
| 592 | out_free_acceptor_enc: | ||
| 593 | crypto_free_blkcipher(ctx->acceptor_enc); | ||
| 594 | out_free_initiator_enc: | ||
| 595 | crypto_free_blkcipher(ctx->initiator_enc); | ||
| 596 | out_err: | ||
| 597 | return -EINVAL; | ||
| 598 | } | ||
| 599 | |||
| 600 | static int | ||
| 601 | gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, | ||
| 602 | gfp_t gfp_mask) | ||
| 603 | { | ||
| 604 | int keylen; | ||
| 605 | |||
| 606 | p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); | ||
| 607 | if (IS_ERR(p)) | ||
| 608 | goto out_err; | ||
| 609 | ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; | ||
| 610 | |||
| 611 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); | ||
| 612 | if (IS_ERR(p)) | ||
| 613 | goto out_err; | ||
| 614 | p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64)); | ||
| 615 | if (IS_ERR(p)) | ||
| 616 | goto out_err; | ||
| 617 | /* set seq_send for use by "older" enctypes */ | ||
| 618 | ctx->seq_send = ctx->seq_send64; | ||
| 619 | if (ctx->seq_send64 != ctx->seq_send) { | ||
| 620 | dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__, | ||
| 621 | (long unsigned)ctx->seq_send64, ctx->seq_send); | ||
| 622 | goto out_err; | ||
| 623 | } | ||
| 624 | p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); | ||
| 625 | if (IS_ERR(p)) | ||
| 626 | goto out_err; | ||
| 627 | /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */ | ||
| 628 | if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1) | ||
| 629 | ctx->enctype = ENCTYPE_DES3_CBC_RAW; | ||
| 630 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); | ||
| 631 | if (ctx->gk5e == NULL) { | ||
| 632 | dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", | ||
| 633 | ctx->enctype); | ||
| 634 | p = ERR_PTR(-EINVAL); | ||
| 635 | goto out_err; | ||
| 636 | } | ||
| 637 | keylen = ctx->gk5e->keylength; | ||
| 638 | |||
| 639 | p = simple_get_bytes(p, end, ctx->Ksess, keylen); | ||
| 640 | if (IS_ERR(p)) | ||
| 641 | goto out_err; | ||
| 642 | |||
| 643 | if (p != end) { | ||
| 644 | p = ERR_PTR(-EINVAL); | ||
| 645 | goto out_err; | ||
| 646 | } | ||
| 647 | |||
| 648 | ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, | ||
| 649 | gss_kerberos_mech.gm_oid.len, gfp_mask); | ||
| 650 | if (unlikely(ctx->mech_used.data == NULL)) { | ||
| 651 | p = ERR_PTR(-ENOMEM); | ||
| 652 | goto out_err; | ||
| 653 | } | ||
| 654 | ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; | ||
| 655 | |||
| 656 | switch (ctx->enctype) { | ||
| 657 | case ENCTYPE_DES3_CBC_RAW: | ||
| 658 | return context_derive_keys_des3(ctx, gfp_mask); | ||
| 659 | case ENCTYPE_ARCFOUR_HMAC: | ||
| 660 | return context_derive_keys_rc4(ctx); | ||
| 661 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 662 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 663 | return context_derive_keys_new(ctx, gfp_mask); | ||
| 664 | default: | ||
| 665 | return -EINVAL; | ||
| 666 | } | ||
| 667 | |||
| 668 | out_err: | ||
| 669 | return PTR_ERR(p); | ||
| 670 | } | ||
| 671 | |||
| 672 | static int | ||
| 673 | gss_import_sec_context_kerberos(const void *p, size_t len, | ||
| 674 | struct gss_ctx *ctx_id, | ||
| 675 | gfp_t gfp_mask) | ||
| 676 | { | ||
| 677 | const void *end = (const void *)((const char *)p + len); | ||
| 678 | struct krb5_ctx *ctx; | ||
| 679 | int ret; | ||
| 680 | |||
| 681 | ctx = kzalloc(sizeof(*ctx), gfp_mask); | ||
| 682 | if (ctx == NULL) | ||
| 683 | return -ENOMEM; | ||
| 684 | |||
| 685 | if (len == 85) | ||
| 686 | ret = gss_import_v1_context(p, end, ctx); | ||
| 687 | else | ||
| 688 | ret = gss_import_v2_context(p, end, ctx, gfp_mask); | ||
| 689 | |||
| 690 | if (ret == 0) | ||
| 691 | ctx_id->internal_ctx_id = ctx; | ||
| 692 | else | ||
| 693 | kfree(ctx); | ||
| 694 | |||
| 695 | dprintk("RPC: %s: returning %d\n", __func__, ret); | ||
| 696 | return ret; | ||
| 697 | } | ||
| 698 | |||
| 200 | static void | 699 | static void |
| 201 | gss_delete_sec_context_kerberos(void *internal_ctx) { | 700 | gss_delete_sec_context_kerberos(void *internal_ctx) { |
| 202 | struct krb5_ctx *kctx = internal_ctx; | 701 | struct krb5_ctx *kctx = internal_ctx; |
| 203 | 702 | ||
| 204 | crypto_free_blkcipher(kctx->seq); | 703 | crypto_free_blkcipher(kctx->seq); |
| 205 | crypto_free_blkcipher(kctx->enc); | 704 | crypto_free_blkcipher(kctx->enc); |
| 705 | crypto_free_blkcipher(kctx->acceptor_enc); | ||
| 706 | crypto_free_blkcipher(kctx->initiator_enc); | ||
| 707 | crypto_free_blkcipher(kctx->acceptor_enc_aux); | ||
| 708 | crypto_free_blkcipher(kctx->initiator_enc_aux); | ||
| 206 | kfree(kctx->mech_used.data); | 709 | kfree(kctx->mech_used.data); |
| 207 | kfree(kctx); | 710 | kfree(kctx); |
| 208 | } | 711 | } |
| @@ -241,6 +744,7 @@ static struct gss_api_mech gss_kerberos_mech = { | |||
| 241 | .gm_ops = &gss_kerberos_ops, | 744 | .gm_ops = &gss_kerberos_ops, |
| 242 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | 745 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), |
| 243 | .gm_pfs = gss_kerberos_pfs, | 746 | .gm_pfs = gss_kerberos_pfs, |
| 747 | .gm_upcall_enctypes = "enctypes=18,17,16,23,3,1,2 ", | ||
| 244 | }; | 748 | }; |
| 245 | 749 | ||
| 246 | static int __init init_kerberos_module(void) | 750 | static int __init init_kerberos_module(void) |
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 88fe6e75ed7e..d7941eab7796 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c | 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5seal.c |
| 5 | * | 5 | * |
| 6 | * Copyright (c) 2000 The Regents of the University of Michigan. | 6 | * Copyright (c) 2000-2008 The Regents of the University of Michigan. |
| 7 | * All rights reserved. | 7 | * All rights reserved. |
| 8 | * | 8 | * |
| 9 | * Andy Adamson <andros@umich.edu> | 9 | * Andy Adamson <andros@umich.edu> |
| @@ -70,53 +70,154 @@ | |||
| 70 | 70 | ||
| 71 | DEFINE_SPINLOCK(krb5_seq_lock); | 71 | DEFINE_SPINLOCK(krb5_seq_lock); |
| 72 | 72 | ||
| 73 | u32 | 73 | static char * |
| 74 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | 74 | setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) |
| 75 | { | ||
| 76 | __be16 *ptr, *krb5_hdr; | ||
| 77 | int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | ||
| 78 | |||
| 79 | token->len = g_token_size(&ctx->mech_used, body_size); | ||
| 80 | |||
| 81 | ptr = (__be16 *)token->data; | ||
| 82 | g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr); | ||
| 83 | |||
| 84 | /* ptr now at start of header described in rfc 1964, section 1.2.1: */ | ||
| 85 | krb5_hdr = ptr; | ||
| 86 | *ptr++ = KG_TOK_MIC_MSG; | ||
| 87 | *ptr++ = cpu_to_le16(ctx->gk5e->signalg); | ||
| 88 | *ptr++ = SEAL_ALG_NONE; | ||
| 89 | *ptr++ = 0xffff; | ||
| 90 | |||
| 91 | return (char *)krb5_hdr; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void * | ||
| 95 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | ||
| 96 | { | ||
| 97 | __be16 *ptr, *krb5_hdr; | ||
| 98 | u8 *p, flags = 0x00; | ||
| 99 | |||
| 100 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | ||
| 101 | flags |= 0x01; | ||
| 102 | if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) | ||
| 103 | flags |= 0x04; | ||
| 104 | |||
| 105 | /* Per rfc 4121, sec 4.2.6.1, there is no header, | ||
| 106 | * just start the token */ | ||
| 107 | krb5_hdr = ptr = (__be16 *)token->data; | ||
| 108 | |||
| 109 | *ptr++ = KG2_TOK_MIC; | ||
| 110 | p = (u8 *)ptr; | ||
| 111 | *p++ = flags; | ||
| 112 | *p++ = 0xff; | ||
| 113 | ptr = (__be16 *)p; | ||
| 114 | *ptr++ = 0xffff; | ||
| 115 | *ptr++ = 0xffff; | ||
| 116 | |||
| 117 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | ||
| 118 | return krb5_hdr; | ||
| 119 | } | ||
| 120 | |||
| 121 | static u32 | ||
| 122 | gss_get_mic_v1(struct krb5_ctx *ctx, struct xdr_buf *text, | ||
| 75 | struct xdr_netobj *token) | 123 | struct xdr_netobj *token) |
| 76 | { | 124 | { |
| 77 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; | 125 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; |
| 78 | char cksumdata[16]; | 126 | struct xdr_netobj md5cksum = {.len = sizeof(cksumdata), |
| 79 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | 127 | .data = cksumdata}; |
| 80 | unsigned char *ptr, *msg_start; | 128 | void *ptr; |
| 81 | s32 now; | 129 | s32 now; |
| 82 | u32 seq_send; | 130 | u32 seq_send; |
| 131 | u8 *cksumkey; | ||
| 83 | 132 | ||
| 84 | dprintk("RPC: gss_krb5_seal\n"); | 133 | dprintk("RPC: %s\n", __func__); |
| 85 | BUG_ON(ctx == NULL); | 134 | BUG_ON(ctx == NULL); |
| 86 | 135 | ||
| 87 | now = get_seconds(); | 136 | now = get_seconds(); |
| 88 | 137 | ||
| 89 | token->len = g_token_size(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8); | 138 | ptr = setup_token(ctx, token); |
| 90 | 139 | ||
| 91 | ptr = token->data; | 140 | if (ctx->gk5e->keyed_cksum) |
| 92 | g_make_token_header(&ctx->mech_used, GSS_KRB5_TOK_HDR_LEN + 8, &ptr); | 141 | cksumkey = ctx->cksum; |
| 142 | else | ||
| 143 | cksumkey = NULL; | ||
| 93 | 144 | ||
| 94 | /* ptr now at header described in rfc 1964, section 1.2.1: */ | 145 | if (make_checksum(ctx, ptr, 8, text, 0, cksumkey, |
| 95 | ptr[0] = (unsigned char) ((KG_TOK_MIC_MSG >> 8) & 0xff); | 146 | KG_USAGE_SIGN, &md5cksum)) |
| 96 | ptr[1] = (unsigned char) (KG_TOK_MIC_MSG & 0xff); | 147 | return GSS_S_FAILURE; |
| 97 | 148 | ||
| 98 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8; | 149 | memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len); |
| 99 | 150 | ||
| 100 | *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5); | 151 | spin_lock(&krb5_seq_lock); |
| 101 | memset(ptr + 4, 0xff, 4); | 152 | seq_send = ctx->seq_send++; |
| 153 | spin_unlock(&krb5_seq_lock); | ||
| 102 | 154 | ||
| 103 | if (make_checksum("md5", ptr, 8, text, 0, &md5cksum)) | 155 | if (krb5_make_seq_num(ctx, ctx->seq, ctx->initiate ? 0 : 0xff, |
| 156 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8)) | ||
| 104 | return GSS_S_FAILURE; | 157 | return GSS_S_FAILURE; |
| 105 | 158 | ||
| 106 | if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, | 159 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; |
| 107 | md5cksum.data, md5cksum.len)) | 160 | } |
| 108 | return GSS_S_FAILURE; | 161 | |
| 162 | u32 | ||
| 163 | gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, | ||
| 164 | struct xdr_netobj *token) | ||
| 165 | { | ||
| 166 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 167 | struct xdr_netobj cksumobj = { .len = sizeof(cksumdata), | ||
| 168 | .data = cksumdata}; | ||
| 169 | void *krb5_hdr; | ||
| 170 | s32 now; | ||
| 171 | u64 seq_send; | ||
| 172 | u8 *cksumkey; | ||
| 173 | unsigned int cksum_usage; | ||
| 109 | 174 | ||
| 110 | memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8); | 175 | dprintk("RPC: %s\n", __func__); |
| 111 | 176 | ||
| 177 | krb5_hdr = setup_token_v2(ctx, token); | ||
| 178 | |||
| 179 | /* Set up the sequence number. Now 64-bits in clear | ||
| 180 | * text and w/o direction indicator */ | ||
| 112 | spin_lock(&krb5_seq_lock); | 181 | spin_lock(&krb5_seq_lock); |
| 113 | seq_send = ctx->seq_send++; | 182 | seq_send = ctx->seq_send64++; |
| 114 | spin_unlock(&krb5_seq_lock); | 183 | spin_unlock(&krb5_seq_lock); |
| 115 | 184 | *((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); | |
| 116 | if (krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff, | 185 | |
| 117 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, | 186 | if (ctx->initiate) { |
| 118 | ptr + 8)) | 187 | cksumkey = ctx->initiator_sign; |
| 188 | cksum_usage = KG_USAGE_INITIATOR_SIGN; | ||
| 189 | } else { | ||
| 190 | cksumkey = ctx->acceptor_sign; | ||
| 191 | cksum_usage = KG_USAGE_ACCEPTOR_SIGN; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (make_checksum_v2(ctx, krb5_hdr, GSS_KRB5_TOK_HDR_LEN, | ||
| 195 | text, 0, cksumkey, cksum_usage, &cksumobj)) | ||
| 119 | return GSS_S_FAILURE; | 196 | return GSS_S_FAILURE; |
| 120 | 197 | ||
| 198 | memcpy(krb5_hdr + GSS_KRB5_TOK_HDR_LEN, cksumobj.data, cksumobj.len); | ||
| 199 | |||
| 200 | now = get_seconds(); | ||
| 201 | |||
| 121 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | 202 | return (ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; |
| 122 | } | 203 | } |
| 204 | |||
| 205 | u32 | ||
| 206 | gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text, | ||
| 207 | struct xdr_netobj *token) | ||
| 208 | { | ||
| 209 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; | ||
| 210 | |||
| 211 | switch (ctx->enctype) { | ||
| 212 | default: | ||
| 213 | BUG(); | ||
| 214 | case ENCTYPE_DES_CBC_RAW: | ||
| 215 | case ENCTYPE_DES3_CBC_RAW: | ||
| 216 | case ENCTYPE_ARCFOUR_HMAC: | ||
| 217 | return gss_get_mic_v1(ctx, text, token); | ||
| 218 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 219 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 220 | return gss_get_mic_v2(ctx, text, token); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c index 6331cd6866ec..415c013ba382 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c +++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c | |||
| @@ -39,14 +39,51 @@ | |||
| 39 | # define RPCDBG_FACILITY RPCDBG_AUTH | 39 | # define RPCDBG_FACILITY RPCDBG_AUTH |
| 40 | #endif | 40 | #endif |
| 41 | 41 | ||
| 42 | static s32 | ||
| 43 | krb5_make_rc4_seq_num(struct krb5_ctx *kctx, int direction, s32 seqnum, | ||
| 44 | unsigned char *cksum, unsigned char *buf) | ||
| 45 | { | ||
| 46 | struct crypto_blkcipher *cipher; | ||
| 47 | unsigned char plain[8]; | ||
| 48 | s32 code; | ||
| 49 | |||
| 50 | dprintk("RPC: %s:\n", __func__); | ||
| 51 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
| 52 | CRYPTO_ALG_ASYNC); | ||
| 53 | if (IS_ERR(cipher)) | ||
| 54 | return PTR_ERR(cipher); | ||
| 55 | |||
| 56 | plain[0] = (unsigned char) ((seqnum >> 24) & 0xff); | ||
| 57 | plain[1] = (unsigned char) ((seqnum >> 16) & 0xff); | ||
| 58 | plain[2] = (unsigned char) ((seqnum >> 8) & 0xff); | ||
| 59 | plain[3] = (unsigned char) ((seqnum >> 0) & 0xff); | ||
| 60 | plain[4] = direction; | ||
| 61 | plain[5] = direction; | ||
| 62 | plain[6] = direction; | ||
| 63 | plain[7] = direction; | ||
| 64 | |||
| 65 | code = krb5_rc4_setup_seq_key(kctx, cipher, cksum); | ||
| 66 | if (code) | ||
| 67 | goto out; | ||
| 68 | |||
| 69 | code = krb5_encrypt(cipher, cksum, plain, buf, 8); | ||
| 70 | out: | ||
| 71 | crypto_free_blkcipher(cipher); | ||
| 72 | return code; | ||
| 73 | } | ||
| 42 | s32 | 74 | s32 |
| 43 | krb5_make_seq_num(struct crypto_blkcipher *key, | 75 | krb5_make_seq_num(struct krb5_ctx *kctx, |
| 76 | struct crypto_blkcipher *key, | ||
| 44 | int direction, | 77 | int direction, |
| 45 | u32 seqnum, | 78 | u32 seqnum, |
| 46 | unsigned char *cksum, unsigned char *buf) | 79 | unsigned char *cksum, unsigned char *buf) |
| 47 | { | 80 | { |
| 48 | unsigned char plain[8]; | 81 | unsigned char plain[8]; |
| 49 | 82 | ||
| 83 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | ||
| 84 | return krb5_make_rc4_seq_num(kctx, direction, seqnum, | ||
| 85 | cksum, buf); | ||
| 86 | |||
| 50 | plain[0] = (unsigned char) (seqnum & 0xff); | 87 | plain[0] = (unsigned char) (seqnum & 0xff); |
| 51 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); | 88 | plain[1] = (unsigned char) ((seqnum >> 8) & 0xff); |
| 52 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); | 89 | plain[2] = (unsigned char) ((seqnum >> 16) & 0xff); |
| @@ -60,17 +97,59 @@ krb5_make_seq_num(struct crypto_blkcipher *key, | |||
| 60 | return krb5_encrypt(key, cksum, plain, buf, 8); | 97 | return krb5_encrypt(key, cksum, plain, buf, 8); |
| 61 | } | 98 | } |
| 62 | 99 | ||
| 100 | static s32 | ||
| 101 | krb5_get_rc4_seq_num(struct krb5_ctx *kctx, unsigned char *cksum, | ||
| 102 | unsigned char *buf, int *direction, s32 *seqnum) | ||
| 103 | { | ||
| 104 | struct crypto_blkcipher *cipher; | ||
| 105 | unsigned char plain[8]; | ||
| 106 | s32 code; | ||
| 107 | |||
| 108 | dprintk("RPC: %s:\n", __func__); | ||
| 109 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
| 110 | CRYPTO_ALG_ASYNC); | ||
| 111 | if (IS_ERR(cipher)) | ||
| 112 | return PTR_ERR(cipher); | ||
| 113 | |||
| 114 | code = krb5_rc4_setup_seq_key(kctx, cipher, cksum); | ||
| 115 | if (code) | ||
| 116 | goto out; | ||
| 117 | |||
| 118 | code = krb5_decrypt(cipher, cksum, buf, plain, 8); | ||
| 119 | if (code) | ||
| 120 | goto out; | ||
| 121 | |||
| 122 | if ((plain[4] != plain[5]) || (plain[4] != plain[6]) | ||
| 123 | || (plain[4] != plain[7])) { | ||
| 124 | code = (s32)KG_BAD_SEQ; | ||
| 125 | goto out; | ||
| 126 | } | ||
| 127 | |||
| 128 | *direction = plain[4]; | ||
| 129 | |||
| 130 | *seqnum = ((plain[0] << 24) | (plain[1] << 16) | | ||
| 131 | (plain[2] << 8) | (plain[3])); | ||
| 132 | out: | ||
| 133 | crypto_free_blkcipher(cipher); | ||
| 134 | return code; | ||
| 135 | } | ||
| 136 | |||
| 63 | s32 | 137 | s32 |
| 64 | krb5_get_seq_num(struct crypto_blkcipher *key, | 138 | krb5_get_seq_num(struct krb5_ctx *kctx, |
| 65 | unsigned char *cksum, | 139 | unsigned char *cksum, |
| 66 | unsigned char *buf, | 140 | unsigned char *buf, |
| 67 | int *direction, u32 *seqnum) | 141 | int *direction, u32 *seqnum) |
| 68 | { | 142 | { |
| 69 | s32 code; | 143 | s32 code; |
| 70 | unsigned char plain[8]; | 144 | unsigned char plain[8]; |
| 145 | struct crypto_blkcipher *key = kctx->seq; | ||
| 71 | 146 | ||
| 72 | dprintk("RPC: krb5_get_seq_num:\n"); | 147 | dprintk("RPC: krb5_get_seq_num:\n"); |
| 73 | 148 | ||
| 149 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) | ||
| 150 | return krb5_get_rc4_seq_num(kctx, cksum, buf, | ||
| 151 | direction, seqnum); | ||
| 152 | |||
| 74 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) | 153 | if ((code = krb5_decrypt(key, cksum, buf, plain, 8))) |
| 75 | return code; | 154 | return code; |
| 76 | 155 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c index ce6c247edad0..6cd930f3678f 100644 --- a/net/sunrpc/auth_gss/gss_krb5_unseal.c +++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c | 4 | * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/krb5/k5unseal.c |
| 5 | * | 5 | * |
| 6 | * Copyright (c) 2000 The Regents of the University of Michigan. | 6 | * Copyright (c) 2000-2008 The Regents of the University of Michigan. |
| 7 | * All rights reserved. | 7 | * All rights reserved. |
| 8 | * | 8 | * |
| 9 | * Andy Adamson <andros@umich.edu> | 9 | * Andy Adamson <andros@umich.edu> |
| @@ -70,20 +70,21 @@ | |||
| 70 | /* read_token is a mic token, and message_buffer is the data that the mic was | 70 | /* read_token is a mic token, and message_buffer is the data that the mic was |
| 71 | * supposedly taken over. */ | 71 | * supposedly taken over. */ |
| 72 | 72 | ||
| 73 | u32 | 73 | static u32 |
| 74 | gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | 74 | gss_verify_mic_v1(struct krb5_ctx *ctx, |
| 75 | struct xdr_buf *message_buffer, struct xdr_netobj *read_token) | 75 | struct xdr_buf *message_buffer, struct xdr_netobj *read_token) |
| 76 | { | 76 | { |
| 77 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; | ||
| 78 | int signalg; | 77 | int signalg; |
| 79 | int sealalg; | 78 | int sealalg; |
| 80 | char cksumdata[16]; | 79 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; |
| 81 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | 80 | struct xdr_netobj md5cksum = {.len = sizeof(cksumdata), |
| 81 | .data = cksumdata}; | ||
| 82 | s32 now; | 82 | s32 now; |
| 83 | int direction; | 83 | int direction; |
| 84 | u32 seqnum; | 84 | u32 seqnum; |
| 85 | unsigned char *ptr = (unsigned char *)read_token->data; | 85 | unsigned char *ptr = (unsigned char *)read_token->data; |
| 86 | int bodysize; | 86 | int bodysize; |
| 87 | u8 *cksumkey; | ||
| 87 | 88 | ||
| 88 | dprintk("RPC: krb5_read_token\n"); | 89 | dprintk("RPC: krb5_read_token\n"); |
| 89 | 90 | ||
| @@ -98,7 +99,7 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
| 98 | /* XXX sanity-check bodysize?? */ | 99 | /* XXX sanity-check bodysize?? */ |
| 99 | 100 | ||
| 100 | signalg = ptr[2] + (ptr[3] << 8); | 101 | signalg = ptr[2] + (ptr[3] << 8); |
| 101 | if (signalg != SGN_ALG_DES_MAC_MD5) | 102 | if (signalg != ctx->gk5e->signalg) |
| 102 | return GSS_S_DEFECTIVE_TOKEN; | 103 | return GSS_S_DEFECTIVE_TOKEN; |
| 103 | 104 | ||
| 104 | sealalg = ptr[4] + (ptr[5] << 8); | 105 | sealalg = ptr[4] + (ptr[5] << 8); |
| @@ -108,13 +109,17 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
| 108 | if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) | 109 | if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) |
| 109 | return GSS_S_DEFECTIVE_TOKEN; | 110 | return GSS_S_DEFECTIVE_TOKEN; |
| 110 | 111 | ||
| 111 | if (make_checksum("md5", ptr, 8, message_buffer, 0, &md5cksum)) | 112 | if (ctx->gk5e->keyed_cksum) |
| 112 | return GSS_S_FAILURE; | 113 | cksumkey = ctx->cksum; |
| 114 | else | ||
| 115 | cksumkey = NULL; | ||
| 113 | 116 | ||
| 114 | if (krb5_encrypt(ctx->seq, NULL, md5cksum.data, md5cksum.data, 16)) | 117 | if (make_checksum(ctx, ptr, 8, message_buffer, 0, |
| 118 | cksumkey, KG_USAGE_SIGN, &md5cksum)) | ||
| 115 | return GSS_S_FAILURE; | 119 | return GSS_S_FAILURE; |
| 116 | 120 | ||
| 117 | if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) | 121 | if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN, |
| 122 | ctx->gk5e->cksumlength)) | ||
| 118 | return GSS_S_BAD_SIG; | 123 | return GSS_S_BAD_SIG; |
| 119 | 124 | ||
| 120 | /* it got through unscathed. Make sure the context is unexpired */ | 125 | /* it got through unscathed. Make sure the context is unexpired */ |
| @@ -126,7 +131,8 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
| 126 | 131 | ||
| 127 | /* do sequencing checks */ | 132 | /* do sequencing checks */ |
| 128 | 133 | ||
| 129 | if (krb5_get_seq_num(ctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, &direction, &seqnum)) | 134 | if (krb5_get_seq_num(ctx, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, |
| 135 | &direction, &seqnum)) | ||
| 130 | return GSS_S_FAILURE; | 136 | return GSS_S_FAILURE; |
| 131 | 137 | ||
| 132 | if ((ctx->initiate && direction != 0xff) || | 138 | if ((ctx->initiate && direction != 0xff) || |
| @@ -135,3 +141,86 @@ gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | |||
| 135 | 141 | ||
| 136 | return GSS_S_COMPLETE; | 142 | return GSS_S_COMPLETE; |
| 137 | } | 143 | } |
| 144 | |||
| 145 | static u32 | ||
| 146 | gss_verify_mic_v2(struct krb5_ctx *ctx, | ||
| 147 | struct xdr_buf *message_buffer, struct xdr_netobj *read_token) | ||
| 148 | { | ||
| 149 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; | ||
| 150 | struct xdr_netobj cksumobj = {.len = sizeof(cksumdata), | ||
| 151 | .data = cksumdata}; | ||
| 152 | s32 now; | ||
| 153 | u64 seqnum; | ||
| 154 | u8 *ptr = read_token->data; | ||
| 155 | u8 *cksumkey; | ||
| 156 | u8 flags; | ||
| 157 | int i; | ||
| 158 | unsigned int cksum_usage; | ||
| 159 | |||
| 160 | dprintk("RPC: %s\n", __func__); | ||
| 161 | |||
| 162 | if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_MIC) | ||
| 163 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 164 | |||
| 165 | flags = ptr[2]; | ||
| 166 | if ((!ctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) || | ||
| 167 | (ctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR))) | ||
| 168 | return GSS_S_BAD_SIG; | ||
| 169 | |||
| 170 | if (flags & KG2_TOKEN_FLAG_SEALED) { | ||
| 171 | dprintk("%s: token has unexpected sealed flag\n", __func__); | ||
| 172 | return GSS_S_FAILURE; | ||
| 173 | } | ||
| 174 | |||
| 175 | for (i = 3; i < 8; i++) | ||
| 176 | if (ptr[i] != 0xff) | ||
| 177 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 178 | |||
| 179 | if (ctx->initiate) { | ||
| 180 | cksumkey = ctx->acceptor_sign; | ||
| 181 | cksum_usage = KG_USAGE_ACCEPTOR_SIGN; | ||
| 182 | } else { | ||
| 183 | cksumkey = ctx->initiator_sign; | ||
| 184 | cksum_usage = KG_USAGE_INITIATOR_SIGN; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (make_checksum_v2(ctx, ptr, GSS_KRB5_TOK_HDR_LEN, message_buffer, 0, | ||
| 188 | cksumkey, cksum_usage, &cksumobj)) | ||
| 189 | return GSS_S_FAILURE; | ||
| 190 | |||
| 191 | if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN, | ||
| 192 | ctx->gk5e->cksumlength)) | ||
| 193 | return GSS_S_BAD_SIG; | ||
| 194 | |||
| 195 | /* it got through unscathed. Make sure the context is unexpired */ | ||
| 196 | now = get_seconds(); | ||
| 197 | if (now > ctx->endtime) | ||
| 198 | return GSS_S_CONTEXT_EXPIRED; | ||
| 199 | |||
| 200 | /* do sequencing checks */ | ||
| 201 | |||
| 202 | seqnum = be64_to_cpup((__be64 *)ptr + 8); | ||
| 203 | |||
| 204 | return GSS_S_COMPLETE; | ||
| 205 | } | ||
| 206 | |||
| 207 | u32 | ||
| 208 | gss_verify_mic_kerberos(struct gss_ctx *gss_ctx, | ||
| 209 | struct xdr_buf *message_buffer, | ||
| 210 | struct xdr_netobj *read_token) | ||
| 211 | { | ||
| 212 | struct krb5_ctx *ctx = gss_ctx->internal_ctx_id; | ||
| 213 | |||
| 214 | switch (ctx->enctype) { | ||
| 215 | default: | ||
| 216 | BUG(); | ||
| 217 | case ENCTYPE_DES_CBC_RAW: | ||
| 218 | case ENCTYPE_DES3_CBC_RAW: | ||
| 219 | case ENCTYPE_ARCFOUR_HMAC: | ||
| 220 | return gss_verify_mic_v1(ctx, message_buffer, read_token); | ||
| 221 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 222 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 223 | return gss_verify_mic_v2(ctx, message_buffer, read_token); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index a6e905637e03..2763e3e48db4 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
| @@ -1,3 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * COPYRIGHT (c) 2008 | ||
| 3 | * The Regents of the University of Michigan | ||
| 4 | * ALL RIGHTS RESERVED | ||
| 5 | * | ||
| 6 | * Permission is granted to use, copy, create derivative works | ||
| 7 | * and redistribute this software and such derivative works | ||
| 8 | * for any purpose, so long as the name of The University of | ||
| 9 | * Michigan is not used in any advertising or publicity | ||
| 10 | * pertaining to the use of distribution of this software | ||
| 11 | * without specific, written prior authorization. If the | ||
| 12 | * above copyright notice or any other identification of the | ||
| 13 | * University of Michigan is included in any copy of any | ||
| 14 | * portion of this software, then the disclaimer below must | ||
| 15 | * also be included. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION | ||
| 18 | * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY | ||
| 19 | * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF | ||
| 20 | * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING | ||
| 21 | * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF | ||
| 22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | ||
| 23 | * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE | ||
| 24 | * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR | ||
| 25 | * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING | ||
| 26 | * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN | ||
| 27 | * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF | ||
| 28 | * SUCH DAMAGES. | ||
| 29 | */ | ||
| 30 | |||
| 1 | #include <linux/types.h> | 31 | #include <linux/types.h> |
| 2 | #include <linux/jiffies.h> | 32 | #include <linux/jiffies.h> |
| 3 | #include <linux/sunrpc/gss_krb5.h> | 33 | #include <linux/sunrpc/gss_krb5.h> |
| @@ -12,10 +42,7 @@ | |||
| 12 | static inline int | 42 | static inline int |
| 13 | gss_krb5_padding(int blocksize, int length) | 43 | gss_krb5_padding(int blocksize, int length) |
| 14 | { | 44 | { |
| 15 | /* Most of the code is block-size independent but currently we | 45 | return blocksize - (length % blocksize); |
| 16 | * use only 8: */ | ||
| 17 | BUG_ON(blocksize != 8); | ||
| 18 | return 8 - (length & 7); | ||
| 19 | } | 46 | } |
| 20 | 47 | ||
| 21 | static inline void | 48 | static inline void |
| @@ -86,8 +113,8 @@ out: | |||
| 86 | return 0; | 113 | return 0; |
| 87 | } | 114 | } |
| 88 | 115 | ||
| 89 | static void | 116 | void |
| 90 | make_confounder(char *p, u32 conflen) | 117 | gss_krb5_make_confounder(char *p, u32 conflen) |
| 91 | { | 118 | { |
| 92 | static u64 i = 0; | 119 | static u64 i = 0; |
| 93 | u64 *q = (u64 *)p; | 120 | u64 *q = (u64 *)p; |
| @@ -127,69 +154,73 @@ make_confounder(char *p, u32 conflen) | |||
| 127 | 154 | ||
| 128 | /* XXX factor out common code with seal/unseal. */ | 155 | /* XXX factor out common code with seal/unseal. */ |
| 129 | 156 | ||
| 130 | u32 | 157 | static u32 |
| 131 | gss_wrap_kerberos(struct gss_ctx *ctx, int offset, | 158 | gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, |
| 132 | struct xdr_buf *buf, struct page **pages) | 159 | struct xdr_buf *buf, struct page **pages) |
| 133 | { | 160 | { |
| 134 | struct krb5_ctx *kctx = ctx->internal_ctx_id; | 161 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; |
| 135 | char cksumdata[16]; | 162 | struct xdr_netobj md5cksum = {.len = sizeof(cksumdata), |
| 136 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | 163 | .data = cksumdata}; |
| 137 | int blocksize = 0, plainlen; | 164 | int blocksize = 0, plainlen; |
| 138 | unsigned char *ptr, *msg_start; | 165 | unsigned char *ptr, *msg_start; |
| 139 | s32 now; | 166 | s32 now; |
| 140 | int headlen; | 167 | int headlen; |
| 141 | struct page **tmp_pages; | 168 | struct page **tmp_pages; |
| 142 | u32 seq_send; | 169 | u32 seq_send; |
| 170 | u8 *cksumkey; | ||
| 171 | u32 conflen = kctx->gk5e->conflen; | ||
| 143 | 172 | ||
| 144 | dprintk("RPC: gss_wrap_kerberos\n"); | 173 | dprintk("RPC: %s\n", __func__); |
| 145 | 174 | ||
| 146 | now = get_seconds(); | 175 | now = get_seconds(); |
| 147 | 176 | ||
| 148 | blocksize = crypto_blkcipher_blocksize(kctx->enc); | 177 | blocksize = crypto_blkcipher_blocksize(kctx->enc); |
| 149 | gss_krb5_add_padding(buf, offset, blocksize); | 178 | gss_krb5_add_padding(buf, offset, blocksize); |
| 150 | BUG_ON((buf->len - offset) % blocksize); | 179 | BUG_ON((buf->len - offset) % blocksize); |
| 151 | plainlen = blocksize + buf->len - offset; | 180 | plainlen = conflen + buf->len - offset; |
| 152 | 181 | ||
| 153 | headlen = g_token_size(&kctx->mech_used, 24 + plainlen) - | 182 | headlen = g_token_size(&kctx->mech_used, |
| 154 | (buf->len - offset); | 183 | GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength + plainlen) - |
| 184 | (buf->len - offset); | ||
| 155 | 185 | ||
| 156 | ptr = buf->head[0].iov_base + offset; | 186 | ptr = buf->head[0].iov_base + offset; |
| 157 | /* shift data to make room for header. */ | 187 | /* shift data to make room for header. */ |
| 188 | xdr_extend_head(buf, offset, headlen); | ||
| 189 | |||
| 158 | /* XXX Would be cleverer to encrypt while copying. */ | 190 | /* XXX Would be cleverer to encrypt while copying. */ |
| 159 | /* XXX bounds checking, slack, etc. */ | ||
| 160 | memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset); | ||
| 161 | buf->head[0].iov_len += headlen; | ||
| 162 | buf->len += headlen; | ||
| 163 | BUG_ON((buf->len - offset - headlen) % blocksize); | 191 | BUG_ON((buf->len - offset - headlen) % blocksize); |
| 164 | 192 | ||
| 165 | g_make_token_header(&kctx->mech_used, | 193 | g_make_token_header(&kctx->mech_used, |
| 166 | GSS_KRB5_TOK_HDR_LEN + 8 + plainlen, &ptr); | 194 | GSS_KRB5_TOK_HDR_LEN + |
| 195 | kctx->gk5e->cksumlength + plainlen, &ptr); | ||
| 167 | 196 | ||
| 168 | 197 | ||
| 169 | /* ptr now at header described in rfc 1964, section 1.2.1: */ | 198 | /* ptr now at header described in rfc 1964, section 1.2.1: */ |
| 170 | ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff); | 199 | ptr[0] = (unsigned char) ((KG_TOK_WRAP_MSG >> 8) & 0xff); |
| 171 | ptr[1] = (unsigned char) (KG_TOK_WRAP_MSG & 0xff); | 200 | ptr[1] = (unsigned char) (KG_TOK_WRAP_MSG & 0xff); |
| 172 | 201 | ||
| 173 | msg_start = ptr + 24; | 202 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength; |
| 174 | 203 | ||
| 175 | *(__be16 *)(ptr + 2) = htons(SGN_ALG_DES_MAC_MD5); | 204 | *(__be16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg); |
| 176 | memset(ptr + 4, 0xff, 4); | 205 | memset(ptr + 4, 0xff, 4); |
| 177 | *(__be16 *)(ptr + 4) = htons(SEAL_ALG_DES); | 206 | *(__be16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg); |
| 178 | 207 | ||
| 179 | make_confounder(msg_start, blocksize); | 208 | gss_krb5_make_confounder(msg_start, conflen); |
| 209 | |||
| 210 | if (kctx->gk5e->keyed_cksum) | ||
| 211 | cksumkey = kctx->cksum; | ||
| 212 | else | ||
| 213 | cksumkey = NULL; | ||
| 180 | 214 | ||
| 181 | /* XXXJBF: UGH!: */ | 215 | /* XXXJBF: UGH!: */ |
| 182 | tmp_pages = buf->pages; | 216 | tmp_pages = buf->pages; |
| 183 | buf->pages = pages; | 217 | buf->pages = pages; |
| 184 | if (make_checksum("md5", ptr, 8, buf, | 218 | if (make_checksum(kctx, ptr, 8, buf, offset + headlen - conflen, |
| 185 | offset + headlen - blocksize, &md5cksum)) | 219 | cksumkey, KG_USAGE_SEAL, &md5cksum)) |
| 186 | return GSS_S_FAILURE; | 220 | return GSS_S_FAILURE; |
| 187 | buf->pages = tmp_pages; | 221 | buf->pages = tmp_pages; |
| 188 | 222 | ||
| 189 | if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, | 223 | memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data, md5cksum.len); |
| 190 | md5cksum.data, md5cksum.len)) | ||
| 191 | return GSS_S_FAILURE; | ||
| 192 | memcpy(ptr + GSS_KRB5_TOK_HDR_LEN, md5cksum.data + md5cksum.len - 8, 8); | ||
| 193 | 224 | ||
| 194 | spin_lock(&krb5_seq_lock); | 225 | spin_lock(&krb5_seq_lock); |
| 195 | seq_send = kctx->seq_send++; | 226 | seq_send = kctx->seq_send++; |
| @@ -197,25 +228,42 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset, | |||
| 197 | 228 | ||
| 198 | /* XXX would probably be more efficient to compute checksum | 229 | /* XXX would probably be more efficient to compute checksum |
| 199 | * and encrypt at the same time: */ | 230 | * and encrypt at the same time: */ |
| 200 | if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, | 231 | if ((krb5_make_seq_num(kctx, kctx->seq, kctx->initiate ? 0 : 0xff, |
| 201 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))) | 232 | seq_send, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8))) |
| 202 | return GSS_S_FAILURE; | 233 | return GSS_S_FAILURE; |
| 203 | 234 | ||
| 204 | if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, | 235 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { |
| 205 | pages)) | 236 | struct crypto_blkcipher *cipher; |
| 206 | return GSS_S_FAILURE; | 237 | int err; |
| 238 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
| 239 | CRYPTO_ALG_ASYNC); | ||
| 240 | if (IS_ERR(cipher)) | ||
| 241 | return GSS_S_FAILURE; | ||
| 242 | |||
| 243 | krb5_rc4_setup_enc_key(kctx, cipher, seq_send); | ||
| 244 | |||
| 245 | err = gss_encrypt_xdr_buf(cipher, buf, | ||
| 246 | offset + headlen - conflen, pages); | ||
| 247 | crypto_free_blkcipher(cipher); | ||
| 248 | if (err) | ||
| 249 | return GSS_S_FAILURE; | ||
| 250 | } else { | ||
| 251 | if (gss_encrypt_xdr_buf(kctx->enc, buf, | ||
| 252 | offset + headlen - conflen, pages)) | ||
| 253 | return GSS_S_FAILURE; | ||
| 254 | } | ||
| 207 | 255 | ||
| 208 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | 256 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; |
| 209 | } | 257 | } |
| 210 | 258 | ||
| 211 | u32 | 259 | static u32 |
| 212 | gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | 260 | gss_unwrap_kerberos_v1(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) |
| 213 | { | 261 | { |
| 214 | struct krb5_ctx *kctx = ctx->internal_ctx_id; | ||
| 215 | int signalg; | 262 | int signalg; |
| 216 | int sealalg; | 263 | int sealalg; |
| 217 | char cksumdata[16]; | 264 | char cksumdata[GSS_KRB5_MAX_CKSUM_LEN]; |
| 218 | struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; | 265 | struct xdr_netobj md5cksum = {.len = sizeof(cksumdata), |
| 266 | .data = cksumdata}; | ||
| 219 | s32 now; | 267 | s32 now; |
| 220 | int direction; | 268 | int direction; |
| 221 | s32 seqnum; | 269 | s32 seqnum; |
| @@ -224,6 +272,9 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
| 224 | void *data_start, *orig_start; | 272 | void *data_start, *orig_start; |
| 225 | int data_len; | 273 | int data_len; |
| 226 | int blocksize; | 274 | int blocksize; |
| 275 | u32 conflen = kctx->gk5e->conflen; | ||
| 276 | int crypt_offset; | ||
| 277 | u8 *cksumkey; | ||
| 227 | 278 | ||
| 228 | dprintk("RPC: gss_unwrap_kerberos\n"); | 279 | dprintk("RPC: gss_unwrap_kerberos\n"); |
| 229 | 280 | ||
| @@ -241,29 +292,65 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
| 241 | /* get the sign and seal algorithms */ | 292 | /* get the sign and seal algorithms */ |
| 242 | 293 | ||
| 243 | signalg = ptr[2] + (ptr[3] << 8); | 294 | signalg = ptr[2] + (ptr[3] << 8); |
| 244 | if (signalg != SGN_ALG_DES_MAC_MD5) | 295 | if (signalg != kctx->gk5e->signalg) |
| 245 | return GSS_S_DEFECTIVE_TOKEN; | 296 | return GSS_S_DEFECTIVE_TOKEN; |
| 246 | 297 | ||
| 247 | sealalg = ptr[4] + (ptr[5] << 8); | 298 | sealalg = ptr[4] + (ptr[5] << 8); |
| 248 | if (sealalg != SEAL_ALG_DES) | 299 | if (sealalg != kctx->gk5e->sealalg) |
| 249 | return GSS_S_DEFECTIVE_TOKEN; | 300 | return GSS_S_DEFECTIVE_TOKEN; |
| 250 | 301 | ||
| 251 | if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) | 302 | if ((ptr[6] != 0xff) || (ptr[7] != 0xff)) |
| 252 | return GSS_S_DEFECTIVE_TOKEN; | 303 | return GSS_S_DEFECTIVE_TOKEN; |
| 253 | 304 | ||
| 254 | if (gss_decrypt_xdr_buf(kctx->enc, buf, | 305 | /* |
| 255 | ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base)) | 306 | * Data starts after token header and checksum. ptr points |
| 256 | return GSS_S_DEFECTIVE_TOKEN; | 307 | * to the beginning of the token header |
| 308 | */ | ||
| 309 | crypt_offset = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) - | ||
| 310 | (unsigned char *)buf->head[0].iov_base; | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Need plaintext seqnum to derive encryption key for arcfour-hmac | ||
| 314 | */ | ||
| 315 | if (krb5_get_seq_num(kctx, ptr + GSS_KRB5_TOK_HDR_LEN, | ||
| 316 | ptr + 8, &direction, &seqnum)) | ||
| 317 | return GSS_S_BAD_SIG; | ||
| 257 | 318 | ||
| 258 | if (make_checksum("md5", ptr, 8, buf, | 319 | if ((kctx->initiate && direction != 0xff) || |
| 259 | ptr + GSS_KRB5_TOK_HDR_LEN + 8 - (unsigned char *)buf->head[0].iov_base, &md5cksum)) | 320 | (!kctx->initiate && direction != 0)) |
| 260 | return GSS_S_FAILURE; | 321 | return GSS_S_BAD_SIG; |
| 322 | |||
| 323 | if (kctx->enctype == ENCTYPE_ARCFOUR_HMAC) { | ||
| 324 | struct crypto_blkcipher *cipher; | ||
| 325 | int err; | ||
| 326 | |||
| 327 | cipher = crypto_alloc_blkcipher(kctx->gk5e->encrypt_name, 0, | ||
| 328 | CRYPTO_ALG_ASYNC); | ||
| 329 | if (IS_ERR(cipher)) | ||
| 330 | return GSS_S_FAILURE; | ||
| 331 | |||
| 332 | krb5_rc4_setup_enc_key(kctx, cipher, seqnum); | ||
| 261 | 333 | ||
| 262 | if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, | 334 | err = gss_decrypt_xdr_buf(cipher, buf, crypt_offset); |
| 263 | md5cksum.data, md5cksum.len)) | 335 | crypto_free_blkcipher(cipher); |
| 336 | if (err) | ||
| 337 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 338 | } else { | ||
| 339 | if (gss_decrypt_xdr_buf(kctx->enc, buf, crypt_offset)) | ||
| 340 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 341 | } | ||
| 342 | |||
| 343 | if (kctx->gk5e->keyed_cksum) | ||
| 344 | cksumkey = kctx->cksum; | ||
| 345 | else | ||
| 346 | cksumkey = NULL; | ||
| 347 | |||
| 348 | if (make_checksum(kctx, ptr, 8, buf, crypt_offset, | ||
| 349 | cksumkey, KG_USAGE_SEAL, &md5cksum)) | ||
| 264 | return GSS_S_FAILURE; | 350 | return GSS_S_FAILURE; |
| 265 | 351 | ||
| 266 | if (memcmp(md5cksum.data + 8, ptr + GSS_KRB5_TOK_HDR_LEN, 8)) | 352 | if (memcmp(md5cksum.data, ptr + GSS_KRB5_TOK_HDR_LEN, |
| 353 | kctx->gk5e->cksumlength)) | ||
| 267 | return GSS_S_BAD_SIG; | 354 | return GSS_S_BAD_SIG; |
| 268 | 355 | ||
| 269 | /* it got through unscathed. Make sure the context is unexpired */ | 356 | /* it got through unscathed. Make sure the context is unexpired */ |
| @@ -275,19 +362,12 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
| 275 | 362 | ||
| 276 | /* do sequencing checks */ | 363 | /* do sequencing checks */ |
| 277 | 364 | ||
| 278 | if (krb5_get_seq_num(kctx->seq, ptr + GSS_KRB5_TOK_HDR_LEN, ptr + 8, | ||
| 279 | &direction, &seqnum)) | ||
| 280 | return GSS_S_BAD_SIG; | ||
| 281 | |||
| 282 | if ((kctx->initiate && direction != 0xff) || | ||
| 283 | (!kctx->initiate && direction != 0)) | ||
| 284 | return GSS_S_BAD_SIG; | ||
| 285 | |||
| 286 | /* Copy the data back to the right position. XXX: Would probably be | 365 | /* Copy the data back to the right position. XXX: Would probably be |
| 287 | * better to copy and encrypt at the same time. */ | 366 | * better to copy and encrypt at the same time. */ |
| 288 | 367 | ||
| 289 | blocksize = crypto_blkcipher_blocksize(kctx->enc); | 368 | blocksize = crypto_blkcipher_blocksize(kctx->enc); |
| 290 | data_start = ptr + GSS_KRB5_TOK_HDR_LEN + 8 + blocksize; | 369 | data_start = ptr + (GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength) + |
| 370 | conflen; | ||
| 291 | orig_start = buf->head[0].iov_base + offset; | 371 | orig_start = buf->head[0].iov_base + offset; |
| 292 | data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start; | 372 | data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start; |
| 293 | memmove(orig_start, data_start, data_len); | 373 | memmove(orig_start, data_start, data_len); |
| @@ -299,3 +379,209 @@ gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) | |||
| 299 | 379 | ||
| 300 | return GSS_S_COMPLETE; | 380 | return GSS_S_COMPLETE; |
| 301 | } | 381 | } |
| 382 | |||
| 383 | /* | ||
| 384 | * We cannot currently handle tokens with rotated data. We need a | ||
| 385 | * generalized routine to rotate the data in place. It is anticipated | ||
| 386 | * that we won't encounter rotated data in the general case. | ||
| 387 | */ | ||
| 388 | static u32 | ||
| 389 | rotate_left(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, u16 rrc) | ||
| 390 | { | ||
| 391 | unsigned int realrrc = rrc % (buf->len - offset - GSS_KRB5_TOK_HDR_LEN); | ||
| 392 | |||
| 393 | if (realrrc == 0) | ||
| 394 | return 0; | ||
| 395 | |||
| 396 | dprintk("%s: cannot process token with rotated data: " | ||
| 397 | "rrc %u, realrrc %u\n", __func__, rrc, realrrc); | ||
| 398 | return 1; | ||
| 399 | } | ||
| 400 | |||
| 401 | static u32 | ||
| 402 | gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | ||
| 403 | struct xdr_buf *buf, struct page **pages) | ||
| 404 | { | ||
| 405 | int blocksize; | ||
| 406 | u8 *ptr, *plainhdr; | ||
| 407 | s32 now; | ||
| 408 | u8 flags = 0x00; | ||
| 409 | __be16 *be16ptr, ec = 0; | ||
| 410 | __be64 *be64ptr; | ||
| 411 | u32 err; | ||
| 412 | |||
| 413 | dprintk("RPC: %s\n", __func__); | ||
| 414 | |||
| 415 | if (kctx->gk5e->encrypt_v2 == NULL) | ||
| 416 | return GSS_S_FAILURE; | ||
| 417 | |||
| 418 | /* make room for gss token header */ | ||
| 419 | if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN)) | ||
| 420 | return GSS_S_FAILURE; | ||
| 421 | |||
| 422 | /* construct gss token header */ | ||
| 423 | ptr = plainhdr = buf->head[0].iov_base + offset; | ||
| 424 | *ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff); | ||
| 425 | *ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff); | ||
| 426 | |||
| 427 | if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | ||
| 428 | flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR; | ||
| 429 | if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0) | ||
| 430 | flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY; | ||
| 431 | /* We always do confidentiality in wrap tokens */ | ||
| 432 | flags |= KG2_TOKEN_FLAG_SEALED; | ||
| 433 | |||
| 434 | *ptr++ = flags; | ||
| 435 | *ptr++ = 0xff; | ||
| 436 | be16ptr = (__be16 *)ptr; | ||
| 437 | |||
| 438 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); | ||
| 439 | *be16ptr++ = cpu_to_be16(ec); | ||
| 440 | /* "inner" token header always uses 0 for RRC */ | ||
| 441 | *be16ptr++ = cpu_to_be16(0); | ||
| 442 | |||
| 443 | be64ptr = (__be64 *)be16ptr; | ||
| 444 | spin_lock(&krb5_seq_lock); | ||
| 445 | *be64ptr = cpu_to_be64(kctx->seq_send64++); | ||
| 446 | spin_unlock(&krb5_seq_lock); | ||
| 447 | |||
| 448 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages); | ||
| 449 | if (err) | ||
| 450 | return err; | ||
| 451 | |||
| 452 | now = get_seconds(); | ||
| 453 | return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE; | ||
| 454 | } | ||
| 455 | |||
| 456 | static u32 | ||
| 457 | gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf) | ||
| 458 | { | ||
| 459 | s32 now; | ||
| 460 | u64 seqnum; | ||
| 461 | u8 *ptr; | ||
| 462 | u8 flags = 0x00; | ||
| 463 | u16 ec, rrc; | ||
| 464 | int err; | ||
| 465 | u32 headskip, tailskip; | ||
| 466 | u8 decrypted_hdr[GSS_KRB5_TOK_HDR_LEN]; | ||
| 467 | unsigned int movelen; | ||
| 468 | |||
| 469 | |||
| 470 | dprintk("RPC: %s\n", __func__); | ||
| 471 | |||
| 472 | if (kctx->gk5e->decrypt_v2 == NULL) | ||
| 473 | return GSS_S_FAILURE; | ||
| 474 | |||
| 475 | ptr = buf->head[0].iov_base + offset; | ||
| 476 | |||
| 477 | if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP) | ||
| 478 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 479 | |||
| 480 | flags = ptr[2]; | ||
| 481 | if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) || | ||
| 482 | (kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR))) | ||
| 483 | return GSS_S_BAD_SIG; | ||
| 484 | |||
| 485 | if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) { | ||
| 486 | dprintk("%s: token missing expected sealed flag\n", __func__); | ||
| 487 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 488 | } | ||
| 489 | |||
| 490 | if (ptr[3] != 0xff) | ||
| 491 | return GSS_S_DEFECTIVE_TOKEN; | ||
| 492 | |||
| 493 | ec = be16_to_cpup((__be16 *)(ptr + 4)); | ||
| 494 | rrc = be16_to_cpup((__be16 *)(ptr + 6)); | ||
| 495 | |||
| 496 | seqnum = be64_to_cpup((__be64 *)(ptr + 8)); | ||
| 497 | |||
| 498 | if (rrc != 0) { | ||
| 499 | err = rotate_left(kctx, offset, buf, rrc); | ||
| 500 | if (err) | ||
| 501 | return GSS_S_FAILURE; | ||
| 502 | } | ||
| 503 | |||
| 504 | err = (*kctx->gk5e->decrypt_v2)(kctx, offset, buf, | ||
| 505 | &headskip, &tailskip); | ||
| 506 | if (err) | ||
| 507 | return GSS_S_FAILURE; | ||
| 508 | |||
| 509 | /* | ||
| 510 | * Retrieve the decrypted gss token header and verify | ||
| 511 | * it against the original | ||
| 512 | */ | ||
| 513 | err = read_bytes_from_xdr_buf(buf, | ||
| 514 | buf->len - GSS_KRB5_TOK_HDR_LEN - tailskip, | ||
| 515 | decrypted_hdr, GSS_KRB5_TOK_HDR_LEN); | ||
| 516 | if (err) { | ||
| 517 | dprintk("%s: error %u getting decrypted_hdr\n", __func__, err); | ||
| 518 | return GSS_S_FAILURE; | ||
| 519 | } | ||
| 520 | if (memcmp(ptr, decrypted_hdr, 6) | ||
| 521 | || memcmp(ptr + 8, decrypted_hdr + 8, 8)) { | ||
| 522 | dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__); | ||
| 523 | return GSS_S_FAILURE; | ||
| 524 | } | ||
| 525 | |||
| 526 | /* do sequencing checks */ | ||
| 527 | |||
| 528 | /* it got through unscathed. Make sure the context is unexpired */ | ||
| 529 | now = get_seconds(); | ||
| 530 | if (now > kctx->endtime) | ||
| 531 | return GSS_S_CONTEXT_EXPIRED; | ||
| 532 | |||
| 533 | /* | ||
| 534 | * Move the head data back to the right position in xdr_buf. | ||
| 535 | * We ignore any "ec" data since it might be in the head or | ||
| 536 | * the tail, and we really don't need to deal with it. | ||
| 537 | * Note that buf->head[0].iov_len may indicate the available | ||
| 538 | * head buffer space rather than that actually occupied. | ||
| 539 | */ | ||
| 540 | movelen = min_t(unsigned int, buf->head[0].iov_len, buf->len); | ||
| 541 | movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip; | ||
| 542 | BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen > | ||
| 543 | buf->head[0].iov_len); | ||
| 544 | memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen); | ||
| 545 | buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip; | ||
| 546 | buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip; | ||
| 547 | |||
| 548 | return GSS_S_COMPLETE; | ||
| 549 | } | ||
| 550 | |||
| 551 | u32 | ||
| 552 | gss_wrap_kerberos(struct gss_ctx *gctx, int offset, | ||
| 553 | struct xdr_buf *buf, struct page **pages) | ||
| 554 | { | ||
| 555 | struct krb5_ctx *kctx = gctx->internal_ctx_id; | ||
| 556 | |||
| 557 | switch (kctx->enctype) { | ||
| 558 | default: | ||
| 559 | BUG(); | ||
| 560 | case ENCTYPE_DES_CBC_RAW: | ||
| 561 | case ENCTYPE_DES3_CBC_RAW: | ||
| 562 | case ENCTYPE_ARCFOUR_HMAC: | ||
| 563 | return gss_wrap_kerberos_v1(kctx, offset, buf, pages); | ||
| 564 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 565 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 566 | return gss_wrap_kerberos_v2(kctx, offset, buf, pages); | ||
| 567 | } | ||
| 568 | } | ||
| 569 | |||
| 570 | u32 | ||
| 571 | gss_unwrap_kerberos(struct gss_ctx *gctx, int offset, struct xdr_buf *buf) | ||
| 572 | { | ||
| 573 | struct krb5_ctx *kctx = gctx->internal_ctx_id; | ||
| 574 | |||
| 575 | switch (kctx->enctype) { | ||
| 576 | default: | ||
| 577 | BUG(); | ||
| 578 | case ENCTYPE_DES_CBC_RAW: | ||
| 579 | case ENCTYPE_DES3_CBC_RAW: | ||
| 580 | case ENCTYPE_ARCFOUR_HMAC: | ||
| 581 | return gss_unwrap_kerberos_v1(kctx, offset, buf); | ||
| 582 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | ||
| 583 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | ||
| 584 | return gss_unwrap_kerberos_v2(kctx, offset, buf); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 76e4c6f4ac3c..2689de39dc78 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
| @@ -249,14 +249,15 @@ EXPORT_SYMBOL_GPL(gss_mech_put); | |||
| 249 | int | 249 | int |
| 250 | gss_import_sec_context(const void *input_token, size_t bufsize, | 250 | gss_import_sec_context(const void *input_token, size_t bufsize, |
| 251 | struct gss_api_mech *mech, | 251 | struct gss_api_mech *mech, |
| 252 | struct gss_ctx **ctx_id) | 252 | struct gss_ctx **ctx_id, |
| 253 | gfp_t gfp_mask) | ||
| 253 | { | 254 | { |
| 254 | if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL))) | 255 | if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask))) |
| 255 | return -ENOMEM; | 256 | return -ENOMEM; |
| 256 | (*ctx_id)->mech_type = gss_mech_get(mech); | 257 | (*ctx_id)->mech_type = gss_mech_get(mech); |
| 257 | 258 | ||
| 258 | return mech->gm_ops | 259 | return mech->gm_ops |
| 259 | ->gss_import_sec_context(input_token, bufsize, *ctx_id); | 260 | ->gss_import_sec_context(input_token, bufsize, *ctx_id, gfp_mask); |
| 260 | } | 261 | } |
| 261 | 262 | ||
| 262 | /* gss_get_mic: compute a mic over message and return mic_token. */ | 263 | /* gss_get_mic: compute a mic over message and return mic_token. */ |
| @@ -285,6 +286,20 @@ gss_verify_mic(struct gss_ctx *context_handle, | |||
| 285 | mic_token); | 286 | mic_token); |
| 286 | } | 287 | } |
| 287 | 288 | ||
| 289 | /* | ||
| 290 | * This function is called from both the client and server code. | ||
| 291 | * Each makes guarantees about how much "slack" space is available | ||
| 292 | * for the underlying function in "buf"'s head and tail while | ||
| 293 | * performing the wrap. | ||
| 294 | * | ||
| 295 | * The client and server code allocate RPC_MAX_AUTH_SIZE extra | ||
| 296 | * space in both the head and tail which is available for use by | ||
| 297 | * the wrap function. | ||
| 298 | * | ||
| 299 | * Underlying functions should verify they do not use more than | ||
| 300 | * RPC_MAX_AUTH_SIZE of extra space in either the head or tail | ||
| 301 | * when performing the wrap. | ||
| 302 | */ | ||
| 288 | u32 | 303 | u32 |
| 289 | gss_wrap(struct gss_ctx *ctx_id, | 304 | gss_wrap(struct gss_ctx *ctx_id, |
| 290 | int offset, | 305 | int offset, |
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c index 035e1dd6af1b..dc3f1f5ed865 100644 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |||
| @@ -84,13 +84,14 @@ simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) | |||
| 84 | 84 | ||
| 85 | static int | 85 | static int |
| 86 | gss_import_sec_context_spkm3(const void *p, size_t len, | 86 | gss_import_sec_context_spkm3(const void *p, size_t len, |
| 87 | struct gss_ctx *ctx_id) | 87 | struct gss_ctx *ctx_id, |
| 88 | gfp_t gfp_mask) | ||
| 88 | { | 89 | { |
| 89 | const void *end = (const void *)((const char *)p + len); | 90 | const void *end = (const void *)((const char *)p + len); |
| 90 | struct spkm3_ctx *ctx; | 91 | struct spkm3_ctx *ctx; |
| 91 | int version; | 92 | int version; |
| 92 | 93 | ||
| 93 | if (!(ctx = kzalloc(sizeof(*ctx), GFP_NOFS))) | 94 | if (!(ctx = kzalloc(sizeof(*ctx), gfp_mask))) |
| 94 | goto out_err; | 95 | goto out_err; |
| 95 | 96 | ||
| 96 | p = simple_get_bytes(p, end, &version, sizeof(version)); | 97 | p = simple_get_bytes(p, end, &version, sizeof(version)); |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index b81e790ef9f4..cc385b3a59c2 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
| @@ -494,7 +494,7 @@ static int rsc_parse(struct cache_detail *cd, | |||
| 494 | len = qword_get(&mesg, buf, mlen); | 494 | len = qword_get(&mesg, buf, mlen); |
| 495 | if (len < 0) | 495 | if (len < 0) |
| 496 | goto out; | 496 | goto out; |
| 497 | status = gss_import_sec_context(buf, len, gm, &rsci.mechctx); | 497 | status = gss_import_sec_context(buf, len, gm, &rsci.mechctx, GFP_KERNEL); |
| 498 | if (status) | 498 | if (status) |
| 499 | goto out; | 499 | goto out; |
| 500 | 500 | ||
| @@ -1315,6 +1315,14 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) | |||
| 1315 | inpages = resbuf->pages; | 1315 | inpages = resbuf->pages; |
| 1316 | /* XXX: Would be better to write some xdr helper functions for | 1316 | /* XXX: Would be better to write some xdr helper functions for |
| 1317 | * nfs{2,3,4}xdr.c that place the data right, instead of copying: */ | 1317 | * nfs{2,3,4}xdr.c that place the data right, instead of copying: */ |
| 1318 | |||
| 1319 | /* | ||
| 1320 | * If there is currently tail data, make sure there is | ||
| 1321 | * room for the head, tail, and 2 * RPC_MAX_AUTH_SIZE in | ||
| 1322 | * the page, and move the current tail data such that | ||
| 1323 | * there is RPC_MAX_AUTH_SIZE slack space available in | ||
| 1324 | * both the head and tail. | ||
| 1325 | */ | ||
| 1318 | if (resbuf->tail[0].iov_base) { | 1326 | if (resbuf->tail[0].iov_base) { |
| 1319 | BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base | 1327 | BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base |
| 1320 | + PAGE_SIZE); | 1328 | + PAGE_SIZE); |
| @@ -1327,6 +1335,13 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp) | |||
| 1327 | resbuf->tail[0].iov_len); | 1335 | resbuf->tail[0].iov_len); |
| 1328 | resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE; | 1336 | resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE; |
| 1329 | } | 1337 | } |
| 1338 | /* | ||
| 1339 | * If there is no current tail data, make sure there is | ||
| 1340 | * room for the head data, and 2 * RPC_MAX_AUTH_SIZE in the | ||
| 1341 | * allotted page, and set up tail information such that there | ||
| 1342 | * is RPC_MAX_AUTH_SIZE slack space available in both the | ||
| 1343 | * head and tail. | ||
| 1344 | */ | ||
| 1330 | if (resbuf->tail[0].iov_base == NULL) { | 1345 | if (resbuf->tail[0].iov_base == NULL) { |
| 1331 | if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE) | 1346 | if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE) |
| 1332 | return -ENOMEM; | 1347 | return -ENOMEM; |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 19c9983d5360..8c7b5433022a 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -556,26 +556,16 @@ static const struct rpc_call_ops rpc_default_ops = { | |||
| 556 | */ | 556 | */ |
| 557 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) | 557 | struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data) |
| 558 | { | 558 | { |
| 559 | struct rpc_task *task, *ret; | 559 | struct rpc_task *task; |
| 560 | 560 | ||
| 561 | task = rpc_new_task(task_setup_data); | 561 | task = rpc_new_task(task_setup_data); |
| 562 | if (task == NULL) { | 562 | if (IS_ERR(task)) |
| 563 | rpc_release_calldata(task_setup_data->callback_ops, | ||
| 564 | task_setup_data->callback_data); | ||
| 565 | ret = ERR_PTR(-ENOMEM); | ||
| 566 | goto out; | 563 | goto out; |
| 567 | } | ||
| 568 | 564 | ||
| 569 | if (task->tk_status != 0) { | ||
| 570 | ret = ERR_PTR(task->tk_status); | ||
| 571 | rpc_put_task(task); | ||
| 572 | goto out; | ||
| 573 | } | ||
| 574 | atomic_inc(&task->tk_count); | 565 | atomic_inc(&task->tk_count); |
| 575 | rpc_execute(task); | 566 | rpc_execute(task); |
| 576 | ret = task; | ||
| 577 | out: | 567 | out: |
| 578 | return ret; | 568 | return task; |
| 579 | } | 569 | } |
| 580 | EXPORT_SYMBOL_GPL(rpc_run_task); | 570 | EXPORT_SYMBOL_GPL(rpc_run_task); |
| 581 | 571 | ||
| @@ -657,9 +647,8 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, | |||
| 657 | * Create an rpc_task to send the data | 647 | * Create an rpc_task to send the data |
| 658 | */ | 648 | */ |
| 659 | task = rpc_new_task(&task_setup_data); | 649 | task = rpc_new_task(&task_setup_data); |
| 660 | if (!task) { | 650 | if (IS_ERR(task)) { |
| 661 | xprt_free_bc_request(req); | 651 | xprt_free_bc_request(req); |
| 662 | task = ERR_PTR(-ENOMEM); | ||
| 663 | goto out; | 652 | goto out; |
| 664 | } | 653 | } |
| 665 | task->tk_rqstp = req; | 654 | task->tk_rqstp = req; |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index aae6907fd546..4a843b883b89 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | #ifdef RPC_DEBUG | 26 | #ifdef RPC_DEBUG |
| 27 | #define RPCDBG_FACILITY RPCDBG_SCHED | 27 | #define RPCDBG_FACILITY RPCDBG_SCHED |
| 28 | #define RPC_TASK_MAGIC_ID 0xf00baa | ||
| 29 | #endif | 28 | #endif |
| 30 | 29 | ||
| 31 | /* | 30 | /* |
| @@ -237,7 +236,6 @@ static void rpc_task_set_debuginfo(struct rpc_task *task) | |||
| 237 | { | 236 | { |
| 238 | static atomic_t rpc_pid; | 237 | static atomic_t rpc_pid; |
| 239 | 238 | ||
| 240 | task->tk_magic = RPC_TASK_MAGIC_ID; | ||
| 241 | task->tk_pid = atomic_inc_return(&rpc_pid); | 239 | task->tk_pid = atomic_inc_return(&rpc_pid); |
| 242 | } | 240 | } |
| 243 | #else | 241 | #else |
| @@ -360,9 +358,6 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task | |||
| 360 | dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", | 358 | dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n", |
| 361 | task->tk_pid, jiffies); | 359 | task->tk_pid, jiffies); |
| 362 | 360 | ||
| 363 | #ifdef RPC_DEBUG | ||
| 364 | BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); | ||
| 365 | #endif | ||
| 366 | /* Has the task been executed yet? If not, we cannot wake it up! */ | 361 | /* Has the task been executed yet? If not, we cannot wake it up! */ |
| 367 | if (!RPC_IS_ACTIVATED(task)) { | 362 | if (!RPC_IS_ACTIVATED(task)) { |
| 368 | printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); | 363 | printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task); |
| @@ -834,7 +829,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
| 834 | } | 829 | } |
| 835 | 830 | ||
| 836 | /* starting timestamp */ | 831 | /* starting timestamp */ |
| 837 | task->tk_start = jiffies; | 832 | task->tk_start = ktime_get(); |
| 838 | 833 | ||
| 839 | dprintk("RPC: new task initialized, procpid %u\n", | 834 | dprintk("RPC: new task initialized, procpid %u\n", |
| 840 | task_pid_nr(current)); | 835 | task_pid_nr(current)); |
| @@ -856,16 +851,23 @@ struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data) | |||
| 856 | 851 | ||
| 857 | if (task == NULL) { | 852 | if (task == NULL) { |
| 858 | task = rpc_alloc_task(); | 853 | task = rpc_alloc_task(); |
| 859 | if (task == NULL) | 854 | if (task == NULL) { |
| 860 | goto out; | 855 | rpc_release_calldata(setup_data->callback_ops, |
| 856 | setup_data->callback_data); | ||
| 857 | return ERR_PTR(-ENOMEM); | ||
| 858 | } | ||
| 861 | flags = RPC_TASK_DYNAMIC; | 859 | flags = RPC_TASK_DYNAMIC; |
| 862 | } | 860 | } |
| 863 | 861 | ||
| 864 | rpc_init_task(task, setup_data); | 862 | rpc_init_task(task, setup_data); |
| 863 | if (task->tk_status < 0) { | ||
| 864 | int err = task->tk_status; | ||
| 865 | rpc_put_task(task); | ||
| 866 | return ERR_PTR(err); | ||
| 867 | } | ||
| 865 | 868 | ||
| 866 | task->tk_flags |= flags; | 869 | task->tk_flags |= flags; |
| 867 | dprintk("RPC: allocated task %p\n", task); | 870 | dprintk("RPC: allocated task %p\n", task); |
| 868 | out: | ||
| 869 | return task; | 871 | return task; |
| 870 | } | 872 | } |
| 871 | 873 | ||
| @@ -909,9 +911,6 @@ EXPORT_SYMBOL_GPL(rpc_put_task); | |||
| 909 | 911 | ||
| 910 | static void rpc_release_task(struct rpc_task *task) | 912 | static void rpc_release_task(struct rpc_task *task) |
| 911 | { | 913 | { |
| 912 | #ifdef RPC_DEBUG | ||
| 913 | BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); | ||
| 914 | #endif | ||
| 915 | dprintk("RPC: %5u release task\n", task->tk_pid); | 914 | dprintk("RPC: %5u release task\n", task->tk_pid); |
| 916 | 915 | ||
| 917 | if (!list_empty(&task->tk_task)) { | 916 | if (!list_empty(&task->tk_task)) { |
| @@ -923,9 +922,6 @@ static void rpc_release_task(struct rpc_task *task) | |||
| 923 | } | 922 | } |
| 924 | BUG_ON (RPC_IS_QUEUED(task)); | 923 | BUG_ON (RPC_IS_QUEUED(task)); |
| 925 | 924 | ||
| 926 | #ifdef RPC_DEBUG | ||
| 927 | task->tk_magic = 0; | ||
| 928 | #endif | ||
| 929 | /* Wake up anyone who is waiting for task completion */ | 925 | /* Wake up anyone who is waiting for task completion */ |
| 930 | rpc_mark_complete_task(task); | 926 | rpc_mark_complete_task(task); |
| 931 | 927 | ||
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 5785d2037f45..ea1046f3f9a3 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
| @@ -144,7 +144,7 @@ void rpc_count_iostats(struct rpc_task *task) | |||
| 144 | struct rpc_rqst *req = task->tk_rqstp; | 144 | struct rpc_rqst *req = task->tk_rqstp; |
| 145 | struct rpc_iostats *stats; | 145 | struct rpc_iostats *stats; |
| 146 | struct rpc_iostats *op_metrics; | 146 | struct rpc_iostats *op_metrics; |
| 147 | long rtt, execute, queue; | 147 | ktime_t delta; |
| 148 | 148 | ||
| 149 | if (!task->tk_client || !task->tk_client->cl_metrics || !req) | 149 | if (!task->tk_client || !task->tk_client->cl_metrics || !req) |
| 150 | return; | 150 | return; |
| @@ -156,23 +156,16 @@ void rpc_count_iostats(struct rpc_task *task) | |||
| 156 | op_metrics->om_ntrans += req->rq_ntrans; | 156 | op_metrics->om_ntrans += req->rq_ntrans; |
| 157 | op_metrics->om_timeouts += task->tk_timeouts; | 157 | op_metrics->om_timeouts += task->tk_timeouts; |
| 158 | 158 | ||
| 159 | op_metrics->om_bytes_sent += task->tk_bytes_sent; | 159 | op_metrics->om_bytes_sent += req->rq_xmit_bytes_sent; |
| 160 | op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd; | 160 | op_metrics->om_bytes_recv += req->rq_reply_bytes_recvd; |
| 161 | 161 | ||
| 162 | queue = (long)req->rq_xtime - task->tk_start; | 162 | delta = ktime_sub(req->rq_xtime, task->tk_start); |
| 163 | if (queue < 0) | 163 | op_metrics->om_queue = ktime_add(op_metrics->om_queue, delta); |
| 164 | queue = -queue; | ||
| 165 | op_metrics->om_queue += queue; | ||
| 166 | 164 | ||
| 167 | rtt = task->tk_rtt; | 165 | op_metrics->om_rtt = ktime_add(op_metrics->om_rtt, req->rq_rtt); |
| 168 | if (rtt < 0) | ||
| 169 | rtt = -rtt; | ||
| 170 | op_metrics->om_rtt += rtt; | ||
| 171 | 166 | ||
| 172 | execute = (long)jiffies - task->tk_start; | 167 | delta = ktime_sub(ktime_get(), task->tk_start); |
| 173 | if (execute < 0) | 168 | op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta); |
| 174 | execute = -execute; | ||
| 175 | op_metrics->om_execute += execute; | ||
| 176 | } | 169 | } |
| 177 | 170 | ||
| 178 | static void _print_name(struct seq_file *seq, unsigned int op, | 171 | static void _print_name(struct seq_file *seq, unsigned int op, |
| @@ -186,8 +179,6 @@ static void _print_name(struct seq_file *seq, unsigned int op, | |||
| 186 | seq_printf(seq, "\t%12u: ", op); | 179 | seq_printf(seq, "\t%12u: ", op); |
| 187 | } | 180 | } |
| 188 | 181 | ||
| 189 | #define MILLISECS_PER_JIFFY (1000 / HZ) | ||
| 190 | |||
| 191 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | 182 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) |
| 192 | { | 183 | { |
| 193 | struct rpc_iostats *stats = clnt->cl_metrics; | 184 | struct rpc_iostats *stats = clnt->cl_metrics; |
| @@ -214,9 +205,9 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
| 214 | metrics->om_timeouts, | 205 | metrics->om_timeouts, |
| 215 | metrics->om_bytes_sent, | 206 | metrics->om_bytes_sent, |
| 216 | metrics->om_bytes_recv, | 207 | metrics->om_bytes_recv, |
| 217 | metrics->om_queue * MILLISECS_PER_JIFFY, | 208 | ktime_to_ms(metrics->om_queue), |
| 218 | metrics->om_rtt * MILLISECS_PER_JIFFY, | 209 | ktime_to_ms(metrics->om_rtt), |
| 219 | metrics->om_execute * MILLISECS_PER_JIFFY); | 210 | ktime_to_ms(metrics->om_execute)); |
| 220 | } | 211 | } |
| 221 | } | 212 | } |
| 222 | EXPORT_SYMBOL_GPL(rpc_print_iostats); | 213 | EXPORT_SYMBOL_GPL(rpc_print_iostats); |
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 2763fde88499..a1f82a87d34d 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c | |||
| @@ -762,6 +762,7 @@ int write_bytes_to_xdr_buf(struct xdr_buf *buf, unsigned int base, void *obj, un | |||
| 762 | __write_bytes_to_xdr_buf(&subbuf, obj, len); | 762 | __write_bytes_to_xdr_buf(&subbuf, obj, len); |
| 763 | return 0; | 763 | return 0; |
| 764 | } | 764 | } |
| 765 | EXPORT_SYMBOL_GPL(write_bytes_to_xdr_buf); | ||
| 765 | 766 | ||
| 766 | int | 767 | int |
| 767 | xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) | 768 | xdr_decode_word(struct xdr_buf *buf, unsigned int base, u32 *obj) |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 42f09ade0044..65fe2e4e7cbf 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
| 44 | #include <linux/workqueue.h> | 44 | #include <linux/workqueue.h> |
| 45 | #include <linux/net.h> | 45 | #include <linux/net.h> |
| 46 | #include <linux/ktime.h> | ||
| 46 | 47 | ||
| 47 | #include <linux/sunrpc/clnt.h> | 48 | #include <linux/sunrpc/clnt.h> |
| 48 | #include <linux/sunrpc/metrics.h> | 49 | #include <linux/sunrpc/metrics.h> |
| @@ -62,7 +63,6 @@ | |||
| 62 | * Local functions | 63 | * Local functions |
| 63 | */ | 64 | */ |
| 64 | static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); | 65 | static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); |
| 65 | static inline void do_xprt_reserve(struct rpc_task *); | ||
| 66 | static void xprt_connect_status(struct rpc_task *task); | 66 | static void xprt_connect_status(struct rpc_task *task); |
| 67 | static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); | 67 | static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); |
| 68 | 68 | ||
| @@ -711,12 +711,16 @@ void xprt_connect(struct rpc_task *task) | |||
| 711 | if (task->tk_rqstp) | 711 | if (task->tk_rqstp) |
| 712 | task->tk_rqstp->rq_bytes_sent = 0; | 712 | task->tk_rqstp->rq_bytes_sent = 0; |
| 713 | 713 | ||
| 714 | task->tk_timeout = xprt->connect_timeout; | 714 | task->tk_timeout = task->tk_rqstp->rq_timeout; |
| 715 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status); | 715 | rpc_sleep_on(&xprt->pending, task, xprt_connect_status); |
| 716 | |||
| 717 | if (test_bit(XPRT_CLOSING, &xprt->state)) | ||
| 718 | return; | ||
| 719 | if (xprt_test_and_set_connecting(xprt)) | ||
| 720 | return; | ||
| 716 | xprt->stat.connect_start = jiffies; | 721 | xprt->stat.connect_start = jiffies; |
| 717 | xprt->ops->connect(task); | 722 | xprt->ops->connect(task); |
| 718 | } | 723 | } |
| 719 | return; | ||
| 720 | } | 724 | } |
| 721 | 725 | ||
| 722 | static void xprt_connect_status(struct rpc_task *task) | 726 | static void xprt_connect_status(struct rpc_task *task) |
| @@ -771,25 +775,19 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid) | |||
| 771 | } | 775 | } |
| 772 | EXPORT_SYMBOL_GPL(xprt_lookup_rqst); | 776 | EXPORT_SYMBOL_GPL(xprt_lookup_rqst); |
| 773 | 777 | ||
| 774 | /** | 778 | static void xprt_update_rtt(struct rpc_task *task) |
| 775 | * xprt_update_rtt - update an RPC client's RTT state after receiving a reply | ||
| 776 | * @task: RPC request that recently completed | ||
| 777 | * | ||
| 778 | */ | ||
| 779 | void xprt_update_rtt(struct rpc_task *task) | ||
| 780 | { | 779 | { |
| 781 | struct rpc_rqst *req = task->tk_rqstp; | 780 | struct rpc_rqst *req = task->tk_rqstp; |
| 782 | struct rpc_rtt *rtt = task->tk_client->cl_rtt; | 781 | struct rpc_rtt *rtt = task->tk_client->cl_rtt; |
| 783 | unsigned timer = task->tk_msg.rpc_proc->p_timer; | 782 | unsigned timer = task->tk_msg.rpc_proc->p_timer; |
| 783 | long m = usecs_to_jiffies(ktime_to_us(req->rq_rtt)); | ||
| 784 | 784 | ||
| 785 | if (timer) { | 785 | if (timer) { |
| 786 | if (req->rq_ntrans == 1) | 786 | if (req->rq_ntrans == 1) |
| 787 | rpc_update_rtt(rtt, timer, | 787 | rpc_update_rtt(rtt, timer, m); |
| 788 | (long)jiffies - req->rq_xtime); | ||
| 789 | rpc_set_timeo(rtt, timer, req->rq_ntrans - 1); | 788 | rpc_set_timeo(rtt, timer, req->rq_ntrans - 1); |
| 790 | } | 789 | } |
| 791 | } | 790 | } |
| 792 | EXPORT_SYMBOL_GPL(xprt_update_rtt); | ||
| 793 | 791 | ||
| 794 | /** | 792 | /** |
| 795 | * xprt_complete_rqst - called when reply processing is complete | 793 | * xprt_complete_rqst - called when reply processing is complete |
| @@ -807,7 +805,9 @@ void xprt_complete_rqst(struct rpc_task *task, int copied) | |||
| 807 | task->tk_pid, ntohl(req->rq_xid), copied); | 805 | task->tk_pid, ntohl(req->rq_xid), copied); |
| 808 | 806 | ||
| 809 | xprt->stat.recvs++; | 807 | xprt->stat.recvs++; |
| 810 | task->tk_rtt = (long)jiffies - req->rq_xtime; | 808 | req->rq_rtt = ktime_sub(ktime_get(), req->rq_xtime); |
| 809 | if (xprt->ops->timer != NULL) | ||
| 810 | xprt_update_rtt(task); | ||
| 811 | 811 | ||
| 812 | list_del_init(&req->rq_list); | 812 | list_del_init(&req->rq_list); |
| 813 | req->rq_private_buf.len = copied; | 813 | req->rq_private_buf.len = copied; |
| @@ -906,7 +906,7 @@ void xprt_transmit(struct rpc_task *task) | |||
| 906 | return; | 906 | return; |
| 907 | 907 | ||
| 908 | req->rq_connect_cookie = xprt->connect_cookie; | 908 | req->rq_connect_cookie = xprt->connect_cookie; |
| 909 | req->rq_xtime = jiffies; | 909 | req->rq_xtime = ktime_get(); |
| 910 | status = xprt->ops->send_request(task); | 910 | status = xprt->ops->send_request(task); |
| 911 | if (status != 0) { | 911 | if (status != 0) { |
| 912 | task->tk_status = status; | 912 | task->tk_status = status; |
| @@ -935,7 +935,7 @@ void xprt_transmit(struct rpc_task *task) | |||
| 935 | spin_unlock_bh(&xprt->transport_lock); | 935 | spin_unlock_bh(&xprt->transport_lock); |
| 936 | } | 936 | } |
| 937 | 937 | ||
| 938 | static inline void do_xprt_reserve(struct rpc_task *task) | 938 | static void xprt_alloc_slot(struct rpc_task *task) |
| 939 | { | 939 | { |
| 940 | struct rpc_xprt *xprt = task->tk_xprt; | 940 | struct rpc_xprt *xprt = task->tk_xprt; |
| 941 | 941 | ||
| @@ -955,6 +955,16 @@ static inline void do_xprt_reserve(struct rpc_task *task) | |||
| 955 | rpc_sleep_on(&xprt->backlog, task, NULL); | 955 | rpc_sleep_on(&xprt->backlog, task, NULL); |
| 956 | } | 956 | } |
| 957 | 957 | ||
| 958 | static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | ||
| 959 | { | ||
| 960 | memset(req, 0, sizeof(*req)); /* mark unused */ | ||
| 961 | |||
| 962 | spin_lock(&xprt->reserve_lock); | ||
| 963 | list_add(&req->rq_list, &xprt->free); | ||
| 964 | rpc_wake_up_next(&xprt->backlog); | ||
| 965 | spin_unlock(&xprt->reserve_lock); | ||
| 966 | } | ||
| 967 | |||
| 958 | /** | 968 | /** |
| 959 | * xprt_reserve - allocate an RPC request slot | 969 | * xprt_reserve - allocate an RPC request slot |
| 960 | * @task: RPC task requesting a slot allocation | 970 | * @task: RPC task requesting a slot allocation |
| @@ -968,7 +978,7 @@ void xprt_reserve(struct rpc_task *task) | |||
| 968 | 978 | ||
| 969 | task->tk_status = -EIO; | 979 | task->tk_status = -EIO; |
| 970 | spin_lock(&xprt->reserve_lock); | 980 | spin_lock(&xprt->reserve_lock); |
| 971 | do_xprt_reserve(task); | 981 | xprt_alloc_slot(task); |
| 972 | spin_unlock(&xprt->reserve_lock); | 982 | spin_unlock(&xprt->reserve_lock); |
| 973 | } | 983 | } |
| 974 | 984 | ||
| @@ -1006,14 +1016,10 @@ void xprt_release(struct rpc_task *task) | |||
| 1006 | { | 1016 | { |
| 1007 | struct rpc_xprt *xprt; | 1017 | struct rpc_xprt *xprt; |
| 1008 | struct rpc_rqst *req; | 1018 | struct rpc_rqst *req; |
| 1009 | int is_bc_request; | ||
| 1010 | 1019 | ||
| 1011 | if (!(req = task->tk_rqstp)) | 1020 | if (!(req = task->tk_rqstp)) |
| 1012 | return; | 1021 | return; |
| 1013 | 1022 | ||
| 1014 | /* Preallocated backchannel request? */ | ||
| 1015 | is_bc_request = bc_prealloc(req); | ||
| 1016 | |||
| 1017 | xprt = req->rq_xprt; | 1023 | xprt = req->rq_xprt; |
| 1018 | rpc_count_iostats(task); | 1024 | rpc_count_iostats(task); |
| 1019 | spin_lock_bh(&xprt->transport_lock); | 1025 | spin_lock_bh(&xprt->transport_lock); |
| @@ -1027,21 +1033,16 @@ void xprt_release(struct rpc_task *task) | |||
| 1027 | mod_timer(&xprt->timer, | 1033 | mod_timer(&xprt->timer, |
| 1028 | xprt->last_used + xprt->idle_timeout); | 1034 | xprt->last_used + xprt->idle_timeout); |
| 1029 | spin_unlock_bh(&xprt->transport_lock); | 1035 | spin_unlock_bh(&xprt->transport_lock); |
| 1030 | if (!bc_prealloc(req)) | 1036 | if (req->rq_buffer) |
| 1031 | xprt->ops->buf_free(req->rq_buffer); | 1037 | xprt->ops->buf_free(req->rq_buffer); |
| 1032 | task->tk_rqstp = NULL; | 1038 | task->tk_rqstp = NULL; |
| 1033 | if (req->rq_release_snd_buf) | 1039 | if (req->rq_release_snd_buf) |
| 1034 | req->rq_release_snd_buf(req); | 1040 | req->rq_release_snd_buf(req); |
| 1035 | 1041 | ||
| 1036 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); | 1042 | dprintk("RPC: %5u release request %p\n", task->tk_pid, req); |
| 1037 | if (likely(!is_bc_request)) { | 1043 | if (likely(!bc_prealloc(req))) |
| 1038 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1044 | xprt_free_slot(xprt, req); |
| 1039 | 1045 | else | |
| 1040 | spin_lock(&xprt->reserve_lock); | ||
| 1041 | list_add(&req->rq_list, &xprt->free); | ||
| 1042 | rpc_wake_up_next(&xprt->backlog); | ||
| 1043 | spin_unlock(&xprt->reserve_lock); | ||
| 1044 | } else | ||
| 1045 | xprt_free_bc_request(req); | 1046 | xprt_free_bc_request(req); |
| 1046 | } | 1047 | } |
| 1047 | 1048 | ||
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 187257b1d880..a85e866a77f7 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
| @@ -305,7 +305,6 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 305 | /* 60 second timeout, no retries */ | 305 | /* 60 second timeout, no retries */ |
| 306 | xprt->timeout = &xprt_rdma_default_timeout; | 306 | xprt->timeout = &xprt_rdma_default_timeout; |
| 307 | xprt->bind_timeout = (60U * HZ); | 307 | xprt->bind_timeout = (60U * HZ); |
| 308 | xprt->connect_timeout = (60U * HZ); | ||
| 309 | xprt->reestablish_timeout = (5U * HZ); | 308 | xprt->reestablish_timeout = (5U * HZ); |
| 310 | xprt->idle_timeout = (5U * 60 * HZ); | 309 | xprt->idle_timeout = (5U * 60 * HZ); |
| 311 | 310 | ||
| @@ -449,21 +448,19 @@ xprt_rdma_connect(struct rpc_task *task) | |||
| 449 | struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt; | 448 | struct rpc_xprt *xprt = (struct rpc_xprt *)task->tk_xprt; |
| 450 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); | 449 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); |
| 451 | 450 | ||
| 452 | if (!xprt_test_and_set_connecting(xprt)) { | 451 | if (r_xprt->rx_ep.rep_connected != 0) { |
| 453 | if (r_xprt->rx_ep.rep_connected != 0) { | 452 | /* Reconnect */ |
| 454 | /* Reconnect */ | 453 | schedule_delayed_work(&r_xprt->rdma_connect, |
| 455 | schedule_delayed_work(&r_xprt->rdma_connect, | 454 | xprt->reestablish_timeout); |
| 456 | xprt->reestablish_timeout); | 455 | xprt->reestablish_timeout <<= 1; |
| 457 | xprt->reestablish_timeout <<= 1; | 456 | if (xprt->reestablish_timeout > (30 * HZ)) |
| 458 | if (xprt->reestablish_timeout > (30 * HZ)) | 457 | xprt->reestablish_timeout = (30 * HZ); |
| 459 | xprt->reestablish_timeout = (30 * HZ); | 458 | else if (xprt->reestablish_timeout < (5 * HZ)) |
| 460 | else if (xprt->reestablish_timeout < (5 * HZ)) | 459 | xprt->reestablish_timeout = (5 * HZ); |
| 461 | xprt->reestablish_timeout = (5 * HZ); | 460 | } else { |
| 462 | } else { | 461 | schedule_delayed_work(&r_xprt->rdma_connect, 0); |
| 463 | schedule_delayed_work(&r_xprt->rdma_connect, 0); | 462 | if (!RPC_IS_ASYNC(task)) |
| 464 | if (!RPC_IS_ASYNC(task)) | 463 | flush_scheduled_work(); |
| 465 | flush_scheduled_work(); | ||
| 466 | } | ||
| 467 | } | 464 | } |
| 468 | } | 465 | } |
| 469 | 466 | ||
| @@ -677,7 +674,7 @@ xprt_rdma_send_request(struct rpc_task *task) | |||
| 677 | if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) | 674 | if (rpcrdma_ep_post(&r_xprt->rx_ia, &r_xprt->rx_ep, req)) |
| 678 | goto drop_connection; | 675 | goto drop_connection; |
| 679 | 676 | ||
| 680 | task->tk_bytes_sent += rqst->rq_snd_buf.len; | 677 | rqst->rq_xmit_bytes_sent += rqst->rq_snd_buf.len; |
| 681 | rqst->rq_bytes_sent = 0; | 678 | rqst->rq_bytes_sent = 0; |
| 682 | return 0; | 679 | return 0; |
| 683 | 680 | ||
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 9847c30b5001..02fc7f04dd17 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -138,20 +138,6 @@ static ctl_table sunrpc_table[] = { | |||
| 138 | #endif | 138 | #endif |
| 139 | 139 | ||
| 140 | /* | 140 | /* |
| 141 | * Time out for an RPC UDP socket connect. UDP socket connects are | ||
| 142 | * synchronous, but we set a timeout anyway in case of resource | ||
| 143 | * exhaustion on the local host. | ||
| 144 | */ | ||
| 145 | #define XS_UDP_CONN_TO (5U * HZ) | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Wait duration for an RPC TCP connection to be established. Solaris | ||
| 149 | * NFS over TCP uses 60 seconds, for example, which is in line with how | ||
| 150 | * long a server takes to reboot. | ||
| 151 | */ | ||
| 152 | #define XS_TCP_CONN_TO (60U * HZ) | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Wait duration for a reply from the RPC portmapper. | 141 | * Wait duration for a reply from the RPC portmapper. |
| 156 | */ | 142 | */ |
| 157 | #define XS_BIND_TO (60U * HZ) | 143 | #define XS_BIND_TO (60U * HZ) |
| @@ -542,7 +528,7 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 542 | xdr->len - req->rq_bytes_sent, status); | 528 | xdr->len - req->rq_bytes_sent, status); |
| 543 | 529 | ||
| 544 | if (status >= 0) { | 530 | if (status >= 0) { |
| 545 | task->tk_bytes_sent += status; | 531 | req->rq_xmit_bytes_sent += status; |
| 546 | if (status >= req->rq_slen) | 532 | if (status >= req->rq_slen) |
| 547 | return 0; | 533 | return 0; |
| 548 | /* Still some bytes left; set up for a retry later. */ | 534 | /* Still some bytes left; set up for a retry later. */ |
| @@ -638,7 +624,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 638 | /* If we've sent the entire packet, immediately | 624 | /* If we've sent the entire packet, immediately |
| 639 | * reset the count of bytes sent. */ | 625 | * reset the count of bytes sent. */ |
| 640 | req->rq_bytes_sent += status; | 626 | req->rq_bytes_sent += status; |
| 641 | task->tk_bytes_sent += status; | 627 | req->rq_xmit_bytes_sent += status; |
| 642 | if (likely(req->rq_bytes_sent >= req->rq_slen)) { | 628 | if (likely(req->rq_bytes_sent >= req->rq_slen)) { |
| 643 | req->rq_bytes_sent = 0; | 629 | req->rq_bytes_sent = 0; |
| 644 | return 0; | 630 | return 0; |
| @@ -858,7 +844,6 @@ static void xs_udp_data_ready(struct sock *sk, int len) | |||
| 858 | dst_confirm(skb_dst(skb)); | 844 | dst_confirm(skb_dst(skb)); |
| 859 | 845 | ||
| 860 | xprt_adjust_cwnd(task, copied); | 846 | xprt_adjust_cwnd(task, copied); |
| 861 | xprt_update_rtt(task); | ||
| 862 | xprt_complete_rqst(task, copied); | 847 | xprt_complete_rqst(task, copied); |
| 863 | 848 | ||
| 864 | out_unlock: | 849 | out_unlock: |
| @@ -2016,9 +2001,6 @@ static void xs_connect(struct rpc_task *task) | |||
| 2016 | struct rpc_xprt *xprt = task->tk_xprt; | 2001 | struct rpc_xprt *xprt = task->tk_xprt; |
| 2017 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 2002 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
| 2018 | 2003 | ||
| 2019 | if (xprt_test_and_set_connecting(xprt)) | ||
| 2020 | return; | ||
| 2021 | |||
| 2022 | if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) { | 2004 | if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) { |
| 2023 | dprintk("RPC: xs_connect delayed xprt %p for %lu " | 2005 | dprintk("RPC: xs_connect delayed xprt %p for %lu " |
| 2024 | "seconds\n", | 2006 | "seconds\n", |
| @@ -2038,16 +2020,6 @@ static void xs_connect(struct rpc_task *task) | |||
| 2038 | } | 2020 | } |
| 2039 | } | 2021 | } |
| 2040 | 2022 | ||
| 2041 | static void xs_tcp_connect(struct rpc_task *task) | ||
| 2042 | { | ||
| 2043 | struct rpc_xprt *xprt = task->tk_xprt; | ||
| 2044 | |||
| 2045 | /* Exit if we need to wait for socket shutdown to complete */ | ||
| 2046 | if (test_bit(XPRT_CLOSING, &xprt->state)) | ||
| 2047 | return; | ||
| 2048 | xs_connect(task); | ||
| 2049 | } | ||
| 2050 | |||
| 2051 | /** | 2023 | /** |
| 2052 | * xs_udp_print_stats - display UDP socket-specifc stats | 2024 | * xs_udp_print_stats - display UDP socket-specifc stats |
| 2053 | * @xprt: rpc_xprt struct containing statistics | 2025 | * @xprt: rpc_xprt struct containing statistics |
| @@ -2246,7 +2218,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { | |||
| 2246 | .release_xprt = xs_tcp_release_xprt, | 2218 | .release_xprt = xs_tcp_release_xprt, |
| 2247 | .rpcbind = rpcb_getport_async, | 2219 | .rpcbind = rpcb_getport_async, |
| 2248 | .set_port = xs_set_port, | 2220 | .set_port = xs_set_port, |
| 2249 | .connect = xs_tcp_connect, | 2221 | .connect = xs_connect, |
| 2250 | .buf_alloc = rpc_malloc, | 2222 | .buf_alloc = rpc_malloc, |
| 2251 | .buf_free = rpc_free, | 2223 | .buf_free = rpc_free, |
| 2252 | .send_request = xs_tcp_send_request, | 2224 | .send_request = xs_tcp_send_request, |
| @@ -2337,7 +2309,6 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) | |||
| 2337 | xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); | 2309 | xprt->max_payload = (1U << 16) - (MAX_HEADER << 3); |
| 2338 | 2310 | ||
| 2339 | xprt->bind_timeout = XS_BIND_TO; | 2311 | xprt->bind_timeout = XS_BIND_TO; |
| 2340 | xprt->connect_timeout = XS_UDP_CONN_TO; | ||
| 2341 | xprt->reestablish_timeout = XS_UDP_REEST_TO; | 2312 | xprt->reestablish_timeout = XS_UDP_REEST_TO; |
| 2342 | xprt->idle_timeout = XS_IDLE_DISC_TO; | 2313 | xprt->idle_timeout = XS_IDLE_DISC_TO; |
| 2343 | 2314 | ||
| @@ -2412,7 +2383,6 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
| 2412 | xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; | 2383 | xprt->max_payload = RPC_MAX_FRAGMENT_SIZE; |
| 2413 | 2384 | ||
| 2414 | xprt->bind_timeout = XS_BIND_TO; | 2385 | xprt->bind_timeout = XS_BIND_TO; |
| 2415 | xprt->connect_timeout = XS_TCP_CONN_TO; | ||
| 2416 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; | 2386 | xprt->reestablish_timeout = XS_TCP_INIT_REEST_TO; |
| 2417 | xprt->idle_timeout = XS_IDLE_DISC_TO; | 2387 | xprt->idle_timeout = XS_IDLE_DISC_TO; |
| 2418 | 2388 | ||
| @@ -2472,9 +2442,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
| 2472 | struct sock_xprt *transport; | 2442 | struct sock_xprt *transport; |
| 2473 | struct svc_sock *bc_sock; | 2443 | struct svc_sock *bc_sock; |
| 2474 | 2444 | ||
| 2475 | if (!args->bc_xprt) | ||
| 2476 | ERR_PTR(-EINVAL); | ||
| 2477 | |||
| 2478 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); | 2445 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); |
| 2479 | if (IS_ERR(xprt)) | 2446 | if (IS_ERR(xprt)) |
| 2480 | return xprt; | 2447 | return xprt; |
| @@ -2488,7 +2455,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) | |||
| 2488 | /* backchannel */ | 2455 | /* backchannel */ |
| 2489 | xprt_set_bound(xprt); | 2456 | xprt_set_bound(xprt); |
| 2490 | xprt->bind_timeout = 0; | 2457 | xprt->bind_timeout = 0; |
| 2491 | xprt->connect_timeout = 0; | ||
| 2492 | xprt->reestablish_timeout = 0; | 2458 | xprt->reestablish_timeout = 0; |
| 2493 | xprt->idle_timeout = 0; | 2459 | xprt->idle_timeout = 0; |
| 2494 | 2460 | ||
