diff options
Diffstat (limited to 'fs/nfs')
| -rw-r--r-- | fs/nfs/Kconfig | 10 | ||||
| -rw-r--r-- | fs/nfs/callback_proc.c | 19 | ||||
| -rw-r--r-- | fs/nfs/client.c | 158 | ||||
| -rw-r--r-- | fs/nfs/delegation.c | 18 | ||||
| -rw-r--r-- | fs/nfs/delegation.h | 4 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 161 | ||||
| -rw-r--r-- | fs/nfs/direct.c | 29 | ||||
| -rw-r--r-- | fs/nfs/file.c | 84 | ||||
| -rw-r--r-- | fs/nfs/fscache.c | 3 | ||||
| -rw-r--r-- | fs/nfs/getroot.c | 191 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 145 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 18 | ||||
| -rw-r--r-- | fs/nfs/iostat.h | 6 | ||||
| -rw-r--r-- | fs/nfs/namespace.c | 20 | ||||
| -rw-r--r-- | fs/nfs/nfs2xdr.c | 7 | ||||
| -rw-r--r-- | fs/nfs/nfs3acl.c | 23 | ||||
| -rw-r--r-- | fs/nfs/nfs3proc.c | 128 | ||||
| -rw-r--r-- | fs/nfs/nfs3xdr.c | 10 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 65 | ||||
| -rw-r--r-- | fs/nfs/nfs4namespace.c | 12 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 642 | ||||
| -rw-r--r-- | fs/nfs/nfs4renewd.c | 4 | ||||
| -rw-r--r-- | fs/nfs/nfs4state.c | 118 | ||||
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 133 | ||||
| -rw-r--r-- | fs/nfs/nfsroot.c | 16 | ||||
| -rw-r--r-- | fs/nfs/pagelist.c | 22 | ||||
| -rw-r--r-- | fs/nfs/proc.c | 144 | ||||
| -rw-r--r-- | fs/nfs/read.c | 7 | ||||
| -rw-r--r-- | fs/nfs/super.c | 181 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 6 | ||||
| -rw-r--r-- | fs/nfs/write.c | 59 |
31 files changed, 1479 insertions, 964 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index a43d07e7b924..cc1bb33b59b8 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -61,8 +61,8 @@ config NFS_V3_ACL | |||
| 61 | If unsure, say N. | 61 | If unsure, say N. |
| 62 | 62 | ||
| 63 | config NFS_V4 | 63 | config NFS_V4 |
| 64 | bool "NFS client support for NFS version 4 (EXPERIMENTAL)" | 64 | bool "NFS client support for NFS version 4" |
| 65 | depends on NFS_FS && EXPERIMENTAL | 65 | depends on NFS_FS |
| 66 | select RPCSEC_GSS_KRB5 | 66 | select RPCSEC_GSS_KRB5 |
| 67 | help | 67 | help |
| 68 | This option enables support for version 4 of the NFS protocol | 68 | This option enables support for version 4 of the NFS protocol |
| @@ -72,16 +72,16 @@ config NFS_V4 | |||
| 72 | space programs which can be found in the Linux nfs-utils package, | 72 | space programs which can be found in the Linux nfs-utils package, |
| 73 | available from http://linux-nfs.org/. | 73 | available from http://linux-nfs.org/. |
| 74 | 74 | ||
| 75 | If unsure, say N. | 75 | If unsure, say Y. |
| 76 | 76 | ||
| 77 | config NFS_V4_1 | 77 | config NFS_V4_1 |
| 78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | 78 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" |
| 79 | depends on NFS_V4 && EXPERIMENTAL | 79 | depends on NFS_V4 && EXPERIMENTAL |
| 80 | help | 80 | help |
| 81 | This option enables support for minor version 1 of the NFSv4 protocol | 81 | This option enables support for minor version 1 of the NFSv4 protocol |
| 82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | 82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. |
| 83 | 83 | ||
| 84 | Unless you're an NFS developer, say N. | 84 | If unsure, say N. |
| 85 | 85 | ||
| 86 | config ROOT_NFS | 86 | config ROOT_NFS |
| 87 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index a08770a7e857..930d10fecdaf 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
| @@ -37,8 +37,8 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
| 37 | if (inode == NULL) | 37 | if (inode == NULL) |
| 38 | goto out_putclient; | 38 | goto out_putclient; |
| 39 | nfsi = NFS_I(inode); | 39 | nfsi = NFS_I(inode); |
| 40 | down_read(&nfsi->rwsem); | 40 | rcu_read_lock(); |
| 41 | delegation = nfsi->delegation; | 41 | delegation = rcu_dereference(nfsi->delegation); |
| 42 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) | 42 | if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0) |
| 43 | goto out_iput; | 43 | goto out_iput; |
| 44 | res->size = i_size_read(inode); | 44 | res->size = i_size_read(inode); |
| @@ -53,7 +53,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres * | |||
| 53 | args->bitmap[1]; | 53 | args->bitmap[1]; |
| 54 | res->status = 0; | 54 | res->status = 0; |
| 55 | out_iput: | 55 | out_iput: |
| 56 | up_read(&nfsi->rwsem); | 56 | rcu_read_unlock(); |
| 57 | iput(inode); | 57 | iput(inode); |
| 58 | out_putclient: | 58 | out_putclient: |
| 59 | nfs_put_client(clp); | 59 | nfs_put_client(clp); |
| @@ -62,16 +62,6 @@ out: | |||
| 62 | return res->status; | 62 | return res->status; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *) | ||
| 66 | { | ||
| 67 | #if defined(CONFIG_NFS_V4_1) | ||
| 68 | if (clp->cl_minorversion > 0) | ||
| 69 | return nfs41_validate_delegation_stateid; | ||
| 70 | #endif | ||
| 71 | return nfs4_validate_delegation_stateid; | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | 65 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) |
| 76 | { | 66 | { |
| 77 | struct nfs_client *clp; | 67 | struct nfs_client *clp; |
| @@ -92,8 +82,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
| 92 | inode = nfs_delegation_find_inode(clp, &args->fh); | 82 | inode = nfs_delegation_find_inode(clp, &args->fh); |
| 93 | if (inode != NULL) { | 83 | if (inode != NULL) { |
| 94 | /* Set up a helper thread to actually return the delegation */ | 84 | /* Set up a helper thread to actually return the delegation */ |
| 95 | switch (nfs_async_inode_return_delegation(inode, &args->stateid, | 85 | switch (nfs_async_inode_return_delegation(inode, &args->stateid)) { |
| 96 | nfs_validate_delegation_stateid(clp))) { | ||
| 97 | case 0: | 86 | case 0: |
| 98 | res = 0; | 87 | res = 0; |
| 99 | break; | 88 | break; |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index acc9c4943b84..4e7df2adb212 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -150,6 +150,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
| 150 | clp->cl_boot_time = CURRENT_TIME; | 150 | clp->cl_boot_time = CURRENT_TIME; |
| 151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 151 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
| 152 | clp->cl_minorversion = cl_init->minorversion; | 152 | clp->cl_minorversion = cl_init->minorversion; |
| 153 | clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; | ||
| 153 | #endif | 154 | #endif |
| 154 | cred = rpc_lookup_machine_cred(); | 155 | cred = rpc_lookup_machine_cred(); |
| 155 | if (!IS_ERR(cred)) | 156 | if (!IS_ERR(cred)) |
| @@ -178,7 +179,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
| 178 | clp->cl_session = NULL; | 179 | clp->cl_session = NULL; |
| 179 | } | 180 | } |
| 180 | 181 | ||
| 181 | clp->cl_call_sync = _nfs4_call_sync; | 182 | clp->cl_mvops = nfs_v4_minor_ops[0]; |
| 182 | #endif /* CONFIG_NFS_V4_1 */ | 183 | #endif /* CONFIG_NFS_V4_1 */ |
| 183 | } | 184 | } |
| 184 | 185 | ||
| @@ -188,7 +189,7 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
| 188 | static void nfs4_destroy_callback(struct nfs_client *clp) | 189 | static void nfs4_destroy_callback(struct nfs_client *clp) |
| 189 | { | 190 | { |
| 190 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | 191 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) |
| 191 | nfs_callback_down(clp->cl_minorversion); | 192 | nfs_callback_down(clp->cl_mvops->minor_version); |
| 192 | } | 193 | } |
| 193 | 194 | ||
| 194 | static void nfs4_shutdown_client(struct nfs_client *clp) | 195 | static void nfs4_shutdown_client(struct nfs_client *clp) |
| @@ -934,7 +935,6 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str | |||
| 934 | } | 935 | } |
| 935 | 936 | ||
| 936 | fsinfo.fattr = fattr; | 937 | fsinfo.fattr = fattr; |
| 937 | nfs_fattr_init(fattr); | ||
| 938 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); | 938 | error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo); |
| 939 | if (error < 0) | 939 | if (error < 0) |
| 940 | goto out_error; | 940 | goto out_error; |
| @@ -1047,13 +1047,18 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1047 | struct nfs_fh *mntfh) | 1047 | struct nfs_fh *mntfh) |
| 1048 | { | 1048 | { |
| 1049 | struct nfs_server *server; | 1049 | struct nfs_server *server; |
| 1050 | struct nfs_fattr fattr; | 1050 | struct nfs_fattr *fattr; |
| 1051 | int error; | 1051 | int error; |
| 1052 | 1052 | ||
| 1053 | server = nfs_alloc_server(); | 1053 | server = nfs_alloc_server(); |
| 1054 | if (!server) | 1054 | if (!server) |
| 1055 | return ERR_PTR(-ENOMEM); | 1055 | return ERR_PTR(-ENOMEM); |
| 1056 | 1056 | ||
| 1057 | error = -ENOMEM; | ||
| 1058 | fattr = nfs_alloc_fattr(); | ||
| 1059 | if (fattr == NULL) | ||
| 1060 | goto error; | ||
| 1061 | |||
| 1057 | /* Get a client representation */ | 1062 | /* Get a client representation */ |
| 1058 | error = nfs_init_server(server, data); | 1063 | error = nfs_init_server(server, data); |
| 1059 | if (error < 0) | 1064 | if (error < 0) |
| @@ -1064,7 +1069,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); | 1069 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
| 1065 | 1070 | ||
| 1066 | /* Probe the root fh to retrieve its FSID */ | 1071 | /* Probe the root fh to retrieve its FSID */ |
| 1067 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1072 | error = nfs_probe_fsinfo(server, mntfh, fattr); |
| 1068 | if (error < 0) | 1073 | if (error < 0) |
| 1069 | goto error; | 1074 | goto error; |
| 1070 | if (server->nfs_client->rpc_ops->version == 3) { | 1075 | if (server->nfs_client->rpc_ops->version == 3) { |
| @@ -1077,14 +1082,14 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1077 | server->namelen = NFS2_MAXNAMLEN; | 1082 | server->namelen = NFS2_MAXNAMLEN; |
| 1078 | } | 1083 | } |
| 1079 | 1084 | ||
| 1080 | if (!(fattr.valid & NFS_ATTR_FATTR)) { | 1085 | if (!(fattr->valid & NFS_ATTR_FATTR)) { |
| 1081 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); | 1086 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
| 1082 | if (error < 0) { | 1087 | if (error < 0) { |
| 1083 | dprintk("nfs_create_server: getattr error = %d\n", -error); | 1088 | dprintk("nfs_create_server: getattr error = %d\n", -error); |
| 1084 | goto error; | 1089 | goto error; |
| 1085 | } | 1090 | } |
| 1086 | } | 1091 | } |
| 1087 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | 1092 | memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); |
| 1088 | 1093 | ||
| 1089 | dprintk("Server FSID: %llx:%llx\n", | 1094 | dprintk("Server FSID: %llx:%llx\n", |
| 1090 | (unsigned long long) server->fsid.major, | 1095 | (unsigned long long) server->fsid.major, |
| @@ -1096,9 +1101,11 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1096 | spin_unlock(&nfs_client_lock); | 1101 | spin_unlock(&nfs_client_lock); |
| 1097 | 1102 | ||
| 1098 | server->mount_time = jiffies; | 1103 | server->mount_time = jiffies; |
| 1104 | nfs_free_fattr(fattr); | ||
| 1099 | return server; | 1105 | return server; |
| 1100 | 1106 | ||
| 1101 | error: | 1107 | error: |
| 1108 | nfs_free_fattr(fattr); | ||
| 1102 | nfs_free_server(server); | 1109 | nfs_free_server(server); |
| 1103 | return ERR_PTR(error); | 1110 | return ERR_PTR(error); |
| 1104 | } | 1111 | } |
| @@ -1120,7 +1127,7 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
| 1120 | return error; | 1127 | return error; |
| 1121 | } | 1128 | } |
| 1122 | 1129 | ||
| 1123 | error = nfs_callback_up(clp->cl_minorversion, | 1130 | error = nfs_callback_up(clp->cl_mvops->minor_version, |
| 1124 | clp->cl_rpcclient->cl_xprt); | 1131 | clp->cl_rpcclient->cl_xprt); |
| 1125 | if (error < 0) { | 1132 | if (error < 0) { |
| 1126 | dprintk("%s: failed to start callback. Error = %d\n", | 1133 | dprintk("%s: failed to start callback. Error = %d\n", |
| @@ -1137,10 +1144,8 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
| 1137 | */ | 1144 | */ |
| 1138 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | 1145 | static int nfs4_init_client_minor_version(struct nfs_client *clp) |
| 1139 | { | 1146 | { |
| 1140 | clp->cl_call_sync = _nfs4_call_sync; | ||
| 1141 | |||
| 1142 | #if defined(CONFIG_NFS_V4_1) | 1147 | #if defined(CONFIG_NFS_V4_1) |
| 1143 | if (clp->cl_minorversion) { | 1148 | if (clp->cl_mvops->minor_version) { |
| 1144 | struct nfs4_session *session = NULL; | 1149 | struct nfs4_session *session = NULL; |
| 1145 | /* | 1150 | /* |
| 1146 | * Create the session and mark it expired. | 1151 | * Create the session and mark it expired. |
| @@ -1152,7 +1157,13 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp) | |||
| 1152 | return -ENOMEM; | 1157 | return -ENOMEM; |
| 1153 | 1158 | ||
| 1154 | clp->cl_session = session; | 1159 | clp->cl_session = session; |
| 1155 | clp->cl_call_sync = _nfs4_call_sync_session; | 1160 | /* |
| 1161 | * The create session reply races with the server back | ||
| 1162 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
| 1163 | * so that the client back channel can find the | ||
| 1164 | * nfs_client struct | ||
| 1165 | */ | ||
| 1166 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
| 1156 | } | 1167 | } |
| 1157 | #endif /* CONFIG_NFS_V4_1 */ | 1168 | #endif /* CONFIG_NFS_V4_1 */ |
| 1158 | 1169 | ||
| @@ -1280,6 +1291,55 @@ static void nfs4_session_set_rwsize(struct nfs_server *server) | |||
| 1280 | #endif /* CONFIG_NFS_V4_1 */ | 1291 | #endif /* CONFIG_NFS_V4_1 */ |
| 1281 | } | 1292 | } |
| 1282 | 1293 | ||
| 1294 | static int nfs4_server_common_setup(struct nfs_server *server, | ||
| 1295 | struct nfs_fh *mntfh) | ||
| 1296 | { | ||
| 1297 | struct nfs_fattr *fattr; | ||
| 1298 | int error; | ||
| 1299 | |||
| 1300 | BUG_ON(!server->nfs_client); | ||
| 1301 | BUG_ON(!server->nfs_client->rpc_ops); | ||
| 1302 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
| 1303 | |||
| 1304 | fattr = nfs_alloc_fattr(); | ||
| 1305 | if (fattr == NULL) | ||
| 1306 | return -ENOMEM; | ||
| 1307 | |||
| 1308 | /* We must ensure the session is initialised first */ | ||
| 1309 | error = nfs4_init_session(server); | ||
| 1310 | if (error < 0) | ||
| 1311 | goto out; | ||
| 1312 | |||
| 1313 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
| 1314 | error = nfs4_get_rootfh(server, mntfh); | ||
| 1315 | if (error < 0) | ||
| 1316 | goto out; | ||
| 1317 | |||
| 1318 | dprintk("Server FSID: %llx:%llx\n", | ||
| 1319 | (unsigned long long) server->fsid.major, | ||
| 1320 | (unsigned long long) server->fsid.minor); | ||
| 1321 | dprintk("Mount FH: %d\n", mntfh->size); | ||
| 1322 | |||
| 1323 | nfs4_session_set_rwsize(server); | ||
| 1324 | |||
| 1325 | error = nfs_probe_fsinfo(server, mntfh, fattr); | ||
| 1326 | if (error < 0) | ||
| 1327 | goto out; | ||
| 1328 | |||
| 1329 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
| 1330 | server->namelen = NFS4_MAXNAMLEN; | ||
| 1331 | |||
| 1332 | spin_lock(&nfs_client_lock); | ||
| 1333 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
| 1334 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
| 1335 | spin_unlock(&nfs_client_lock); | ||
| 1336 | |||
| 1337 | server->mount_time = jiffies; | ||
| 1338 | out: | ||
| 1339 | nfs_free_fattr(fattr); | ||
| 1340 | return error; | ||
| 1341 | } | ||
| 1342 | |||
| 1283 | /* | 1343 | /* |
| 1284 | * Create a version 4 volume record | 1344 | * Create a version 4 volume record |
| 1285 | */ | 1345 | */ |
| @@ -1340,7 +1400,6 @@ error: | |||
| 1340 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | 1400 | struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, |
| 1341 | struct nfs_fh *mntfh) | 1401 | struct nfs_fh *mntfh) |
| 1342 | { | 1402 | { |
| 1343 | struct nfs_fattr fattr; | ||
| 1344 | struct nfs_server *server; | 1403 | struct nfs_server *server; |
| 1345 | int error; | 1404 | int error; |
| 1346 | 1405 | ||
| @@ -1355,39 +1414,10 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
| 1355 | if (error < 0) | 1414 | if (error < 0) |
| 1356 | goto error; | 1415 | goto error; |
| 1357 | 1416 | ||
| 1358 | BUG_ON(!server->nfs_client); | 1417 | error = nfs4_server_common_setup(server, mntfh); |
| 1359 | BUG_ON(!server->nfs_client->rpc_ops); | ||
| 1360 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
| 1361 | |||
| 1362 | error = nfs4_init_session(server); | ||
| 1363 | if (error < 0) | ||
| 1364 | goto error; | ||
| 1365 | |||
| 1366 | /* Probe the root fh to retrieve its FSID */ | ||
| 1367 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | ||
| 1368 | if (error < 0) | ||
| 1369 | goto error; | ||
| 1370 | |||
| 1371 | dprintk("Server FSID: %llx:%llx\n", | ||
| 1372 | (unsigned long long) server->fsid.major, | ||
| 1373 | (unsigned long long) server->fsid.minor); | ||
| 1374 | dprintk("Mount FH: %d\n", mntfh->size); | ||
| 1375 | |||
| 1376 | nfs4_session_set_rwsize(server); | ||
| 1377 | |||
| 1378 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
| 1379 | if (error < 0) | 1418 | if (error < 0) |
| 1380 | goto error; | 1419 | goto error; |
| 1381 | 1420 | ||
| 1382 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
| 1383 | server->namelen = NFS4_MAXNAMLEN; | ||
| 1384 | |||
| 1385 | spin_lock(&nfs_client_lock); | ||
| 1386 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
| 1387 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
| 1388 | spin_unlock(&nfs_client_lock); | ||
| 1389 | |||
| 1390 | server->mount_time = jiffies; | ||
| 1391 | dprintk("<-- nfs4_create_server() = %p\n", server); | 1421 | dprintk("<-- nfs4_create_server() = %p\n", server); |
| 1392 | return server; | 1422 | return server; |
| 1393 | 1423 | ||
| @@ -1405,7 +1435,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1405 | { | 1435 | { |
| 1406 | struct nfs_client *parent_client; | 1436 | struct nfs_client *parent_client; |
| 1407 | struct nfs_server *server, *parent_server; | 1437 | struct nfs_server *server, *parent_server; |
| 1408 | struct nfs_fattr fattr; | ||
| 1409 | int error; | 1438 | int error; |
| 1410 | 1439 | ||
| 1411 | dprintk("--> nfs4_create_referral_server()\n"); | 1440 | dprintk("--> nfs4_create_referral_server()\n"); |
| @@ -1430,7 +1459,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1430 | data->authflavor, | 1459 | data->authflavor, |
| 1431 | parent_server->client->cl_xprt->prot, | 1460 | parent_server->client->cl_xprt->prot, |
| 1432 | parent_server->client->cl_timeout, | 1461 | parent_server->client->cl_timeout, |
| 1433 | parent_client->cl_minorversion); | 1462 | parent_client->cl_mvops->minor_version); |
| 1434 | if (error < 0) | 1463 | if (error < 0) |
| 1435 | goto error; | 1464 | goto error; |
| 1436 | 1465 | ||
| @@ -1438,34 +1467,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
| 1438 | if (error < 0) | 1467 | if (error < 0) |
| 1439 | goto error; | 1468 | goto error; |
| 1440 | 1469 | ||
| 1441 | BUG_ON(!server->nfs_client); | 1470 | error = nfs4_server_common_setup(server, mntfh); |
| 1442 | BUG_ON(!server->nfs_client->rpc_ops); | ||
| 1443 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | ||
| 1444 | |||
| 1445 | /* Probe the root fh to retrieve its FSID and filehandle */ | ||
| 1446 | error = nfs4_path_walk(server, mntfh, data->mnt_path); | ||
| 1447 | if (error < 0) | 1471 | if (error < 0) |
| 1448 | goto error; | 1472 | goto error; |
| 1449 | 1473 | ||
| 1450 | /* probe the filesystem info for this server filesystem */ | ||
| 1451 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | ||
| 1452 | if (error < 0) | ||
| 1453 | goto error; | ||
| 1454 | |||
| 1455 | if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) | ||
| 1456 | server->namelen = NFS4_MAXNAMLEN; | ||
| 1457 | |||
| 1458 | dprintk("Referral FSID: %llx:%llx\n", | ||
| 1459 | (unsigned long long) server->fsid.major, | ||
| 1460 | (unsigned long long) server->fsid.minor); | ||
| 1461 | |||
| 1462 | spin_lock(&nfs_client_lock); | ||
| 1463 | list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); | ||
| 1464 | list_add_tail(&server->master_link, &nfs_volume_list); | ||
| 1465 | spin_unlock(&nfs_client_lock); | ||
| 1466 | |||
| 1467 | server->mount_time = jiffies; | ||
| 1468 | |||
| 1469 | dprintk("<-- nfs_create_referral_server() = %p\n", server); | 1474 | dprintk("<-- nfs_create_referral_server() = %p\n", server); |
| 1470 | return server; | 1475 | return server; |
| 1471 | 1476 | ||
| @@ -1485,7 +1490,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1485 | struct nfs_fattr *fattr) | 1490 | struct nfs_fattr *fattr) |
| 1486 | { | 1491 | { |
| 1487 | struct nfs_server *server; | 1492 | struct nfs_server *server; |
| 1488 | struct nfs_fattr fattr_fsinfo; | 1493 | struct nfs_fattr *fattr_fsinfo; |
| 1489 | int error; | 1494 | int error; |
| 1490 | 1495 | ||
| 1491 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", | 1496 | dprintk("--> nfs_clone_server(,%llx:%llx,)\n", |
| @@ -1496,6 +1501,11 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1496 | if (!server) | 1501 | if (!server) |
| 1497 | return ERR_PTR(-ENOMEM); | 1502 | return ERR_PTR(-ENOMEM); |
| 1498 | 1503 | ||
| 1504 | error = -ENOMEM; | ||
| 1505 | fattr_fsinfo = nfs_alloc_fattr(); | ||
| 1506 | if (fattr_fsinfo == NULL) | ||
| 1507 | goto out_free_server; | ||
| 1508 | |||
| 1499 | /* Copy data from the source */ | 1509 | /* Copy data from the source */ |
| 1500 | server->nfs_client = source->nfs_client; | 1510 | server->nfs_client = source->nfs_client; |
| 1501 | atomic_inc(&server->nfs_client->cl_count); | 1511 | atomic_inc(&server->nfs_client->cl_count); |
| @@ -1512,7 +1522,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1512 | nfs_init_server_aclclient(server); | 1522 | nfs_init_server_aclclient(server); |
| 1513 | 1523 | ||
| 1514 | /* probe the filesystem info for this server filesystem */ | 1524 | /* probe the filesystem info for this server filesystem */ |
| 1515 | error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo); | 1525 | error = nfs_probe_fsinfo(server, fh, fattr_fsinfo); |
| 1516 | if (error < 0) | 1526 | if (error < 0) |
| 1517 | goto out_free_server; | 1527 | goto out_free_server; |
| 1518 | 1528 | ||
| @@ -1534,10 +1544,12 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, | |||
| 1534 | 1544 | ||
| 1535 | server->mount_time = jiffies; | 1545 | server->mount_time = jiffies; |
| 1536 | 1546 | ||
| 1547 | nfs_free_fattr(fattr_fsinfo); | ||
| 1537 | dprintk("<-- nfs_clone_server() = %p\n", server); | 1548 | dprintk("<-- nfs_clone_server() = %p\n", server); |
| 1538 | return server; | 1549 | return server; |
| 1539 | 1550 | ||
| 1540 | out_free_server: | 1551 | out_free_server: |
| 1552 | nfs_free_fattr(fattr_fsinfo); | ||
| 1541 | nfs_free_server(server); | 1553 | nfs_free_server(server); |
| 1542 | dprintk("<-- nfs_clone_server() = error %d\n", error); | 1554 | dprintk("<-- nfs_clone_server() = error %d\n", error); |
| 1543 | return ERR_PTR(error); | 1555 | return ERR_PTR(error); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ea61d26e7871..b9c3c43cea1d 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, |
| @@ -268,14 +268,6 @@ out: | |||
| 268 | return status; | 268 | return status; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | /* Sync all data to disk upon delegation return */ | ||
| 272 | static void nfs_msync_inode(struct inode *inode) | ||
| 273 | { | ||
| 274 | filemap_fdatawrite(inode->i_mapping); | ||
| 275 | nfs_wb_all(inode); | ||
| 276 | filemap_fdatawait(inode->i_mapping); | ||
| 277 | } | ||
| 278 | |||
| 279 | /* | 271 | /* |
| 280 | * Basic procedure for returning a delegation to the server | 272 | * Basic procedure for returning a delegation to the server |
| 281 | */ | 273 | */ |
| @@ -367,7 +359,7 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
| 367 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); | 359 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
| 368 | spin_unlock(&clp->cl_lock); | 360 | spin_unlock(&clp->cl_lock); |
| 369 | if (delegation != NULL) { | 361 | if (delegation != NULL) { |
| 370 | nfs_msync_inode(inode); | 362 | nfs_wb_all(inode); |
| 371 | err = __nfs_inode_return_delegation(inode, delegation, 1); | 363 | err = __nfs_inode_return_delegation(inode, delegation, 1); |
| 372 | } | 364 | } |
| 373 | } | 365 | } |
| @@ -471,9 +463,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) | |||
| 471 | /* | 463 | /* |
| 472 | * Asynchronous delegation recall! | 464 | * Asynchronous delegation recall! |
| 473 | */ | 465 | */ |
| 474 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, | 466 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) |
| 475 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
| 476 | const nfs4_stateid *stateid)) | ||
| 477 | { | 467 | { |
| 478 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 468 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 479 | struct nfs_delegation *delegation; | 469 | struct nfs_delegation *delegation; |
| @@ -481,7 +471,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
| 481 | rcu_read_lock(); | 471 | rcu_read_lock(); |
| 482 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 472 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 483 | 473 | ||
| 484 | if (!validate_stateid(delegation, stateid)) { | 474 | if (!clp->cl_mvops->validate_stateid(delegation, stateid)) { |
| 485 | rcu_read_unlock(); | 475 | rcu_read_unlock(); |
| 486 | return -ENOENT; | 476 | return -ENOENT; |
| 487 | } | 477 | } |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 69e7b8140122..2026304bda19 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -34,9 +34,7 @@ enum { | |||
| 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
| 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
| 36 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs_inode_return_delegation(struct inode *inode); |
| 37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, | 37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); |
| 38 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
| 39 | const nfs4_stateid *stateid)); | ||
| 40 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
| 41 | 39 | ||
| 42 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a7bb5c694aa3..29539ceeb745 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -53,7 +53,7 @@ static int nfs_link(struct dentry *, struct inode *, struct dentry *); | |||
| 53 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); | 53 | static int nfs_mknod(struct inode *, struct dentry *, int, dev_t); |
| 54 | static int nfs_rename(struct inode *, struct dentry *, | 54 | static int nfs_rename(struct inode *, struct dentry *, |
| 55 | struct inode *, struct dentry *); | 55 | struct inode *, struct dentry *); |
| 56 | static int nfs_fsync_dir(struct file *, struct dentry *, int); | 56 | static int nfs_fsync_dir(struct file *, int); |
| 57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 57 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
| 58 | 58 | ||
| 59 | const struct file_operations nfs_dir_operations = { | 59 | const struct file_operations nfs_dir_operations = { |
| @@ -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; |
| @@ -638,8 +641,10 @@ out: | |||
| 638 | * All directory operations under NFS are synchronous, so fsync() | 641 | * All directory operations under NFS are synchronous, so fsync() |
| 639 | * is a dummy operation. | 642 | * is a dummy operation. |
| 640 | */ | 643 | */ |
| 641 | static int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | 644 | static int nfs_fsync_dir(struct file *filp, int datasync) |
| 642 | { | 645 | { |
| 646 | struct dentry *dentry = filp->f_path.dentry; | ||
| 647 | |||
| 643 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", | 648 | dfprintk(FILE, "NFS: fsync dir(%s/%s) datasync %d\n", |
| 644 | dentry->d_parent->d_name.name, dentry->d_name.name, | 649 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 645 | datasync); | 650 | datasync); |
| @@ -776,9 +781,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 776 | struct inode *dir; | 781 | struct inode *dir; |
| 777 | struct inode *inode; | 782 | struct inode *inode; |
| 778 | struct dentry *parent; | 783 | struct dentry *parent; |
| 784 | struct nfs_fh *fhandle = NULL; | ||
| 785 | struct nfs_fattr *fattr = NULL; | ||
| 779 | int error; | 786 | int error; |
| 780 | struct nfs_fh fhandle; | ||
| 781 | struct nfs_fattr fattr; | ||
| 782 | 787 | ||
| 783 | parent = dget_parent(dentry); | 788 | parent = dget_parent(dentry); |
| 784 | dir = parent->d_inode; | 789 | dir = parent->d_inode; |
| @@ -811,14 +816,22 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
| 811 | if (NFS_STALE(inode)) | 816 | if (NFS_STALE(inode)) |
| 812 | goto out_bad; | 817 | goto out_bad; |
| 813 | 818 | ||
| 814 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 819 | error = -ENOMEM; |
| 820 | fhandle = nfs_alloc_fhandle(); | ||
| 821 | fattr = nfs_alloc_fattr(); | ||
| 822 | if (fhandle == NULL || fattr == NULL) | ||
| 823 | goto out_error; | ||
| 824 | |||
| 825 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); | ||
| 815 | if (error) | 826 | if (error) |
| 816 | goto out_bad; | 827 | goto out_bad; |
| 817 | if (nfs_compare_fh(NFS_FH(inode), &fhandle)) | 828 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
| 818 | goto out_bad; | 829 | goto out_bad; |
| 819 | if ((error = nfs_refresh_inode(inode, &fattr)) != 0) | 830 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
| 820 | goto out_bad; | 831 | goto out_bad; |
| 821 | 832 | ||
| 833 | nfs_free_fattr(fattr); | ||
| 834 | nfs_free_fhandle(fhandle); | ||
| 822 | out_set_verifier: | 835 | out_set_verifier: |
| 823 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 836 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 824 | out_valid: | 837 | out_valid: |
| @@ -842,11 +855,21 @@ out_zap_parent: | |||
| 842 | shrink_dcache_parent(dentry); | 855 | shrink_dcache_parent(dentry); |
| 843 | } | 856 | } |
| 844 | d_drop(dentry); | 857 | d_drop(dentry); |
| 858 | nfs_free_fattr(fattr); | ||
| 859 | nfs_free_fhandle(fhandle); | ||
| 845 | dput(parent); | 860 | dput(parent); |
| 846 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 861 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
| 847 | __func__, dentry->d_parent->d_name.name, | 862 | __func__, dentry->d_parent->d_name.name, |
| 848 | dentry->d_name.name); | 863 | dentry->d_name.name); |
| 849 | return 0; | 864 | return 0; |
| 865 | out_error: | ||
| 866 | nfs_free_fattr(fattr); | ||
| 867 | nfs_free_fhandle(fhandle); | ||
| 868 | dput(parent); | ||
| 869 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", | ||
| 870 | __func__, dentry->d_parent->d_name.name, | ||
| 871 | dentry->d_name.name, error); | ||
| 872 | return error; | ||
| 850 | } | 873 | } |
| 851 | 874 | ||
| 852 | /* | 875 | /* |
| @@ -911,9 +934,9 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 911 | struct dentry *res; | 934 | struct dentry *res; |
| 912 | struct dentry *parent; | 935 | struct dentry *parent; |
| 913 | struct inode *inode = NULL; | 936 | struct inode *inode = NULL; |
| 937 | struct nfs_fh *fhandle = NULL; | ||
| 938 | struct nfs_fattr *fattr = NULL; | ||
| 914 | int error; | 939 | int error; |
| 915 | struct nfs_fh fhandle; | ||
| 916 | struct nfs_fattr fattr; | ||
| 917 | 940 | ||
| 918 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", | 941 | dfprintk(VFS, "NFS: lookup(%s/%s)\n", |
| 919 | dentry->d_parent->d_name.name, dentry->d_name.name); | 942 | dentry->d_parent->d_name.name, dentry->d_name.name); |
| @@ -923,7 +946,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 923 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 946 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
| 924 | goto out; | 947 | goto out; |
| 925 | 948 | ||
| 926 | res = ERR_PTR(-ENOMEM); | ||
| 927 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 949 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; |
| 928 | 950 | ||
| 929 | /* | 951 | /* |
| @@ -936,17 +958,23 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
| 936 | goto out; | 958 | goto out; |
| 937 | } | 959 | } |
| 938 | 960 | ||
| 961 | res = ERR_PTR(-ENOMEM); | ||
| 962 | fhandle = nfs_alloc_fhandle(); | ||
| 963 | fattr = nfs_alloc_fattr(); | ||
| 964 | if (fhandle == NULL || fattr == NULL) | ||
| 965 | goto out; | ||
| 966 | |||
| 939 | parent = dentry->d_parent; | 967 | parent = dentry->d_parent; |
| 940 | /* Protect against concurrent sillydeletes */ | 968 | /* Protect against concurrent sillydeletes */ |
| 941 | nfs_block_sillyrename(parent); | 969 | nfs_block_sillyrename(parent); |
| 942 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr); | 970 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); |
| 943 | if (error == -ENOENT) | 971 | if (error == -ENOENT) |
| 944 | goto no_entry; | 972 | goto no_entry; |
| 945 | if (error < 0) { | 973 | if (error < 0) { |
| 946 | res = ERR_PTR(error); | 974 | res = ERR_PTR(error); |
| 947 | goto out_unblock_sillyrename; | 975 | goto out_unblock_sillyrename; |
| 948 | } | 976 | } |
| 949 | inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); | 977 | inode = nfs_fhget(dentry->d_sb, fhandle, fattr); |
| 950 | res = (struct dentry *)inode; | 978 | res = (struct dentry *)inode; |
| 951 | if (IS_ERR(res)) | 979 | if (IS_ERR(res)) |
| 952 | goto out_unblock_sillyrename; | 980 | goto out_unblock_sillyrename; |
| @@ -962,6 +990,8 @@ no_entry: | |||
| 962 | out_unblock_sillyrename: | 990 | out_unblock_sillyrename: |
| 963 | nfs_unblock_sillyrename(parent); | 991 | nfs_unblock_sillyrename(parent); |
| 964 | out: | 992 | out: |
| 993 | nfs_free_fattr(fattr); | ||
| 994 | nfs_free_fhandle(fhandle); | ||
| 965 | return res; | 995 | return res; |
| 966 | } | 996 | } |
| 967 | 997 | ||
| @@ -1622,16 +1652,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 1622 | } | 1652 | } |
| 1623 | } | 1653 | } |
| 1624 | 1654 | ||
| 1625 | /* | ||
| 1626 | * ... prune child dentries and writebacks if needed. | ||
| 1627 | */ | ||
| 1628 | if (atomic_read(&old_dentry->d_count) > 1) { | ||
| 1629 | if (S_ISREG(old_inode->i_mode)) | ||
| 1630 | nfs_wb_all(old_inode); | ||
| 1631 | shrink_dcache_parent(old_dentry); | ||
| 1632 | } | ||
| 1633 | nfs_inode_return_delegation(old_inode); | 1655 | nfs_inode_return_delegation(old_inode); |
| 1634 | |||
| 1635 | if (new_inode != NULL) | 1656 | if (new_inode != NULL) |
| 1636 | nfs_inode_return_delegation(new_inode); | 1657 | nfs_inode_return_delegation(new_inode); |
| 1637 | 1658 | ||
| @@ -1669,28 +1690,33 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry) | |||
| 1669 | smp_mb__after_atomic_dec(); | 1690 | smp_mb__after_atomic_dec(); |
| 1670 | } | 1691 | } |
| 1671 | 1692 | ||
| 1672 | int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask) | 1693 | static void nfs_access_free_list(struct list_head *head) |
| 1694 | { | ||
| 1695 | struct nfs_access_entry *cache; | ||
| 1696 | |||
| 1697 | while (!list_empty(head)) { | ||
| 1698 | cache = list_entry(head->next, struct nfs_access_entry, lru); | ||
| 1699 | list_del(&cache->lru); | ||
| 1700 | nfs_access_free_entry(cache); | ||
| 1701 | } | ||
| 1702 | } | ||
| 1703 | |||
| 1704 | int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | ||
| 1673 | { | 1705 | { |
| 1674 | LIST_HEAD(head); | 1706 | LIST_HEAD(head); |
| 1675 | struct nfs_inode *nfsi; | 1707 | struct nfs_inode *nfsi; |
| 1676 | struct nfs_access_entry *cache; | 1708 | struct nfs_access_entry *cache; |
| 1677 | 1709 | ||
| 1678 | restart: | 1710 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
| 1711 | return (nr_to_scan == 0) ? 0 : -1; | ||
| 1712 | |||
| 1679 | spin_lock(&nfs_access_lru_lock); | 1713 | spin_lock(&nfs_access_lru_lock); |
| 1680 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { | 1714 | list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) { |
| 1681 | struct rw_semaphore *s_umount; | ||
| 1682 | struct inode *inode; | 1715 | struct inode *inode; |
| 1683 | 1716 | ||
| 1684 | if (nr_to_scan-- == 0) | 1717 | if (nr_to_scan-- == 0) |
| 1685 | break; | 1718 | break; |
| 1686 | s_umount = &nfsi->vfs_inode.i_sb->s_umount; | 1719 | 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); | 1720 | spin_lock(&inode->i_lock); |
| 1695 | if (list_empty(&nfsi->access_cache_entry_lru)) | 1721 | if (list_empty(&nfsi->access_cache_entry_lru)) |
| 1696 | goto remove_lru_entry; | 1722 | goto remove_lru_entry; |
| @@ -1704,61 +1730,48 @@ restart: | |||
| 1704 | else { | 1730 | else { |
| 1705 | remove_lru_entry: | 1731 | remove_lru_entry: |
| 1706 | list_del_init(&nfsi->access_cache_inode_lru); | 1732 | list_del_init(&nfsi->access_cache_inode_lru); |
| 1733 | smp_mb__before_clear_bit(); | ||
| 1707 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); | 1734 | clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags); |
| 1735 | smp_mb__after_clear_bit(); | ||
| 1708 | } | 1736 | } |
| 1709 | spin_unlock(&inode->i_lock); | 1737 | spin_unlock(&inode->i_lock); |
| 1710 | spin_unlock(&nfs_access_lru_lock); | ||
| 1711 | iput(inode); | ||
| 1712 | up_read(s_umount); | ||
| 1713 | goto restart; | ||
| 1714 | } | 1738 | } |
| 1715 | spin_unlock(&nfs_access_lru_lock); | 1739 | spin_unlock(&nfs_access_lru_lock); |
| 1716 | while (!list_empty(&head)) { | 1740 | 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; | 1741 | return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure; |
| 1722 | } | 1742 | } |
| 1723 | 1743 | ||
| 1724 | static void __nfs_access_zap_cache(struct inode *inode) | 1744 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
| 1725 | { | 1745 | { |
| 1726 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 1727 | struct rb_root *root_node = &nfsi->access_cache; | 1746 | struct rb_root *root_node = &nfsi->access_cache; |
| 1728 | struct rb_node *n, *dispose = NULL; | 1747 | struct rb_node *n; |
| 1729 | struct nfs_access_entry *entry; | 1748 | struct nfs_access_entry *entry; |
| 1730 | 1749 | ||
| 1731 | /* Unhook entries from the cache */ | 1750 | /* Unhook entries from the cache */ |
| 1732 | while ((n = rb_first(root_node)) != NULL) { | 1751 | while ((n = rb_first(root_node)) != NULL) { |
| 1733 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | 1752 | entry = rb_entry(n, struct nfs_access_entry, rb_node); |
| 1734 | rb_erase(n, root_node); | 1753 | rb_erase(n, root_node); |
| 1735 | list_del(&entry->lru); | 1754 | list_move(&entry->lru, head); |
| 1736 | n->rb_left = dispose; | ||
| 1737 | dispose = n; | ||
| 1738 | } | 1755 | } |
| 1739 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1756 | 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 | } | 1757 | } |
| 1749 | 1758 | ||
| 1750 | void nfs_access_zap_cache(struct inode *inode) | 1759 | void nfs_access_zap_cache(struct inode *inode) |
| 1751 | { | 1760 | { |
| 1761 | LIST_HEAD(head); | ||
| 1762 | |||
| 1763 | if (test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags) == 0) | ||
| 1764 | return; | ||
| 1752 | /* Remove from global LRU init */ | 1765 | /* Remove from global LRU init */ |
| 1753 | if (test_and_clear_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1766 | spin_lock(&nfs_access_lru_lock); |
| 1754 | spin_lock(&nfs_access_lru_lock); | 1767 | 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); | 1768 | list_del_init(&NFS_I(inode)->access_cache_inode_lru); |
| 1756 | spin_unlock(&nfs_access_lru_lock); | ||
| 1757 | } | ||
| 1758 | 1769 | ||
| 1759 | spin_lock(&inode->i_lock); | 1770 | spin_lock(&inode->i_lock); |
| 1760 | /* This will release the spinlock */ | 1771 | __nfs_access_zap_cache(NFS_I(inode), &head); |
| 1761 | __nfs_access_zap_cache(inode); | 1772 | spin_unlock(&inode->i_lock); |
| 1773 | spin_unlock(&nfs_access_lru_lock); | ||
| 1774 | nfs_access_free_list(&head); | ||
| 1762 | } | 1775 | } |
| 1763 | 1776 | ||
| 1764 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) | 1777 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) |
| @@ -1809,8 +1822,8 @@ out_stale: | |||
| 1809 | nfs_access_free_entry(cache); | 1822 | nfs_access_free_entry(cache); |
| 1810 | return -ENOENT; | 1823 | return -ENOENT; |
| 1811 | out_zap: | 1824 | out_zap: |
| 1812 | /* This will release the spinlock */ | 1825 | spin_unlock(&inode->i_lock); |
| 1813 | __nfs_access_zap_cache(inode); | 1826 | nfs_access_zap_cache(inode); |
| 1814 | return -ENOENT; | 1827 | return -ENOENT; |
| 1815 | } | 1828 | } |
| 1816 | 1829 | ||
| @@ -1865,9 +1878,11 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s | |||
| 1865 | smp_mb__after_atomic_inc(); | 1878 | smp_mb__after_atomic_inc(); |
| 1866 | 1879 | ||
| 1867 | /* Add inode to global LRU list */ | 1880 | /* Add inode to global LRU list */ |
| 1868 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { | 1881 | if (!test_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) { |
| 1869 | spin_lock(&nfs_access_lru_lock); | 1882 | spin_lock(&nfs_access_lru_lock); |
| 1870 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, &nfs_access_lru_list); | 1883 | if (!test_and_set_bit(NFS_INO_ACL_LRU_SET, &NFS_I(inode)->flags)) |
| 1884 | list_add_tail(&NFS_I(inode)->access_cache_inode_lru, | ||
| 1885 | &nfs_access_lru_list); | ||
| 1871 | spin_unlock(&nfs_access_lru_lock); | 1886 | spin_unlock(&nfs_access_lru_lock); |
| 1872 | } | 1887 | } |
| 1873 | } | 1888 | } |
| @@ -1929,7 +1944,7 @@ int nfs_permission(struct inode *inode, int mask) | |||
| 1929 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) | 1944 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
| 1930 | goto out; | 1945 | goto out; |
| 1931 | /* Is this sys_access() ? */ | 1946 | /* Is this sys_access() ? */ |
| 1932 | if (mask & MAY_ACCESS) | 1947 | if (mask & (MAY_ACCESS | MAY_CHDIR)) |
| 1933 | goto force_lookup; | 1948 | goto force_lookup; |
| 1934 | 1949 | ||
| 1935 | switch (inode->i_mode & S_IFMT) { | 1950 | switch (inode->i_mode & S_IFMT) { |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index ad4cd31d6050..064a80961677 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -69,6 +69,7 @@ struct nfs_direct_req { | |||
| 69 | 69 | ||
| 70 | /* I/O parameters */ | 70 | /* I/O parameters */ |
| 71 | struct nfs_open_context *ctx; /* file open context info */ | 71 | struct nfs_open_context *ctx; /* file open context info */ |
| 72 | struct nfs_lock_context *l_ctx; /* Lock context info */ | ||
| 72 | struct kiocb * iocb; /* controlling i/o request */ | 73 | struct kiocb * iocb; /* controlling i/o request */ |
| 73 | struct inode * inode; /* target file of i/o */ | 74 | struct inode * inode; /* target file of i/o */ |
| 74 | 75 | ||
| @@ -160,6 +161,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | |||
| 160 | INIT_LIST_HEAD(&dreq->rewrite_list); | 161 | INIT_LIST_HEAD(&dreq->rewrite_list); |
| 161 | dreq->iocb = NULL; | 162 | dreq->iocb = NULL; |
| 162 | dreq->ctx = NULL; | 163 | dreq->ctx = NULL; |
| 164 | dreq->l_ctx = NULL; | ||
| 163 | spin_lock_init(&dreq->lock); | 165 | spin_lock_init(&dreq->lock); |
| 164 | atomic_set(&dreq->io_count, 0); | 166 | atomic_set(&dreq->io_count, 0); |
| 165 | dreq->count = 0; | 167 | dreq->count = 0; |
| @@ -173,6 +175,8 @@ static void nfs_direct_req_free(struct kref *kref) | |||
| 173 | { | 175 | { |
| 174 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); | 176 | struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref); |
| 175 | 177 | ||
| 178 | if (dreq->l_ctx != NULL) | ||
| 179 | nfs_put_lock_context(dreq->l_ctx); | ||
| 176 | if (dreq->ctx != NULL) | 180 | if (dreq->ctx != NULL) |
| 177 | put_nfs_open_context(dreq->ctx); | 181 | put_nfs_open_context(dreq->ctx); |
| 178 | kmem_cache_free(nfs_direct_cachep, dreq); | 182 | kmem_cache_free(nfs_direct_cachep, dreq); |
| @@ -336,6 +340,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
| 336 | data->cred = msg.rpc_cred; | 340 | data->cred = msg.rpc_cred; |
| 337 | data->args.fh = NFS_FH(inode); | 341 | data->args.fh = NFS_FH(inode); |
| 338 | data->args.context = ctx; | 342 | data->args.context = ctx; |
| 343 | data->args.lock_context = dreq->l_ctx; | ||
| 339 | data->args.offset = pos; | 344 | data->args.offset = pos; |
| 340 | data->args.pgbase = pgbase; | 345 | data->args.pgbase = pgbase; |
| 341 | data->args.pages = data->pagevec; | 346 | data->args.pages = data->pagevec; |
| @@ -416,24 +421,28 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
| 416 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | 421 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
| 417 | unsigned long nr_segs, loff_t pos) | 422 | unsigned long nr_segs, loff_t pos) |
| 418 | { | 423 | { |
| 419 | ssize_t result = 0; | 424 | ssize_t result = -ENOMEM; |
| 420 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 425 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
| 421 | struct nfs_direct_req *dreq; | 426 | struct nfs_direct_req *dreq; |
| 422 | 427 | ||
| 423 | dreq = nfs_direct_req_alloc(); | 428 | dreq = nfs_direct_req_alloc(); |
| 424 | if (!dreq) | 429 | if (dreq == NULL) |
| 425 | return -ENOMEM; | 430 | goto out; |
| 426 | 431 | ||
| 427 | dreq->inode = inode; | 432 | dreq->inode = inode; |
| 428 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 433 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
| 434 | dreq->l_ctx = nfs_get_lock_context(dreq->ctx); | ||
| 435 | if (dreq->l_ctx == NULL) | ||
| 436 | goto out_release; | ||
| 429 | if (!is_sync_kiocb(iocb)) | 437 | if (!is_sync_kiocb(iocb)) |
| 430 | dreq->iocb = iocb; | 438 | dreq->iocb = iocb; |
| 431 | 439 | ||
| 432 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); | 440 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); |
| 433 | if (!result) | 441 | if (!result) |
| 434 | result = nfs_direct_wait(dreq); | 442 | result = nfs_direct_wait(dreq); |
| 443 | out_release: | ||
| 435 | nfs_direct_req_release(dreq); | 444 | nfs_direct_req_release(dreq); |
| 436 | 445 | out: | |
| 437 | return result; | 446 | return result; |
| 438 | } | 447 | } |
| 439 | 448 | ||
| @@ -574,6 +583,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
| 574 | data->args.offset = 0; | 583 | data->args.offset = 0; |
| 575 | data->args.count = 0; | 584 | data->args.count = 0; |
| 576 | data->args.context = dreq->ctx; | 585 | data->args.context = dreq->ctx; |
| 586 | data->args.lock_context = dreq->l_ctx; | ||
| 577 | data->res.count = 0; | 587 | data->res.count = 0; |
| 578 | data->res.fattr = &data->fattr; | 588 | data->res.fattr = &data->fattr; |
| 579 | data->res.verf = &data->verf; | 589 | data->res.verf = &data->verf; |
| @@ -761,6 +771,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
| 761 | data->cred = msg.rpc_cred; | 771 | data->cred = msg.rpc_cred; |
| 762 | data->args.fh = NFS_FH(inode); | 772 | data->args.fh = NFS_FH(inode); |
| 763 | data->args.context = ctx; | 773 | data->args.context = ctx; |
| 774 | data->args.lock_context = dreq->l_ctx; | ||
| 764 | data->args.offset = pos; | 775 | data->args.offset = pos; |
| 765 | data->args.pgbase = pgbase; | 776 | data->args.pgbase = pgbase; |
| 766 | data->args.pages = data->pagevec; | 777 | data->args.pages = data->pagevec; |
| @@ -845,7 +856,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 845 | unsigned long nr_segs, loff_t pos, | 856 | unsigned long nr_segs, loff_t pos, |
| 846 | size_t count) | 857 | size_t count) |
| 847 | { | 858 | { |
| 848 | ssize_t result = 0; | 859 | ssize_t result = -ENOMEM; |
| 849 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 860 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
| 850 | struct nfs_direct_req *dreq; | 861 | struct nfs_direct_req *dreq; |
| 851 | size_t wsize = NFS_SERVER(inode)->wsize; | 862 | size_t wsize = NFS_SERVER(inode)->wsize; |
| @@ -853,7 +864,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 853 | 864 | ||
| 854 | dreq = nfs_direct_req_alloc(); | 865 | dreq = nfs_direct_req_alloc(); |
| 855 | if (!dreq) | 866 | if (!dreq) |
| 856 | return -ENOMEM; | 867 | goto out; |
| 857 | nfs_alloc_commit_data(dreq); | 868 | nfs_alloc_commit_data(dreq); |
| 858 | 869 | ||
| 859 | if (dreq->commit_data == NULL || count < wsize) | 870 | if (dreq->commit_data == NULL || count < wsize) |
| @@ -861,14 +872,18 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 861 | 872 | ||
| 862 | dreq->inode = inode; | 873 | dreq->inode = inode; |
| 863 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); | 874 | dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp)); |
| 875 | dreq->l_ctx = nfs_get_lock_context(dreq->ctx); | ||
| 876 | if (dreq->l_ctx != NULL) | ||
| 877 | goto out_release; | ||
| 864 | if (!is_sync_kiocb(iocb)) | 878 | if (!is_sync_kiocb(iocb)) |
| 865 | dreq->iocb = iocb; | 879 | dreq->iocb = iocb; |
| 866 | 880 | ||
| 867 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); | 881 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync); |
| 868 | if (!result) | 882 | if (!result) |
| 869 | result = nfs_direct_wait(dreq); | 883 | result = nfs_direct_wait(dreq); |
| 884 | out_release: | ||
| 870 | nfs_direct_req_release(dreq); | 885 | nfs_direct_req_release(dreq); |
| 871 | 886 | out: | |
| 872 | return result; | 887 | return result; |
| 873 | } | 888 | } |
| 874 | 889 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 8d965bddb87e..2d141a74ae82 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
| 28 | #include <linux/aio.h> | 28 | #include <linux/aio.h> |
| 29 | #include <linux/gfp.h> | 29 | #include <linux/gfp.h> |
| 30 | #include <linux/swap.h> | ||
| 30 | 31 | ||
| 31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
| 32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
| @@ -53,7 +54,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
| 53 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 54 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
| 54 | unsigned long nr_segs, loff_t pos); | 55 | unsigned long nr_segs, loff_t pos); |
| 55 | static int nfs_file_flush(struct file *, fl_owner_t id); | 56 | static int nfs_file_flush(struct file *, fl_owner_t id); |
| 56 | static int nfs_file_fsync(struct file *, struct dentry *dentry, int datasync); | 57 | static int nfs_file_fsync(struct file *, int datasync); |
| 57 | static int nfs_check_flags(int flags); | 58 | static int nfs_check_flags(int flags); |
| 58 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); | 59 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl); |
| 59 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); | 60 | static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl); |
| @@ -161,14 +162,17 @@ static int nfs_revalidate_file_size(struct inode *inode, struct file *filp) | |||
| 161 | struct nfs_server *server = NFS_SERVER(inode); | 162 | struct nfs_server *server = NFS_SERVER(inode); |
| 162 | struct nfs_inode *nfsi = NFS_I(inode); | 163 | struct nfs_inode *nfsi = NFS_I(inode); |
| 163 | 164 | ||
| 164 | if (server->flags & NFS_MOUNT_NOAC) | 165 | if (nfs_have_delegated_attributes(inode)) |
| 165 | goto force_reval; | 166 | goto out_noreval; |
| 167 | |||
| 166 | if (filp->f_flags & O_DIRECT) | 168 | if (filp->f_flags & O_DIRECT) |
| 167 | goto force_reval; | 169 | goto force_reval; |
| 168 | if (nfsi->npages != 0) | 170 | if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
| 169 | return 0; | 171 | goto force_reval; |
| 170 | if (!(nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) && !nfs_attribute_timeout(inode)) | 172 | if (nfs_attribute_timeout(inode)) |
| 171 | return 0; | 173 | goto force_reval; |
| 174 | out_noreval: | ||
| 175 | return 0; | ||
| 172 | force_reval: | 176 | force_reval: |
| 173 | return __nfs_revalidate_inode(server, inode); | 177 | return __nfs_revalidate_inode(server, inode); |
| 174 | } | 178 | } |
| @@ -199,37 +203,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
| 199 | } | 203 | } |
| 200 | 204 | ||
| 201 | /* | 205 | /* |
| 202 | * Helper for nfs_file_flush() and nfs_file_fsync() | ||
| 203 | * | ||
| 204 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
| 205 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
| 206 | * the two being set at the same time in nfs_context_set_write_error(). | ||
| 207 | * This is because the former is used to notify the _next_ call to | ||
| 208 | * nfs_file_write() that a write error occured, and hence cause it to | ||
| 209 | * fall back to doing a synchronous write. | ||
| 210 | */ | ||
| 211 | static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) | ||
| 212 | { | ||
| 213 | int have_error, status; | ||
| 214 | int ret = 0; | ||
| 215 | |||
| 216 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 217 | status = nfs_wb_all(inode); | ||
| 218 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 219 | if (have_error) | ||
| 220 | ret = xchg(&ctx->error, 0); | ||
| 221 | if (!ret) | ||
| 222 | ret = status; | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Flush all dirty pages, and check for write errors. | 206 | * Flush all dirty pages, and check for write errors. |
| 228 | */ | 207 | */ |
| 229 | static int | 208 | static int |
| 230 | nfs_file_flush(struct file *file, fl_owner_t id) | 209 | nfs_file_flush(struct file *file, fl_owner_t id) |
| 231 | { | 210 | { |
| 232 | struct nfs_open_context *ctx = nfs_file_open_context(file); | ||
| 233 | struct dentry *dentry = file->f_path.dentry; | 211 | struct dentry *dentry = file->f_path.dentry; |
| 234 | struct inode *inode = dentry->d_inode; | 212 | struct inode *inode = dentry->d_inode; |
| 235 | 213 | ||
| @@ -242,7 +220,7 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
| 242 | return 0; | 220 | return 0; |
| 243 | 221 | ||
| 244 | /* Flush writes to the server and return any errors */ | 222 | /* Flush writes to the server and return any errors */ |
| 245 | return nfs_do_fsync(ctx, inode); | 223 | return vfs_fsync(file, 0); |
| 246 | } | 224 | } |
| 247 | 225 | ||
| 248 | static ssize_t | 226 | static ssize_t |
| @@ -317,19 +295,37 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
| 317 | * Flush any dirty pages for this process, and check for write errors. | 295 | * Flush any dirty pages for this process, and check for write errors. |
| 318 | * The return status from this call provides a reliable indication of | 296 | * The return status from this call provides a reliable indication of |
| 319 | * whether any write errors occurred for this process. | 297 | * whether any write errors occurred for this process. |
| 298 | * | ||
| 299 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
| 300 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
| 301 | * the two being set at the same time in nfs_context_set_write_error(). | ||
| 302 | * This is because the former is used to notify the _next_ call to | ||
| 303 | * nfs_file_write() that a write error occured, and hence cause it to | ||
| 304 | * fall back to doing a synchronous write. | ||
| 320 | */ | 305 | */ |
| 321 | static int | 306 | static int |
| 322 | nfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) | 307 | nfs_file_fsync(struct file *file, int datasync) |
| 323 | { | 308 | { |
| 309 | struct dentry *dentry = file->f_path.dentry; | ||
| 324 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 310 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
| 325 | struct inode *inode = dentry->d_inode; | 311 | struct inode *inode = dentry->d_inode; |
| 312 | int have_error, status; | ||
| 313 | int ret = 0; | ||
| 314 | |||
| 326 | 315 | ||
| 327 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", | 316 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", |
| 328 | dentry->d_parent->d_name.name, dentry->d_name.name, | 317 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 329 | datasync); | 318 | datasync); |
| 330 | 319 | ||
| 331 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 320 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
| 332 | return nfs_do_fsync(ctx, inode); | 321 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
| 322 | status = nfs_commit_inode(inode, FLUSH_SYNC); | ||
| 323 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 324 | if (have_error) | ||
| 325 | ret = xchg(&ctx->error, 0); | ||
| 326 | if (!ret) | ||
| 327 | ret = status; | ||
| 328 | return ret; | ||
| 333 | } | 329 | } |
| 334 | 330 | ||
| 335 | /* | 331 | /* |
| @@ -489,11 +485,19 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset) | |||
| 489 | */ | 485 | */ |
| 490 | static int nfs_release_page(struct page *page, gfp_t gfp) | 486 | static int nfs_release_page(struct page *page, gfp_t gfp) |
| 491 | { | 487 | { |
| 488 | struct address_space *mapping = page->mapping; | ||
| 489 | |||
| 492 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); | 490 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); |
| 493 | 491 | ||
| 494 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ | 492 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ |
| 495 | if ((gfp & GFP_KERNEL) == GFP_KERNEL) | 493 | if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) { |
| 496 | nfs_wb_page(page->mapping->host, page); | 494 | int how = FLUSH_SYNC; |
| 495 | |||
| 496 | /* Don't let kswapd deadlock waiting for OOM RPC calls */ | ||
| 497 | if (current_is_kswapd()) | ||
| 498 | how = 0; | ||
| 499 | nfs_commit_inode(mapping->host, how); | ||
| 500 | } | ||
| 497 | /* If PagePrivate() is set, then the page is not freeable */ | 501 | /* If PagePrivate() is set, then the page is not freeable */ |
| 498 | if (PagePrivate(page)) | 502 | if (PagePrivate(page)) |
| 499 | return 0; | 503 | return 0; |
| @@ -635,7 +639,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 635 | 639 | ||
| 636 | /* Return error values for O_DSYNC and IS_SYNC() */ | 640 | /* Return error values for O_DSYNC and IS_SYNC() */ |
| 637 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 641 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
| 638 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 642 | int err = vfs_fsync(iocb->ki_filp, 0); |
| 639 | if (err < 0) | 643 | if (err < 0) |
| 640 | result = err; | 644 | result = err; |
| 641 | } | 645 | } |
| @@ -671,7 +675,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
| 671 | written = ret; | 675 | written = ret; |
| 672 | 676 | ||
| 673 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 677 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
| 674 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 678 | int err = vfs_fsync(filp, 0); |
| 675 | if (err < 0) | 679 | if (err < 0) |
| 676 | ret = err; | 680 | ret = err; |
| 677 | } | 681 | } |
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..a70e446e1605 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_TYPE) |
| 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..7d2d6c72aa78 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -98,7 +98,7 @@ u64 nfs_compat_user_ino64(u64 fileid) | |||
| 98 | return ino; | 98 | return ino; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void nfs_clear_inode(struct inode *inode) | 101 | static void nfs_clear_inode(struct inode *inode) |
| 102 | { | 102 | { |
| 103 | /* | 103 | /* |
| 104 | * The following should never happen... | 104 | * The following should never happen... |
| @@ -110,6 +110,13 @@ void nfs_clear_inode(struct inode *inode) | |||
| 110 | nfs_fscache_release_inode_cookie(inode); | 110 | nfs_fscache_release_inode_cookie(inode); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | void nfs_evict_inode(struct inode *inode) | ||
| 114 | { | ||
| 115 | truncate_inode_pages(&inode->i_data, 0); | ||
| 116 | end_writeback(inode); | ||
| 117 | nfs_clear_inode(inode); | ||
| 118 | } | ||
| 119 | |||
| 113 | /** | 120 | /** |
| 114 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk | 121 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk |
| 115 | */ | 122 | */ |
| @@ -393,8 +400,8 @@ int | |||
| 393 | nfs_setattr(struct dentry *dentry, struct iattr *attr) | 400 | nfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 394 | { | 401 | { |
| 395 | struct inode *inode = dentry->d_inode; | 402 | struct inode *inode = dentry->d_inode; |
| 396 | struct nfs_fattr fattr; | 403 | struct nfs_fattr *fattr; |
| 397 | int error; | 404 | int error = -ENOMEM; |
| 398 | 405 | ||
| 399 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); | 406 | nfs_inc_stats(inode, NFSIOS_VFSSETATTR); |
| 400 | 407 | ||
| @@ -413,18 +420,22 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 413 | return 0; | 420 | return 0; |
| 414 | 421 | ||
| 415 | /* Write all dirty data */ | 422 | /* Write all dirty data */ |
| 416 | if (S_ISREG(inode->i_mode)) { | 423 | if (S_ISREG(inode->i_mode)) |
| 417 | filemap_write_and_wait(inode->i_mapping); | ||
| 418 | nfs_wb_all(inode); | 424 | nfs_wb_all(inode); |
| 419 | } | 425 | |
| 426 | fattr = nfs_alloc_fattr(); | ||
| 427 | if (fattr == NULL) | ||
| 428 | goto out; | ||
| 420 | /* | 429 | /* |
| 421 | * Return any delegations if we're going to change ACLs | 430 | * Return any delegations if we're going to change ACLs |
| 422 | */ | 431 | */ |
| 423 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) | 432 | if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) |
| 424 | nfs_inode_return_delegation(inode); | 433 | nfs_inode_return_delegation(inode); |
| 425 | error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); | 434 | error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); |
| 426 | if (error == 0) | 435 | if (error == 0) |
| 427 | nfs_refresh_inode(inode, &fattr); | 436 | nfs_refresh_inode(inode, fattr); |
| 437 | nfs_free_fattr(fattr); | ||
| 438 | out: | ||
| 428 | return error; | 439 | return error; |
| 429 | } | 440 | } |
| 430 | 441 | ||
| @@ -524,6 +535,68 @@ out: | |||
| 524 | return err; | 535 | return err; |
| 525 | } | 536 | } |
| 526 | 537 | ||
| 538 | static void nfs_init_lock_context(struct nfs_lock_context *l_ctx) | ||
| 539 | { | ||
| 540 | atomic_set(&l_ctx->count, 1); | ||
| 541 | l_ctx->lockowner = current->files; | ||
| 542 | l_ctx->pid = current->tgid; | ||
| 543 | INIT_LIST_HEAD(&l_ctx->list); | ||
| 544 | } | ||
| 545 | |||
| 546 | static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) | ||
| 547 | { | ||
| 548 | struct nfs_lock_context *pos; | ||
| 549 | |||
| 550 | list_for_each_entry(pos, &ctx->lock_context.list, list) { | ||
| 551 | if (pos->lockowner != current->files) | ||
| 552 | continue; | ||
| 553 | if (pos->pid != current->tgid) | ||
| 554 | continue; | ||
| 555 | atomic_inc(&pos->count); | ||
| 556 | return pos; | ||
| 557 | } | ||
| 558 | return NULL; | ||
| 559 | } | ||
| 560 | |||
| 561 | struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) | ||
| 562 | { | ||
| 563 | struct nfs_lock_context *res, *new = NULL; | ||
| 564 | struct inode *inode = ctx->path.dentry->d_inode; | ||
| 565 | |||
| 566 | spin_lock(&inode->i_lock); | ||
| 567 | res = __nfs_find_lock_context(ctx); | ||
| 568 | if (res == NULL) { | ||
| 569 | spin_unlock(&inode->i_lock); | ||
| 570 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
| 571 | if (new == NULL) | ||
| 572 | return NULL; | ||
| 573 | nfs_init_lock_context(new); | ||
| 574 | spin_lock(&inode->i_lock); | ||
| 575 | res = __nfs_find_lock_context(ctx); | ||
| 576 | if (res == NULL) { | ||
| 577 | list_add_tail(&new->list, &ctx->lock_context.list); | ||
| 578 | new->open_context = ctx; | ||
| 579 | res = new; | ||
| 580 | new = NULL; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | spin_unlock(&inode->i_lock); | ||
| 584 | kfree(new); | ||
| 585 | return res; | ||
| 586 | } | ||
| 587 | |||
| 588 | void nfs_put_lock_context(struct nfs_lock_context *l_ctx) | ||
| 589 | { | ||
| 590 | struct nfs_open_context *ctx = l_ctx->open_context; | ||
| 591 | struct inode *inode = ctx->path.dentry->d_inode; | ||
| 592 | |||
| 593 | if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock)) | ||
| 594 | return; | ||
| 595 | list_del(&l_ctx->list); | ||
| 596 | spin_unlock(&inode->i_lock); | ||
| 597 | kfree(l_ctx); | ||
| 598 | } | ||
| 599 | |||
| 527 | /** | 600 | /** |
| 528 | * nfs_close_context - Common close_context() routine NFSv2/v3 | 601 | * nfs_close_context - Common close_context() routine NFSv2/v3 |
| 529 | * @ctx: pointer to context | 602 | * @ctx: pointer to context |
| @@ -560,11 +633,11 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
| 560 | path_get(&ctx->path); | 633 | path_get(&ctx->path); |
| 561 | ctx->cred = get_rpccred(cred); | 634 | ctx->cred = get_rpccred(cred); |
| 562 | ctx->state = NULL; | 635 | ctx->state = NULL; |
| 563 | ctx->lockowner = current->files; | ||
| 564 | ctx->flags = 0; | 636 | ctx->flags = 0; |
| 565 | ctx->error = 0; | 637 | ctx->error = 0; |
| 566 | ctx->dir_cookie = 0; | 638 | ctx->dir_cookie = 0; |
| 567 | atomic_set(&ctx->count, 1); | 639 | nfs_init_lock_context(&ctx->lock_context); |
| 640 | ctx->lock_context.open_context = ctx; | ||
| 568 | } | 641 | } |
| 569 | return ctx; | 642 | return ctx; |
| 570 | } | 643 | } |
| @@ -572,7 +645,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct | |||
| 572 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | 645 | struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) |
| 573 | { | 646 | { |
| 574 | if (ctx != NULL) | 647 | if (ctx != NULL) |
| 575 | atomic_inc(&ctx->count); | 648 | atomic_inc(&ctx->lock_context.count); |
| 576 | return ctx; | 649 | return ctx; |
| 577 | } | 650 | } |
| 578 | 651 | ||
| @@ -580,7 +653,7 @@ static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) | |||
| 580 | { | 653 | { |
| 581 | struct inode *inode = ctx->path.dentry->d_inode; | 654 | struct inode *inode = ctx->path.dentry->d_inode; |
| 582 | 655 | ||
| 583 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 656 | if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock)) |
| 584 | return; | 657 | return; |
| 585 | list_del(&ctx->list); | 658 | list_del(&ctx->list); |
| 586 | spin_unlock(&inode->i_lock); | 659 | spin_unlock(&inode->i_lock); |
| @@ -682,7 +755,7 @@ int | |||
| 682 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 755 | __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
| 683 | { | 756 | { |
| 684 | int status = -ESTALE; | 757 | int status = -ESTALE; |
| 685 | struct nfs_fattr fattr; | 758 | struct nfs_fattr *fattr = NULL; |
| 686 | struct nfs_inode *nfsi = NFS_I(inode); | 759 | struct nfs_inode *nfsi = NFS_I(inode); |
| 687 | 760 | ||
| 688 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", | 761 | dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", |
| @@ -693,8 +766,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 693 | if (NFS_STALE(inode)) | 766 | if (NFS_STALE(inode)) |
| 694 | goto out; | 767 | goto out; |
| 695 | 768 | ||
| 769 | status = -ENOMEM; | ||
| 770 | fattr = nfs_alloc_fattr(); | ||
| 771 | if (fattr == NULL) | ||
| 772 | goto out; | ||
| 773 | |||
| 696 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); | 774 | nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); |
| 697 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr); | 775 | status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); |
| 698 | if (status != 0) { | 776 | if (status != 0) { |
| 699 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", | 777 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", |
| 700 | inode->i_sb->s_id, | 778 | inode->i_sb->s_id, |
| @@ -707,7 +785,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 707 | goto out; | 785 | goto out; |
| 708 | } | 786 | } |
| 709 | 787 | ||
| 710 | status = nfs_refresh_inode(inode, &fattr); | 788 | status = nfs_refresh_inode(inode, fattr); |
| 711 | if (status) { | 789 | if (status) { |
| 712 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", | 790 | dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", |
| 713 | inode->i_sb->s_id, | 791 | inode->i_sb->s_id, |
| @@ -723,6 +801,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 723 | (long long)NFS_FILEID(inode)); | 801 | (long long)NFS_FILEID(inode)); |
| 724 | 802 | ||
| 725 | out: | 803 | out: |
| 804 | nfs_free_fattr(fattr); | ||
| 726 | return status; | 805 | return status; |
| 727 | } | 806 | } |
| 728 | 807 | ||
| @@ -730,9 +809,14 @@ int nfs_attribute_timeout(struct inode *inode) | |||
| 730 | { | 809 | { |
| 731 | struct nfs_inode *nfsi = NFS_I(inode); | 810 | struct nfs_inode *nfsi = NFS_I(inode); |
| 732 | 811 | ||
| 812 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | ||
| 813 | } | ||
| 814 | |||
| 815 | static int nfs_attribute_cache_expired(struct inode *inode) | ||
| 816 | { | ||
| 733 | if (nfs_have_delegated_attributes(inode)) | 817 | if (nfs_have_delegated_attributes(inode)) |
| 734 | return 0; | 818 | return 0; |
| 735 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 819 | return nfs_attribute_timeout(inode); |
| 736 | } | 820 | } |
| 737 | 821 | ||
| 738 | /** | 822 | /** |
| @@ -745,7 +829,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
| 745 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | 829 | int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) |
| 746 | { | 830 | { |
| 747 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) | 831 | if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) |
| 748 | && !nfs_attribute_timeout(inode)) | 832 | && !nfs_attribute_cache_expired(inode)) |
| 749 | return NFS_STALE(inode) ? -ESTALE : 0; | 833 | return NFS_STALE(inode) ? -ESTALE : 0; |
| 750 | return __nfs_revalidate_inode(server, inode); | 834 | return __nfs_revalidate_inode(server, inode); |
| 751 | } | 835 | } |
| @@ -782,7 +866,8 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | |||
| 782 | int ret = 0; | 866 | int ret = 0; |
| 783 | 867 | ||
| 784 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | 868 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) |
| 785 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { | 869 | || nfs_attribute_cache_expired(inode) |
| 870 | || NFS_STALE(inode)) { | ||
| 786 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | 871 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); |
| 787 | if (ret < 0) | 872 | if (ret < 0) |
| 788 | goto out; | 873 | goto out; |
| @@ -916,6 +1001,26 @@ void nfs_fattr_init(struct nfs_fattr *fattr) | |||
| 916 | fattr->gencount = nfs_inc_attr_generation_counter(); | 1001 | fattr->gencount = nfs_inc_attr_generation_counter(); |
| 917 | } | 1002 | } |
| 918 | 1003 | ||
| 1004 | struct nfs_fattr *nfs_alloc_fattr(void) | ||
| 1005 | { | ||
| 1006 | struct nfs_fattr *fattr; | ||
| 1007 | |||
| 1008 | fattr = kmalloc(sizeof(*fattr), GFP_NOFS); | ||
| 1009 | if (fattr != NULL) | ||
| 1010 | nfs_fattr_init(fattr); | ||
| 1011 | return fattr; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | struct nfs_fh *nfs_alloc_fhandle(void) | ||
| 1015 | { | ||
| 1016 | struct nfs_fh *fh; | ||
| 1017 | |||
| 1018 | fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS); | ||
| 1019 | if (fh != NULL) | ||
| 1020 | fh->size = 0; | ||
| 1021 | return fh; | ||
| 1022 | } | ||
| 1023 | |||
| 919 | /** | 1024 | /** |
| 920 | * nfs_inode_attrs_need_update - check if the inode attributes need updating | 1025 | * nfs_inode_attrs_need_update - check if the inode attributes need updating |
| 921 | * @inode - pointer to inode | 1026 | * @inode - pointer to inode |
| @@ -1300,8 +1405,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1300 | * to open() calls that passed nfs_atomic_lookup, but failed to call | 1405 | * to open() calls that passed nfs_atomic_lookup, but failed to call |
| 1301 | * nfs_open(). | 1406 | * nfs_open(). |
| 1302 | */ | 1407 | */ |
| 1303 | void nfs4_clear_inode(struct inode *inode) | 1408 | void nfs4_evict_inode(struct inode *inode) |
| 1304 | { | 1409 | { |
| 1410 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1411 | end_writeback(inode); | ||
| 1305 | /* If we are holding a delegation, return it! */ | 1412 | /* If we are holding a delegation, return it! */ |
| 1306 | nfs_inode_return_delegation_noreclaim(inode); | 1413 | nfs_inode_return_delegation_noreclaim(inode); |
| 1307 | /* First call standard NFS clear_inode() code */ | 1414 | /* First call standard NFS clear_inode() code */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 11f82f03c5de..c961bc92c107 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -205,16 +205,17 @@ extern struct rpc_procinfo nfs4_procedures[]; | |||
| 205 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); | 205 | void nfs_close_context(struct nfs_open_context *ctx, int is_sync); |
| 206 | 206 | ||
| 207 | /* dir.c */ | 207 | /* dir.c */ |
| 208 | extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | 208 | extern int nfs_access_cache_shrinker(struct shrinker *shrink, |
| 209 | int nr_to_scan, gfp_t gfp_mask); | ||
| 209 | 210 | ||
| 210 | /* inode.c */ | 211 | /* inode.c */ |
| 211 | extern struct workqueue_struct *nfsiod_workqueue; | 212 | extern struct workqueue_struct *nfsiod_workqueue; |
| 212 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 213 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
| 213 | extern void nfs_destroy_inode(struct inode *); | 214 | extern void nfs_destroy_inode(struct inode *); |
| 214 | extern int nfs_write_inode(struct inode *, struct writeback_control *); | 215 | extern int nfs_write_inode(struct inode *, struct writeback_control *); |
| 215 | extern void nfs_clear_inode(struct inode *); | 216 | extern void nfs_evict_inode(struct inode *); |
| 216 | #ifdef CONFIG_NFS_V4 | 217 | #ifdef CONFIG_NFS_V4 |
| 217 | extern void nfs4_clear_inode(struct inode *); | 218 | extern void nfs4_evict_inode(struct inode *); |
| 218 | #endif | 219 | #endif |
| 219 | void nfs_zap_acl_cache(struct inode *inode); | 220 | void nfs_zap_acl_cache(struct inode *inode); |
| 220 | extern int nfs_wait_bit_killable(void *word); | 221 | extern int nfs_wait_bit_killable(void *word); |
| @@ -244,9 +245,7 @@ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); | |||
| 244 | #ifdef CONFIG_NFS_V4 | 245 | #ifdef CONFIG_NFS_V4 |
| 245 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); | 246 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); |
| 246 | 247 | ||
| 247 | extern int nfs4_path_walk(struct nfs_server *server, | 248 | extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); |
| 248 | struct nfs_fh *mntfh, | ||
| 249 | const char *path); | ||
| 250 | #endif | 249 | #endif |
| 251 | 250 | ||
| 252 | /* read.c */ | 251 | /* read.c */ |
| @@ -371,10 +370,9 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) | |||
| 371 | * Helper for restarting RPC calls in the possible presence of NFSv4.1 | 370 | * Helper for restarting RPC calls in the possible presence of NFSv4.1 |
| 372 | * sessions. | 371 | * sessions. |
| 373 | */ | 372 | */ |
| 374 | static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp) | 373 | static inline int nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp) |
| 375 | { | 374 | { |
| 376 | if (nfs4_has_session(clp)) | 375 | if (nfs4_has_session(clp)) |
| 377 | rpc_restart_call_prepare(task); | 376 | return rpc_restart_call_prepare(task); |
| 378 | else | 377 | return rpc_restart_call(task); |
| 379 | rpc_restart_call(task); | ||
| 380 | } | 378 | } |
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/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 81cf14257916..db8846a0e82e 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
| @@ -233,7 +233,7 @@ nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs | |||
| 233 | static int | 233 | static int |
| 234 | nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 234 | nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
| 235 | { | 235 | { |
| 236 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 236 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 237 | unsigned int replen; | 237 | unsigned int replen; |
| 238 | u32 offset = (u32)args->offset; | 238 | u32 offset = (u32)args->offset; |
| 239 | u32 count = args->count; | 239 | u32 count = args->count; |
| @@ -393,8 +393,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *arg | |||
| 393 | static int | 393 | static int |
| 394 | nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) | 394 | nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args) |
| 395 | { | 395 | { |
| 396 | struct rpc_task *task = req->rq_task; | 396 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 397 | struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth; | ||
| 398 | unsigned int replen; | 397 | unsigned int replen; |
| 399 | u32 count = args->count; | 398 | u32 count = args->count; |
| 400 | 399 | ||
| @@ -575,7 +574,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res) | |||
| 575 | static int | 574 | static int |
| 576 | nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) | 575 | nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args) |
| 577 | { | 576 | { |
| 578 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 577 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 579 | unsigned int replen; | 578 | unsigned int replen; |
| 580 | 579 | ||
| 581 | p = xdr_encode_fhandle(p, args->fh); | 580 | p = xdr_encode_fhandle(p, args->fh); |
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..9769704f8ce6 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
| @@ -330,7 +330,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg | |||
| 330 | static int | 330 | static int |
| 331 | nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 331 | nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
| 332 | { | 332 | { |
| 333 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 333 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 334 | unsigned int replen; | 334 | unsigned int replen; |
| 335 | u32 count = args->count; | 335 | u32 count = args->count; |
| 336 | 336 | ||
| @@ -471,7 +471,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args) | |||
| 471 | static int | 471 | static int |
| 472 | nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) | 472 | nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args) |
| 473 | { | 473 | { |
| 474 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 474 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 475 | unsigned int replen; | 475 | unsigned int replen; |
| 476 | u32 count = args->count; | 476 | u32 count = args->count; |
| 477 | 477 | ||
| @@ -675,7 +675,7 @@ static int | |||
| 675 | nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, | 675 | nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p, |
| 676 | struct nfs3_getaclargs *args) | 676 | struct nfs3_getaclargs *args) |
| 677 | { | 677 | { |
| 678 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 678 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 679 | unsigned int replen; | 679 | unsigned int replen; |
| 680 | 680 | ||
| 681 | p = xdr_encode_fhandle(p, args->fh); | 681 | p = xdr_encode_fhandle(p, args->fh); |
| @@ -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 | /* |
| @@ -802,7 +802,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res) | |||
| 802 | static int | 802 | static int |
| 803 | nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) | 803 | nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args) |
| 804 | { | 804 | { |
| 805 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 805 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 806 | unsigned int replen; | 806 | unsigned int replen; |
| 807 | 807 | ||
| 808 | p = xdr_encode_fhandle(p, args->fh); | 808 | p = xdr_encode_fhandle(p, args->fh); |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index a187200a7aac..311e15cc8af0 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -45,10 +45,29 @@ enum nfs4_client_state { | |||
| 45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
| 46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
| 47 | NFS4CLNT_SESSION_RESET, | 47 | NFS4CLNT_SESSION_RESET, |
| 48 | NFS4CLNT_SESSION_DRAINING, | ||
| 49 | NFS4CLNT_RECALL_SLOT, | 48 | NFS4CLNT_RECALL_SLOT, |
| 50 | }; | 49 | }; |
| 51 | 50 | ||
| 51 | enum nfs4_session_state { | ||
| 52 | NFS4_SESSION_INITING, | ||
| 53 | NFS4_SESSION_DRAINING, | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct nfs4_minor_version_ops { | ||
| 57 | u32 minor_version; | ||
| 58 | |||
| 59 | int (*call_sync)(struct nfs_server *server, | ||
| 60 | struct rpc_message *msg, | ||
| 61 | struct nfs4_sequence_args *args, | ||
| 62 | struct nfs4_sequence_res *res, | ||
| 63 | int cache_reply); | ||
| 64 | int (*validate_stateid)(struct nfs_delegation *, | ||
| 65 | const nfs4_stateid *); | ||
| 66 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | ||
| 67 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; | ||
| 68 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | ||
| 69 | }; | ||
| 70 | |||
| 52 | /* | 71 | /* |
| 53 | * struct rpc_sequence ensures that RPC calls are sent in the exact | 72 | * struct rpc_sequence ensures that RPC calls are sent in the exact |
| 54 | * order that they appear on the list. | 73 | * order that they appear on the list. |
| @@ -89,7 +108,6 @@ struct nfs_unique_id { | |||
| 89 | */ | 108 | */ |
| 90 | struct nfs4_state_owner { | 109 | struct nfs4_state_owner { |
| 91 | struct nfs_unique_id so_owner_id; | 110 | struct nfs_unique_id so_owner_id; |
| 92 | struct nfs_client *so_client; | ||
| 93 | struct nfs_server *so_server; | 111 | struct nfs_server *so_server; |
| 94 | struct rb_node so_client_node; | 112 | struct rb_node so_client_node; |
| 95 | 113 | ||
| @@ -99,7 +117,6 @@ struct nfs4_state_owner { | |||
| 99 | atomic_t so_count; | 117 | atomic_t so_count; |
| 100 | unsigned long so_flags; | 118 | unsigned long so_flags; |
| 101 | struct list_head so_states; | 119 | struct list_head so_states; |
| 102 | struct list_head so_delegations; | ||
| 103 | struct nfs_seqid_counter so_seqid; | 120 | struct nfs_seqid_counter so_seqid; |
| 104 | struct rpc_sequence so_sequence; | 121 | struct rpc_sequence so_sequence; |
| 105 | }; | 122 | }; |
| @@ -125,10 +142,20 @@ enum { | |||
| 125 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | 142 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) |
| 126 | */ | 143 | */ |
| 127 | 144 | ||
| 145 | struct nfs4_lock_owner { | ||
| 146 | unsigned int lo_type; | ||
| 147 | #define NFS4_ANY_LOCK_TYPE (0U) | ||
| 148 | #define NFS4_FLOCK_LOCK_TYPE (1U << 0) | ||
| 149 | #define NFS4_POSIX_LOCK_TYPE (1U << 1) | ||
| 150 | union { | ||
| 151 | fl_owner_t posix_owner; | ||
| 152 | pid_t flock_owner; | ||
| 153 | } lo_u; | ||
| 154 | }; | ||
| 155 | |||
| 128 | struct nfs4_lock_state { | 156 | struct nfs4_lock_state { |
| 129 | struct list_head ls_locks; /* Other lock stateids */ | 157 | struct list_head ls_locks; /* Other lock stateids */ |
| 130 | struct nfs4_state * ls_state; /* Pointer to open state */ | 158 | struct nfs4_state * ls_state; /* Pointer to open state */ |
| 131 | fl_owner_t ls_owner; /* POSIX lock owner */ | ||
| 132 | #define NFS_LOCK_INITIALIZED 1 | 159 | #define NFS_LOCK_INITIALIZED 1 |
| 133 | int ls_flags; | 160 | int ls_flags; |
| 134 | struct nfs_seqid_counter ls_seqid; | 161 | struct nfs_seqid_counter ls_seqid; |
| @@ -136,6 +163,7 @@ struct nfs4_lock_state { | |||
| 136 | struct nfs_unique_id ls_id; | 163 | struct nfs_unique_id ls_id; |
| 137 | nfs4_stateid ls_stateid; | 164 | nfs4_stateid ls_stateid; |
| 138 | atomic_t ls_count; | 165 | atomic_t ls_count; |
| 166 | struct nfs4_lock_owner ls_owner; | ||
| 139 | }; | 167 | }; |
| 140 | 168 | ||
| 141 | /* bits for nfs4_state->flags */ | 169 | /* bits for nfs4_state->flags */ |
| @@ -206,24 +234,28 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
| 206 | 234 | ||
| 207 | 235 | ||
| 208 | /* nfs4proc.c */ | 236 | /* nfs4proc.c */ |
| 209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); | 237 | 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 *); | 238 | 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); | 239 | 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 *); | 240 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
| 213 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 241 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
| 214 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | 242 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); |
| 215 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | 243 | 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); | 244 | 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 *); | 245 | 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 *); | 246 | 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); | 247 | extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); |
| 220 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 248 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
| 221 | struct nfs4_fs_locations *fs_locations, struct page *page); | 249 | struct nfs4_fs_locations *fs_locations, struct page *page); |
| 250 | extern void nfs4_release_lockowner(const struct nfs4_lock_state *); | ||
| 222 | 251 | ||
| 223 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; | ||
| 224 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; | ||
| 225 | #if defined(CONFIG_NFS_V4_1) | 252 | #if defined(CONFIG_NFS_V4_1) |
| 226 | extern int nfs4_setup_sequence(struct nfs_client *clp, | 253 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
| 254 | { | ||
| 255 | return server->nfs_client->cl_session; | ||
| 256 | } | ||
| 257 | |||
| 258 | extern int nfs4_setup_sequence(const struct nfs_server *server, | ||
| 227 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 259 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
| 228 | int cache_reply, struct rpc_task *task); | 260 | int cache_reply, struct rpc_task *task); |
| 229 | extern void nfs4_destroy_session(struct nfs4_session *session); | 261 | extern void nfs4_destroy_session(struct nfs4_session *session); |
| @@ -234,7 +266,12 @@ extern int nfs4_init_session(struct nfs_server *server); | |||
| 234 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | 266 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, |
| 235 | struct nfs_fsinfo *fsinfo); | 267 | struct nfs_fsinfo *fsinfo); |
| 236 | #else /* CONFIG_NFS_v4_1 */ | 268 | #else /* CONFIG_NFS_v4_1 */ |
| 237 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | 269 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
| 270 | { | ||
| 271 | return NULL; | ||
| 272 | } | ||
| 273 | |||
| 274 | static inline int nfs4_setup_sequence(const struct nfs_server *server, | ||
| 238 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 275 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
| 239 | int cache_reply, struct rpc_task *task) | 276 | int cache_reply, struct rpc_task *task) |
| 240 | { | 277 | { |
| @@ -247,7 +284,7 @@ static inline int nfs4_init_session(struct nfs_server *server) | |||
| 247 | } | 284 | } |
| 248 | #endif /* CONFIG_NFS_V4_1 */ | 285 | #endif /* CONFIG_NFS_V4_1 */ |
| 249 | 286 | ||
| 250 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | 287 | extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; |
| 251 | 288 | ||
| 252 | extern const u32 nfs4_fattr_bitmap[2]; | 289 | extern const u32 nfs4_fattr_bitmap[2]; |
| 253 | extern const u32 nfs4_statfs_bitmap[2]; | 290 | extern const u32 nfs4_statfs_bitmap[2]; |
| @@ -284,9 +321,9 @@ extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | |||
| 284 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | 321 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); |
| 285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 322 | 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); | 323 | 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); | 324 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); |
| 288 | 325 | ||
| 289 | extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); | 326 | 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); | 327 | 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); | 328 | 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); | 329 | 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..7ffbb98ddec3 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) |
| @@ -300,15 +303,19 @@ do_state_recovery: | |||
| 300 | } | 303 | } |
| 301 | 304 | ||
| 302 | 305 | ||
| 303 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | 306 | static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp) |
| 304 | { | 307 | { |
| 305 | struct nfs_client *clp = server->nfs_client; | ||
| 306 | spin_lock(&clp->cl_lock); | 308 | spin_lock(&clp->cl_lock); |
| 307 | if (time_before(clp->cl_last_renewal,timestamp)) | 309 | if (time_before(clp->cl_last_renewal,timestamp)) |
| 308 | clp->cl_last_renewal = timestamp; | 310 | clp->cl_last_renewal = timestamp; |
| 309 | spin_unlock(&clp->cl_lock); | 311 | spin_unlock(&clp->cl_lock); |
| 310 | } | 312 | } |
| 311 | 313 | ||
| 314 | static void renew_lease(const struct nfs_server *server, unsigned long timestamp) | ||
| 315 | { | ||
| 316 | do_renew_lease(server->nfs_client, timestamp); | ||
| 317 | } | ||
| 318 | |||
| 312 | #if defined(CONFIG_NFS_V4_1) | 319 | #if defined(CONFIG_NFS_V4_1) |
| 313 | 320 | ||
| 314 | /* | 321 | /* |
| @@ -353,7 +360,7 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
| 353 | { | 360 | { |
| 354 | struct rpc_task *task; | 361 | struct rpc_task *task; |
| 355 | 362 | ||
| 356 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { | 363 | if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { |
| 357 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); | 364 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
| 358 | if (task) | 365 | if (task) |
| 359 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 366 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
| @@ -367,12 +374,11 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | |||
| 367 | complete(&ses->complete); | 374 | complete(&ses->complete); |
| 368 | } | 375 | } |
| 369 | 376 | ||
| 370 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | 377 | static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res) |
| 371 | struct nfs4_sequence_res *res) | ||
| 372 | { | 378 | { |
| 373 | struct nfs4_slot_table *tbl; | 379 | struct nfs4_slot_table *tbl; |
| 374 | 380 | ||
| 375 | tbl = &clp->cl_session->fc_slot_table; | 381 | tbl = &res->sr_session->fc_slot_table; |
| 376 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 382 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
| 377 | /* just wake up the next guy waiting since | 383 | /* just wake up the next guy waiting since |
| 378 | * we may have not consumed a slot after all */ | 384 | * we may have not consumed a slot after all */ |
| @@ -382,18 +388,17 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp, | |||
| 382 | 388 | ||
| 383 | spin_lock(&tbl->slot_tbl_lock); | 389 | spin_lock(&tbl->slot_tbl_lock); |
| 384 | nfs4_free_slot(tbl, res->sr_slotid); | 390 | nfs4_free_slot(tbl, res->sr_slotid); |
| 385 | nfs41_check_drain_session_complete(clp->cl_session); | 391 | nfs41_check_drain_session_complete(res->sr_session); |
| 386 | spin_unlock(&tbl->slot_tbl_lock); | 392 | spin_unlock(&tbl->slot_tbl_lock); |
| 387 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 393 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 388 | } | 394 | } |
| 389 | 395 | ||
| 390 | static void nfs41_sequence_done(struct nfs_client *clp, | 396 | static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res) |
| 391 | struct nfs4_sequence_res *res, | ||
| 392 | int rpc_status) | ||
| 393 | { | 397 | { |
| 394 | unsigned long timestamp; | 398 | unsigned long timestamp; |
| 395 | struct nfs4_slot_table *tbl; | 399 | struct nfs4_slot_table *tbl; |
| 396 | struct nfs4_slot *slot; | 400 | struct nfs4_slot *slot; |
| 401 | struct nfs_client *clp; | ||
| 397 | 402 | ||
| 398 | /* | 403 | /* |
| 399 | * sr_status remains 1 if an RPC level error occurred. The server | 404 | * sr_status remains 1 if an RPC level error occurred. The server |
| @@ -408,25 +413,51 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
| 408 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 413 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
| 409 | goto out; | 414 | goto out; |
| 410 | 415 | ||
| 416 | tbl = &res->sr_session->fc_slot_table; | ||
| 417 | slot = tbl->slots + res->sr_slotid; | ||
| 418 | |||
| 411 | /* Check the SEQUENCE operation status */ | 419 | /* Check the SEQUENCE operation status */ |
| 412 | if (res->sr_status == 0) { | 420 | switch (res->sr_status) { |
| 413 | tbl = &clp->cl_session->fc_slot_table; | 421 | case 0: |
| 414 | slot = tbl->slots + res->sr_slotid; | ||
| 415 | /* Update the slot's sequence and clientid lease timer */ | 422 | /* Update the slot's sequence and clientid lease timer */ |
| 416 | ++slot->seq_nr; | 423 | ++slot->seq_nr; |
| 417 | timestamp = res->sr_renewal_time; | 424 | timestamp = res->sr_renewal_time; |
| 418 | spin_lock(&clp->cl_lock); | 425 | clp = res->sr_session->clp; |
| 419 | if (time_before(clp->cl_last_renewal, timestamp)) | 426 | do_renew_lease(clp, timestamp); |
| 420 | clp->cl_last_renewal = timestamp; | ||
| 421 | spin_unlock(&clp->cl_lock); | ||
| 422 | /* Check sequence flags */ | 427 | /* Check sequence flags */ |
| 423 | if (atomic_read(&clp->cl_count) > 1) | 428 | if (atomic_read(&clp->cl_count) > 1) |
| 424 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | 429 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); |
| 430 | break; | ||
| 431 | case -NFS4ERR_DELAY: | ||
| 432 | /* The server detected a resend of the RPC call and | ||
| 433 | * returned NFS4ERR_DELAY as per Section 2.10.6.2 | ||
| 434 | * of RFC5661. | ||
| 435 | */ | ||
| 436 | dprintk("%s: slot=%d seq=%d: Operation in progress\n", | ||
| 437 | __func__, res->sr_slotid, slot->seq_nr); | ||
| 438 | goto out_retry; | ||
| 439 | default: | ||
| 440 | /* Just update the slot sequence no. */ | ||
| 441 | ++slot->seq_nr; | ||
| 425 | } | 442 | } |
| 426 | out: | 443 | out: |
| 427 | /* The session may be reset by one of the error handlers. */ | 444 | /* The session may be reset by one of the error handlers. */ |
| 428 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | 445 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); |
| 429 | nfs41_sequence_free_slot(clp, res); | 446 | nfs41_sequence_free_slot(res); |
| 447 | return 1; | ||
| 448 | out_retry: | ||
| 449 | if (!rpc_restart_call(task)) | ||
| 450 | goto out; | ||
| 451 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | static int nfs4_sequence_done(struct rpc_task *task, | ||
| 456 | struct nfs4_sequence_res *res) | ||
| 457 | { | ||
| 458 | if (res->sr_session == NULL) | ||
| 459 | return 1; | ||
| 460 | return nfs41_sequence_done(task, res); | ||
| 430 | } | 461 | } |
| 431 | 462 | ||
| 432 | /* | 463 | /* |
| @@ -477,12 +508,11 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 477 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | 508 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) |
| 478 | return 0; | 509 | return 0; |
| 479 | 510 | ||
| 480 | memset(res, 0, sizeof(*res)); | ||
| 481 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 511 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 482 | tbl = &session->fc_slot_table; | 512 | tbl = &session->fc_slot_table; |
| 483 | 513 | ||
| 484 | spin_lock(&tbl->slot_tbl_lock); | 514 | spin_lock(&tbl->slot_tbl_lock); |
| 485 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && | 515 | if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) && |
| 486 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { | 516 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
| 487 | /* | 517 | /* |
| 488 | * The state manager will wait until the slot table is empty. | 518 | * The state manager will wait until the slot table is empty. |
| @@ -522,6 +552,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 522 | res->sr_session = session; | 552 | res->sr_session = session; |
| 523 | res->sr_slotid = slotid; | 553 | res->sr_slotid = slotid; |
| 524 | res->sr_renewal_time = jiffies; | 554 | res->sr_renewal_time = jiffies; |
| 555 | res->sr_status_flags = 0; | ||
| 525 | /* | 556 | /* |
| 526 | * sr_status is only set in decode_sequence, and so will remain | 557 | * sr_status is only set in decode_sequence, and so will remain |
| 527 | * set to 1 if an rpc level failure occurs. | 558 | * set to 1 if an rpc level failure occurs. |
| @@ -530,33 +561,33 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
| 530 | return 0; | 561 | return 0; |
| 531 | } | 562 | } |
| 532 | 563 | ||
| 533 | int nfs4_setup_sequence(struct nfs_client *clp, | 564 | int nfs4_setup_sequence(const struct nfs_server *server, |
| 534 | struct nfs4_sequence_args *args, | 565 | struct nfs4_sequence_args *args, |
| 535 | struct nfs4_sequence_res *res, | 566 | struct nfs4_sequence_res *res, |
| 536 | int cache_reply, | 567 | int cache_reply, |
| 537 | struct rpc_task *task) | 568 | struct rpc_task *task) |
| 538 | { | 569 | { |
| 570 | struct nfs4_session *session = nfs4_get_session(server); | ||
| 539 | int ret = 0; | 571 | int ret = 0; |
| 540 | 572 | ||
| 573 | if (session == NULL) { | ||
| 574 | args->sa_session = NULL; | ||
| 575 | res->sr_session = NULL; | ||
| 576 | goto out; | ||
| 577 | } | ||
| 578 | |||
| 541 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | 579 | dprintk("--> %s clp %p session %p sr_slotid %d\n", |
| 542 | __func__, clp, clp->cl_session, res->sr_slotid); | 580 | __func__, session->clp, session, res->sr_slotid); |
| 543 | 581 | ||
| 544 | if (!nfs4_has_session(clp)) | 582 | ret = nfs41_setup_sequence(session, args, res, cache_reply, |
| 545 | goto out; | ||
| 546 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
| 547 | task); | 583 | task); |
| 548 | if (ret && ret != -EAGAIN) { | ||
| 549 | /* terminate rpc task */ | ||
| 550 | task->tk_status = ret; | ||
| 551 | task->tk_action = NULL; | ||
| 552 | } | ||
| 553 | out: | 584 | out: |
| 554 | dprintk("<-- %s status=%d\n", __func__, ret); | 585 | dprintk("<-- %s status=%d\n", __func__, ret); |
| 555 | return ret; | 586 | return ret; |
| 556 | } | 587 | } |
| 557 | 588 | ||
| 558 | struct nfs41_call_sync_data { | 589 | struct nfs41_call_sync_data { |
| 559 | struct nfs_client *clp; | 590 | const struct nfs_server *seq_server; |
| 560 | struct nfs4_sequence_args *seq_args; | 591 | struct nfs4_sequence_args *seq_args; |
| 561 | struct nfs4_sequence_res *seq_res; | 592 | struct nfs4_sequence_res *seq_res; |
| 562 | int cache_reply; | 593 | int cache_reply; |
| @@ -566,9 +597,9 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
| 566 | { | 597 | { |
| 567 | struct nfs41_call_sync_data *data = calldata; | 598 | struct nfs41_call_sync_data *data = calldata; |
| 568 | 599 | ||
| 569 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | 600 | dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server); |
| 570 | data->clp->cl_session); | 601 | |
| 571 | if (nfs4_setup_sequence(data->clp, data->seq_args, | 602 | if (nfs4_setup_sequence(data->seq_server, data->seq_args, |
| 572 | data->seq_res, data->cache_reply, task)) | 603 | data->seq_res, data->cache_reply, task)) |
| 573 | return; | 604 | return; |
| 574 | rpc_call_start(task); | 605 | rpc_call_start(task); |
| @@ -584,7 +615,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | |||
| 584 | { | 615 | { |
| 585 | struct nfs41_call_sync_data *data = calldata; | 616 | struct nfs41_call_sync_data *data = calldata; |
| 586 | 617 | ||
| 587 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 618 | nfs41_sequence_done(task, data->seq_res); |
| 588 | } | 619 | } |
| 589 | 620 | ||
| 590 | struct rpc_call_ops nfs41_call_sync_ops = { | 621 | struct rpc_call_ops nfs41_call_sync_ops = { |
| @@ -597,8 +628,7 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = { | |||
| 597 | .rpc_call_done = nfs41_call_sync_done, | 628 | .rpc_call_done = nfs41_call_sync_done, |
| 598 | }; | 629 | }; |
| 599 | 630 | ||
| 600 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 631 | static int nfs4_call_sync_sequence(struct nfs_server *server, |
| 601 | struct rpc_clnt *clnt, | ||
| 602 | struct rpc_message *msg, | 632 | struct rpc_message *msg, |
| 603 | struct nfs4_sequence_args *args, | 633 | struct nfs4_sequence_args *args, |
| 604 | struct nfs4_sequence_res *res, | 634 | struct nfs4_sequence_res *res, |
| @@ -608,13 +638,13 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
| 608 | int ret; | 638 | int ret; |
| 609 | struct rpc_task *task; | 639 | struct rpc_task *task; |
| 610 | struct nfs41_call_sync_data data = { | 640 | struct nfs41_call_sync_data data = { |
| 611 | .clp = clp, | 641 | .seq_server = server, |
| 612 | .seq_args = args, | 642 | .seq_args = args, |
| 613 | .seq_res = res, | 643 | .seq_res = res, |
| 614 | .cache_reply = cache_reply, | 644 | .cache_reply = cache_reply, |
| 615 | }; | 645 | }; |
| 616 | struct rpc_task_setup task_setup = { | 646 | struct rpc_task_setup task_setup = { |
| 617 | .rpc_client = clnt, | 647 | .rpc_client = server->client, |
| 618 | .rpc_message = msg, | 648 | .rpc_message = msg, |
| 619 | .callback_ops = &nfs41_call_sync_ops, | 649 | .callback_ops = &nfs41_call_sync_ops, |
| 620 | .callback_data = &data | 650 | .callback_data = &data |
| @@ -639,10 +669,15 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
| 639 | struct nfs4_sequence_res *res, | 669 | struct nfs4_sequence_res *res, |
| 640 | int cache_reply) | 670 | int cache_reply) |
| 641 | { | 671 | { |
| 642 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 672 | return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0); |
| 643 | msg, args, res, cache_reply, 0); | ||
| 644 | } | 673 | } |
| 645 | 674 | ||
| 675 | #else | ||
| 676 | static int nfs4_sequence_done(struct rpc_task *task, | ||
| 677 | struct nfs4_sequence_res *res) | ||
| 678 | { | ||
| 679 | return 1; | ||
| 680 | } | ||
| 646 | #endif /* CONFIG_NFS_V4_1 */ | 681 | #endif /* CONFIG_NFS_V4_1 */ |
| 647 | 682 | ||
| 648 | int _nfs4_call_sync(struct nfs_server *server, | 683 | int _nfs4_call_sync(struct nfs_server *server, |
| @@ -656,18 +691,9 @@ int _nfs4_call_sync(struct nfs_server *server, | |||
| 656 | } | 691 | } |
| 657 | 692 | ||
| 658 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | 693 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ |
| 659 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | 694 | (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \ |
| 660 | &(res)->seq_res, (cache_reply)) | 695 | &(res)->seq_res, (cache_reply)) |
| 661 | 696 | ||
| 662 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
| 663 | struct nfs4_sequence_res *res, int rpc_status) | ||
| 664 | { | ||
| 665 | #ifdef CONFIG_NFS_V4_1 | ||
| 666 | if (nfs4_has_session(server->nfs_client)) | ||
| 667 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
| 668 | #endif /* CONFIG_NFS_V4_1 */ | ||
| 669 | } | ||
| 670 | |||
| 671 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 697 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
| 672 | { | 698 | { |
| 673 | struct nfs_inode *nfsi = NFS_I(dir); | 699 | struct nfs_inode *nfsi = NFS_I(dir); |
| @@ -714,17 +740,18 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
| 714 | 740 | ||
| 715 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 741 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
| 716 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, | 742 | struct nfs4_state_owner *sp, fmode_t fmode, int flags, |
| 717 | const struct iattr *attrs) | 743 | const struct iattr *attrs, |
| 744 | gfp_t gfp_mask) | ||
| 718 | { | 745 | { |
| 719 | struct dentry *parent = dget_parent(path->dentry); | 746 | struct dentry *parent = dget_parent(path->dentry); |
| 720 | struct inode *dir = parent->d_inode; | 747 | struct inode *dir = parent->d_inode; |
| 721 | struct nfs_server *server = NFS_SERVER(dir); | 748 | struct nfs_server *server = NFS_SERVER(dir); |
| 722 | struct nfs4_opendata *p; | 749 | struct nfs4_opendata *p; |
| 723 | 750 | ||
| 724 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 751 | p = kzalloc(sizeof(*p), gfp_mask); |
| 725 | if (p == NULL) | 752 | if (p == NULL) |
| 726 | goto err; | 753 | goto err; |
| 727 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 754 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); |
| 728 | if (p->o_arg.seqid == NULL) | 755 | if (p->o_arg.seqid == NULL) |
| 729 | goto err_free; | 756 | goto err_free; |
| 730 | path_get(path); | 757 | path_get(path); |
| @@ -741,19 +768,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
| 741 | p->o_arg.server = server; | 768 | p->o_arg.server = server; |
| 742 | p->o_arg.bitmask = server->attr_bitmask; | 769 | p->o_arg.bitmask = server->attr_bitmask; |
| 743 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 770 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
| 744 | if (flags & O_EXCL) { | 771 | if (flags & O_CREAT) { |
| 745 | if (nfs4_has_persistent_session(server->nfs_client)) { | 772 | u32 *s; |
| 746 | /* GUARDED */ | 773 | |
| 747 | p->o_arg.u.attrs = &p->attrs; | ||
| 748 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
| 749 | } else { /* EXCLUSIVE4_1 */ | ||
| 750 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
| 751 | s[0] = jiffies; | ||
| 752 | s[1] = current->pid; | ||
| 753 | } | ||
| 754 | } else if (flags & O_CREAT) { | ||
| 755 | p->o_arg.u.attrs = &p->attrs; | 774 | p->o_arg.u.attrs = &p->attrs; |
| 756 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 775 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
| 776 | s = (u32 *) p->o_arg.u.verifier.data; | ||
| 777 | s[0] = jiffies; | ||
| 778 | s[1] = current->pid; | ||
| 757 | } | 779 | } |
| 758 | p->c_arg.fh = &p->o_res.fh; | 780 | p->c_arg.fh = &p->o_res.fh; |
| 759 | p->c_arg.stateid = &p->o_res.stateid; | 781 | p->c_arg.stateid = &p->o_res.stateid; |
| @@ -1060,7 +1082,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context | |||
| 1060 | { | 1082 | { |
| 1061 | struct nfs4_opendata *opendata; | 1083 | struct nfs4_opendata *opendata; |
| 1062 | 1084 | ||
| 1063 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL); | 1085 | opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, 0, NULL, GFP_NOFS); |
| 1064 | if (opendata == NULL) | 1086 | if (opendata == NULL) |
| 1065 | return ERR_PTR(-ENOMEM); | 1087 | return ERR_PTR(-ENOMEM); |
| 1066 | opendata->state = state; | 1088 | opendata->state = state; |
| @@ -1251,8 +1273,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) | |||
| 1251 | struct nfs4_opendata *data = calldata; | 1273 | struct nfs4_opendata *data = calldata; |
| 1252 | 1274 | ||
| 1253 | data->rpc_status = task->tk_status; | 1275 | data->rpc_status = task->tk_status; |
| 1254 | if (RPC_ASSASSINATED(task)) | ||
| 1255 | return; | ||
| 1256 | if (data->rpc_status == 0) { | 1276 | if (data->rpc_status == 0) { |
| 1257 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, | 1277 | memcpy(data->o_res.stateid.data, data->c_res.stateid.data, |
| 1258 | sizeof(data->o_res.stateid.data)); | 1278 | sizeof(data->o_res.stateid.data)); |
| @@ -1352,13 +1372,13 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
| 1352 | } | 1372 | } |
| 1353 | /* Update sequence id. */ | 1373 | /* Update sequence id. */ |
| 1354 | data->o_arg.id = sp->so_owner_id.id; | 1374 | data->o_arg.id = sp->so_owner_id.id; |
| 1355 | data->o_arg.clientid = sp->so_client->cl_clientid; | 1375 | data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid; |
| 1356 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { | 1376 | if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { |
| 1357 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; | 1377 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; |
| 1358 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1378 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
| 1359 | } | 1379 | } |
| 1360 | data->timestamp = jiffies; | 1380 | data->timestamp = jiffies; |
| 1361 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | 1381 | if (nfs4_setup_sequence(data->o_arg.server, |
| 1362 | &data->o_arg.seq_args, | 1382 | &data->o_arg.seq_args, |
| 1363 | &data->o_res.seq_res, 1, task)) | 1383 | &data->o_res.seq_res, 1, task)) |
| 1364 | return; | 1384 | return; |
| @@ -1381,11 +1401,9 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
| 1381 | 1401 | ||
| 1382 | data->rpc_status = task->tk_status; | 1402 | data->rpc_status = task->tk_status; |
| 1383 | 1403 | ||
| 1384 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, | 1404 | if (!nfs4_sequence_done(task, &data->o_res.seq_res)) |
| 1385 | task->tk_status); | ||
| 1386 | |||
| 1387 | if (RPC_ASSASSINATED(task)) | ||
| 1388 | return; | 1405 | return; |
| 1406 | |||
| 1389 | if (task->tk_status == 0) { | 1407 | if (task->tk_status == 0) { |
| 1390 | switch (data->o_res.f_attr->mode & S_IFMT) { | 1408 | switch (data->o_res.f_attr->mode & S_IFMT) { |
| 1391 | case S_IFREG: | 1409 | case S_IFREG: |
| @@ -1648,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
| 1648 | if (path->dentry->d_inode != NULL) | 1666 | if (path->dentry->d_inode != NULL) |
| 1649 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); | 1667 | nfs4_return_incompatible_delegation(path->dentry->d_inode, fmode); |
| 1650 | status = -ENOMEM; | 1668 | status = -ENOMEM; |
| 1651 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr); | 1669 | opendata = nfs4_opendata_alloc(path, sp, fmode, flags, sattr, GFP_KERNEL); |
| 1652 | if (opendata == NULL) | 1670 | if (opendata == NULL) |
| 1653 | goto err_put_state_owner; | 1671 | goto err_put_state_owner; |
| 1654 | 1672 | ||
| @@ -1659,15 +1677,24 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
| 1659 | if (status != 0) | 1677 | if (status != 0) |
| 1660 | goto err_opendata_put; | 1678 | goto err_opendata_put; |
| 1661 | 1679 | ||
| 1662 | if (opendata->o_arg.open_flags & O_EXCL) | ||
| 1663 | nfs4_exclusive_attrset(opendata, sattr); | ||
| 1664 | |||
| 1665 | state = nfs4_opendata_to_nfs4_state(opendata); | 1680 | state = nfs4_opendata_to_nfs4_state(opendata); |
| 1666 | status = PTR_ERR(state); | 1681 | status = PTR_ERR(state); |
| 1667 | if (IS_ERR(state)) | 1682 | if (IS_ERR(state)) |
| 1668 | goto err_opendata_put; | 1683 | goto err_opendata_put; |
| 1669 | if (server->caps & NFS_CAP_POSIX_LOCK) | 1684 | if (server->caps & NFS_CAP_POSIX_LOCK) |
| 1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 1685 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
| 1686 | |||
| 1687 | if (opendata->o_arg.open_flags & O_EXCL) { | ||
| 1688 | nfs4_exclusive_attrset(opendata, sattr); | ||
| 1689 | |||
| 1690 | nfs_fattr_init(opendata->o_res.f_attr); | ||
| 1691 | status = nfs4_do_setattr(state->inode, cred, | ||
| 1692 | opendata->o_res.f_attr, sattr, | ||
| 1693 | state); | ||
| 1694 | if (status == 0) | ||
| 1695 | nfs_setattr_update_inode(state->inode, sattr); | ||
| 1696 | nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); | ||
| 1697 | } | ||
| 1671 | nfs4_opendata_put(opendata); | 1698 | nfs4_opendata_put(opendata); |
| 1672 | nfs4_put_state_owner(sp); | 1699 | nfs4_put_state_owner(sp); |
| 1673 | *res = state; | 1700 | *res = state; |
| @@ -1760,7 +1787,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
| 1760 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { | 1787 | if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) { |
| 1761 | /* Use that stateid */ | 1788 | /* Use that stateid */ |
| 1762 | } else if (state != NULL) { | 1789 | } else if (state != NULL) { |
| 1763 | nfs4_copy_stateid(&arg.stateid, state, current->files); | 1790 | nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid); |
| 1764 | } else | 1791 | } else |
| 1765 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1792 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
| 1766 | 1793 | ||
| @@ -1825,8 +1852,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
| 1825 | struct nfs4_state *state = calldata->state; | 1852 | struct nfs4_state *state = calldata->state; |
| 1826 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1853 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
| 1827 | 1854 | ||
| 1828 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | 1855 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
| 1829 | if (RPC_ASSASSINATED(task)) | ||
| 1830 | return; | 1856 | return; |
| 1831 | /* hmm. we are done with the inode, and in the process of freeing | 1857 | /* hmm. we are done with the inode, and in the process of freeing |
| 1832 | * the state_owner. we keep this around to process errors | 1858 | * the state_owner. we keep this around to process errors |
| @@ -1890,7 +1916,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
| 1890 | 1916 | ||
| 1891 | nfs_fattr_init(calldata->res.fattr); | 1917 | nfs_fattr_init(calldata->res.fattr); |
| 1892 | calldata->timestamp = jiffies; | 1918 | calldata->timestamp = jiffies; |
| 1893 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1919 | if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), |
| 1894 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1920 | &calldata->arg.seq_args, &calldata->res.seq_res, |
| 1895 | 1, task)) | 1921 | 1, task)) |
| 1896 | return; | 1922 | return; |
| @@ -1914,7 +1940,7 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
| 1914 | * | 1940 | * |
| 1915 | * NOTE: Caller must be holding the sp->so_owner semaphore! | 1941 | * NOTE: Caller must be holding the sp->so_owner semaphore! |
| 1916 | */ | 1942 | */ |
| 1917 | int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | 1943 | int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait) |
| 1918 | { | 1944 | { |
| 1919 | struct nfs_server *server = NFS_SERVER(state->inode); | 1945 | struct nfs_server *server = NFS_SERVER(state->inode); |
| 1920 | struct nfs4_closedata *calldata; | 1946 | struct nfs4_closedata *calldata; |
| @@ -1933,7 +1959,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1933 | }; | 1959 | }; |
| 1934 | int status = -ENOMEM; | 1960 | int status = -ENOMEM; |
| 1935 | 1961 | ||
| 1936 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 1962 | calldata = kzalloc(sizeof(*calldata), gfp_mask); |
| 1937 | if (calldata == NULL) | 1963 | if (calldata == NULL) |
| 1938 | goto out; | 1964 | goto out; |
| 1939 | calldata->inode = state->inode; | 1965 | calldata->inode = state->inode; |
| @@ -1941,7 +1967,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
| 1941 | calldata->arg.fh = NFS_FH(state->inode); | 1967 | calldata->arg.fh = NFS_FH(state->inode); |
| 1942 | calldata->arg.stateid = &state->open_stateid; | 1968 | calldata->arg.stateid = &state->open_stateid; |
| 1943 | /* Serialization for the sequence id */ | 1969 | /* Serialization for the sequence id */ |
| 1944 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1970 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask); |
| 1945 | if (calldata->arg.seqid == NULL) | 1971 | if (calldata->arg.seqid == NULL) |
| 1946 | goto out_free_calldata; | 1972 | goto out_free_calldata; |
| 1947 | calldata->arg.fmode = 0; | 1973 | calldata->arg.fmode = 0; |
| @@ -2404,14 +2430,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) | 2430 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
| 2405 | { | 2431 | { |
| 2406 | struct nfs_server *server = NFS_SERVER(inode); | 2432 | struct nfs_server *server = NFS_SERVER(inode); |
| 2407 | struct nfs_fattr fattr; | ||
| 2408 | struct nfs4_accessargs args = { | 2433 | struct nfs4_accessargs args = { |
| 2409 | .fh = NFS_FH(inode), | 2434 | .fh = NFS_FH(inode), |
| 2410 | .bitmask = server->attr_bitmask, | 2435 | .bitmask = server->attr_bitmask, |
| 2411 | }; | 2436 | }; |
| 2412 | struct nfs4_accessres res = { | 2437 | struct nfs4_accessres res = { |
| 2413 | .server = server, | 2438 | .server = server, |
| 2414 | .fattr = &fattr, | ||
| 2415 | }; | 2439 | }; |
| 2416 | struct rpc_message msg = { | 2440 | struct rpc_message msg = { |
| 2417 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], | 2441 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], |
| @@ -2438,7 +2462,11 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 2438 | if (mode & MAY_EXEC) | 2462 | if (mode & MAY_EXEC) |
| 2439 | args.access |= NFS4_ACCESS_EXECUTE; | 2463 | args.access |= NFS4_ACCESS_EXECUTE; |
| 2440 | } | 2464 | } |
| 2441 | nfs_fattr_init(&fattr); | 2465 | |
| 2466 | res.fattr = nfs_alloc_fattr(); | ||
| 2467 | if (res.fattr == NULL) | ||
| 2468 | return -ENOMEM; | ||
| 2469 | |||
| 2442 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | 2470 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
| 2443 | if (!status) { | 2471 | if (!status) { |
| 2444 | entry->mask = 0; | 2472 | entry->mask = 0; |
| @@ -2448,8 +2476,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
| 2448 | entry->mask |= MAY_WRITE; | 2476 | entry->mask |= MAY_WRITE; |
| 2449 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) | 2477 | if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE)) |
| 2450 | entry->mask |= MAY_EXEC; | 2478 | entry->mask |= MAY_EXEC; |
| 2451 | nfs_refresh_inode(inode, &fattr); | 2479 | nfs_refresh_inode(inode, res.fattr); |
| 2452 | } | 2480 | } |
| 2481 | nfs_free_fattr(res.fattr); | ||
| 2453 | return status; | 2482 | return status; |
| 2454 | } | 2483 | } |
| 2455 | 2484 | ||
| @@ -2562,13 +2591,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | |||
| 2562 | } | 2591 | } |
| 2563 | d_add(dentry, igrab(state->inode)); | 2592 | d_add(dentry, igrab(state->inode)); |
| 2564 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 2593 | 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) | 2594 | if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) |
| 2573 | status = nfs4_intent_set_file(nd, &path, state, fmode); | 2595 | status = nfs4_intent_set_file(nd, &path, state, fmode); |
| 2574 | else | 2596 | else |
| @@ -2596,14 +2618,19 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
| 2596 | .rpc_argp = &args, | 2618 | .rpc_argp = &args, |
| 2597 | .rpc_resp = &res, | 2619 | .rpc_resp = &res, |
| 2598 | }; | 2620 | }; |
| 2599 | int status; | 2621 | int status = -ENOMEM; |
| 2622 | |||
| 2623 | res.dir_attr = nfs_alloc_fattr(); | ||
| 2624 | if (res.dir_attr == NULL) | ||
| 2625 | goto out; | ||
| 2600 | 2626 | ||
| 2601 | nfs_fattr_init(&res.dir_attr); | ||
| 2602 | status = nfs4_call_sync(server, &msg, &args, &res, 1); | 2627 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
| 2603 | if (status == 0) { | 2628 | if (status == 0) { |
| 2604 | update_changeattr(dir, &res.cinfo); | 2629 | update_changeattr(dir, &res.cinfo); |
| 2605 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2630 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 2606 | } | 2631 | } |
| 2632 | nfs_free_fattr(res.dir_attr); | ||
| 2633 | out: | ||
| 2607 | return status; | 2634 | return status; |
| 2608 | } | 2635 | } |
| 2609 | 2636 | ||
| @@ -2634,11 +2661,12 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
| 2634 | { | 2661 | { |
| 2635 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2662 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
| 2636 | 2663 | ||
| 2637 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2664 | if (!nfs4_sequence_done(task, &res->seq_res)) |
| 2665 | return 0; | ||
| 2638 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2666 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
| 2639 | return 0; | 2667 | return 0; |
| 2640 | update_changeattr(dir, &res->cinfo); | 2668 | update_changeattr(dir, &res->cinfo); |
| 2641 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2669 | nfs_post_op_update_inode(dir, res->dir_attr); |
| 2642 | return 1; | 2670 | return 1; |
| 2643 | } | 2671 | } |
| 2644 | 2672 | ||
| @@ -2653,29 +2681,31 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
| 2653 | .new_name = new_name, | 2681 | .new_name = new_name, |
| 2654 | .bitmask = server->attr_bitmask, | 2682 | .bitmask = server->attr_bitmask, |
| 2655 | }; | 2683 | }; |
| 2656 | struct nfs_fattr old_fattr, new_fattr; | ||
| 2657 | struct nfs4_rename_res res = { | 2684 | struct nfs4_rename_res res = { |
| 2658 | .server = server, | 2685 | .server = server, |
| 2659 | .old_fattr = &old_fattr, | ||
| 2660 | .new_fattr = &new_fattr, | ||
| 2661 | }; | 2686 | }; |
| 2662 | struct rpc_message msg = { | 2687 | struct rpc_message msg = { |
| 2663 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], | 2688 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME], |
| 2664 | .rpc_argp = &arg, | 2689 | .rpc_argp = &arg, |
| 2665 | .rpc_resp = &res, | 2690 | .rpc_resp = &res, |
| 2666 | }; | 2691 | }; |
| 2667 | int status; | 2692 | int status = -ENOMEM; |
| 2668 | 2693 | ||
| 2669 | nfs_fattr_init(res.old_fattr); | 2694 | res.old_fattr = nfs_alloc_fattr(); |
| 2670 | nfs_fattr_init(res.new_fattr); | 2695 | res.new_fattr = nfs_alloc_fattr(); |
| 2671 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2696 | if (res.old_fattr == NULL || res.new_fattr == NULL) |
| 2697 | goto out; | ||
| 2672 | 2698 | ||
| 2699 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | ||
| 2673 | if (!status) { | 2700 | if (!status) { |
| 2674 | update_changeattr(old_dir, &res.old_cinfo); | 2701 | update_changeattr(old_dir, &res.old_cinfo); |
| 2675 | nfs_post_op_update_inode(old_dir, res.old_fattr); | 2702 | nfs_post_op_update_inode(old_dir, res.old_fattr); |
| 2676 | update_changeattr(new_dir, &res.new_cinfo); | 2703 | update_changeattr(new_dir, &res.new_cinfo); |
| 2677 | nfs_post_op_update_inode(new_dir, res.new_fattr); | 2704 | nfs_post_op_update_inode(new_dir, res.new_fattr); |
| 2678 | } | 2705 | } |
| 2706 | out: | ||
| 2707 | nfs_free_fattr(res.new_fattr); | ||
| 2708 | nfs_free_fattr(res.old_fattr); | ||
| 2679 | return status; | 2709 | return status; |
| 2680 | } | 2710 | } |
| 2681 | 2711 | ||
| @@ -2702,28 +2732,30 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
| 2702 | .name = name, | 2732 | .name = name, |
| 2703 | .bitmask = server->attr_bitmask, | 2733 | .bitmask = server->attr_bitmask, |
| 2704 | }; | 2734 | }; |
| 2705 | struct nfs_fattr fattr, dir_attr; | ||
| 2706 | struct nfs4_link_res res = { | 2735 | struct nfs4_link_res res = { |
| 2707 | .server = server, | 2736 | .server = server, |
| 2708 | .fattr = &fattr, | ||
| 2709 | .dir_attr = &dir_attr, | ||
| 2710 | }; | 2737 | }; |
| 2711 | struct rpc_message msg = { | 2738 | struct rpc_message msg = { |
| 2712 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], | 2739 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], |
| 2713 | .rpc_argp = &arg, | 2740 | .rpc_argp = &arg, |
| 2714 | .rpc_resp = &res, | 2741 | .rpc_resp = &res, |
| 2715 | }; | 2742 | }; |
| 2716 | int status; | 2743 | int status = -ENOMEM; |
| 2744 | |||
| 2745 | res.fattr = nfs_alloc_fattr(); | ||
| 2746 | res.dir_attr = nfs_alloc_fattr(); | ||
| 2747 | if (res.fattr == NULL || res.dir_attr == NULL) | ||
| 2748 | goto out; | ||
| 2717 | 2749 | ||
| 2718 | nfs_fattr_init(res.fattr); | ||
| 2719 | nfs_fattr_init(res.dir_attr); | ||
| 2720 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); | 2750 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
| 2721 | if (!status) { | 2751 | if (!status) { |
| 2722 | update_changeattr(dir, &res.cinfo); | 2752 | update_changeattr(dir, &res.cinfo); |
| 2723 | nfs_post_op_update_inode(dir, res.dir_attr); | 2753 | nfs_post_op_update_inode(dir, res.dir_attr); |
| 2724 | nfs_post_op_update_inode(inode, res.fattr); | 2754 | nfs_post_op_update_inode(inode, res.fattr); |
| 2725 | } | 2755 | } |
| 2726 | 2756 | out: | |
| 2757 | nfs_free_fattr(res.dir_attr); | ||
| 2758 | nfs_free_fattr(res.fattr); | ||
| 2727 | return status; | 2759 | return status; |
| 2728 | } | 2760 | } |
| 2729 | 2761 | ||
| @@ -3075,7 +3107,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
| 3075 | 3107 | ||
| 3076 | dprintk("--> %s\n", __func__); | 3108 | dprintk("--> %s\n", __func__); |
| 3077 | 3109 | ||
| 3078 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3110 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3111 | return -EAGAIN; | ||
| 3079 | 3112 | ||
| 3080 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3113 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
| 3081 | nfs_restart_rpc(task, server->nfs_client); | 3114 | nfs_restart_rpc(task, server->nfs_client); |
| @@ -3098,8 +3131,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 3098 | { | 3131 | { |
| 3099 | struct inode *inode = data->inode; | 3132 | struct inode *inode = data->inode; |
| 3100 | 3133 | ||
| 3101 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3134 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3102 | task->tk_status); | 3135 | return -EAGAIN; |
| 3103 | 3136 | ||
| 3104 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3137 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
| 3105 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3138 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| @@ -3127,8 +3160,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
| 3127 | { | 3160 | { |
| 3128 | struct inode *inode = data->inode; | 3161 | struct inode *inode = data->inode; |
| 3129 | 3162 | ||
| 3130 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3163 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3131 | task->tk_status); | 3164 | return -EAGAIN; |
| 3165 | |||
| 3132 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3166 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
| 3133 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3167 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
| 3134 | return -EAGAIN; | 3168 | return -EAGAIN; |
| @@ -3146,23 +3180,31 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
| 3146 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; | 3180 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT]; |
| 3147 | } | 3181 | } |
| 3148 | 3182 | ||
| 3183 | struct nfs4_renewdata { | ||
| 3184 | struct nfs_client *client; | ||
| 3185 | unsigned long timestamp; | ||
| 3186 | }; | ||
| 3187 | |||
| 3149 | /* | 3188 | /* |
| 3150 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3189 | * 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. | 3190 | * standalone procedure for queueing an asynchronous RENEW. |
| 3152 | */ | 3191 | */ |
| 3153 | static void nfs4_renew_release(void *data) | 3192 | static void nfs4_renew_release(void *calldata) |
| 3154 | { | 3193 | { |
| 3155 | struct nfs_client *clp = data; | 3194 | struct nfs4_renewdata *data = calldata; |
| 3195 | struct nfs_client *clp = data->client; | ||
| 3156 | 3196 | ||
| 3157 | if (atomic_read(&clp->cl_count) > 1) | 3197 | if (atomic_read(&clp->cl_count) > 1) |
| 3158 | nfs4_schedule_state_renewal(clp); | 3198 | nfs4_schedule_state_renewal(clp); |
| 3159 | nfs_put_client(clp); | 3199 | nfs_put_client(clp); |
| 3200 | kfree(data); | ||
| 3160 | } | 3201 | } |
| 3161 | 3202 | ||
| 3162 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3203 | static void nfs4_renew_done(struct rpc_task *task, void *calldata) |
| 3163 | { | 3204 | { |
| 3164 | struct nfs_client *clp = data; | 3205 | struct nfs4_renewdata *data = calldata; |
| 3165 | unsigned long timestamp = task->tk_start; | 3206 | struct nfs_client *clp = data->client; |
| 3207 | unsigned long timestamp = data->timestamp; | ||
| 3166 | 3208 | ||
| 3167 | if (task->tk_status < 0) { | 3209 | if (task->tk_status < 0) { |
| 3168 | /* Unless we're shutting down, schedule state recovery! */ | 3210 | /* Unless we're shutting down, schedule state recovery! */ |
| @@ -3170,10 +3212,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
| 3170 | nfs4_schedule_state_recovery(clp); | 3212 | nfs4_schedule_state_recovery(clp); |
| 3171 | return; | 3213 | return; |
| 3172 | } | 3214 | } |
| 3173 | spin_lock(&clp->cl_lock); | 3215 | do_renew_lease(clp, timestamp); |
| 3174 | if (time_before(clp->cl_last_renewal,timestamp)) | ||
| 3175 | clp->cl_last_renewal = timestamp; | ||
| 3176 | spin_unlock(&clp->cl_lock); | ||
| 3177 | } | 3216 | } |
| 3178 | 3217 | ||
| 3179 | static const struct rpc_call_ops nfs4_renew_ops = { | 3218 | static const struct rpc_call_ops nfs4_renew_ops = { |
| @@ -3188,11 +3227,17 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 3188 | .rpc_argp = clp, | 3227 | .rpc_argp = clp, |
| 3189 | .rpc_cred = cred, | 3228 | .rpc_cred = cred, |
| 3190 | }; | 3229 | }; |
| 3230 | struct nfs4_renewdata *data; | ||
| 3191 | 3231 | ||
| 3192 | if (!atomic_inc_not_zero(&clp->cl_count)) | 3232 | if (!atomic_inc_not_zero(&clp->cl_count)) |
| 3193 | return -EIO; | 3233 | return -EIO; |
| 3234 | data = kmalloc(sizeof(*data), GFP_KERNEL); | ||
| 3235 | if (data == NULL) | ||
| 3236 | return -ENOMEM; | ||
| 3237 | data->client = clp; | ||
| 3238 | data->timestamp = jiffies; | ||
| 3194 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3239 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
| 3195 | &nfs4_renew_ops, clp); | 3240 | &nfs4_renew_ops, data); |
| 3196 | } | 3241 | } |
| 3197 | 3242 | ||
| 3198 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3243 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
| @@ -3208,10 +3253,7 @@ int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
| 3208 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 3253 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
| 3209 | if (status < 0) | 3254 | if (status < 0) |
| 3210 | return status; | 3255 | return status; |
| 3211 | spin_lock(&clp->cl_lock); | 3256 | do_renew_lease(clp, now); |
| 3212 | if (time_before(clp->cl_last_renewal,now)) | ||
| 3213 | clp->cl_last_renewal = now; | ||
| 3214 | spin_unlock(&clp->cl_lock); | ||
| 3215 | return 0; | 3257 | return 0; |
| 3216 | } | 3258 | } |
| 3217 | 3259 | ||
| @@ -3432,9 +3474,11 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
| 3432 | } | 3474 | } |
| 3433 | 3475 | ||
| 3434 | static int | 3476 | static int |
| 3435 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) | 3477 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) |
| 3436 | { | 3478 | { |
| 3437 | if (!clp || task->tk_status >= 0) | 3479 | struct nfs_client *clp = server->nfs_client; |
| 3480 | |||
| 3481 | if (task->tk_status >= 0) | ||
| 3438 | return 0; | 3482 | return 0; |
| 3439 | switch(task->tk_status) { | 3483 | switch(task->tk_status) { |
| 3440 | case -NFS4ERR_ADMIN_REVOKED: | 3484 | case -NFS4ERR_ADMIN_REVOKED: |
| @@ -3466,8 +3510,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
| 3466 | return -EAGAIN; | 3510 | return -EAGAIN; |
| 3467 | #endif /* CONFIG_NFS_V4_1 */ | 3511 | #endif /* CONFIG_NFS_V4_1 */ |
| 3468 | case -NFS4ERR_DELAY: | 3512 | case -NFS4ERR_DELAY: |
| 3469 | if (server) | 3513 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
| 3470 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
| 3471 | case -NFS4ERR_GRACE: | 3514 | case -NFS4ERR_GRACE: |
| 3472 | case -EKEYEXPIRED: | 3515 | case -EKEYEXPIRED: |
| 3473 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3516 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
| @@ -3488,13 +3531,9 @@ do_state_recovery: | |||
| 3488 | return -EAGAIN; | 3531 | return -EAGAIN; |
| 3489 | } | 3532 | } |
| 3490 | 3533 | ||
| 3491 | static int | 3534 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, |
| 3492 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3535 | unsigned short port, struct rpc_cred *cred, |
| 3493 | { | 3536 | struct nfs4_setclientid_res *res) |
| 3494 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
| 3495 | } | ||
| 3496 | |||
| 3497 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | ||
| 3498 | { | 3537 | { |
| 3499 | nfs4_verifier sc_verifier; | 3538 | nfs4_verifier sc_verifier; |
| 3500 | struct nfs4_setclientid setclientid = { | 3539 | struct nfs4_setclientid setclientid = { |
| @@ -3504,7 +3543,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
| 3504 | struct rpc_message msg = { | 3543 | struct rpc_message msg = { |
| 3505 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], | 3544 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], |
| 3506 | .rpc_argp = &setclientid, | 3545 | .rpc_argp = &setclientid, |
| 3507 | .rpc_resp = clp, | 3546 | .rpc_resp = res, |
| 3508 | .rpc_cred = cred, | 3547 | .rpc_cred = cred, |
| 3509 | }; | 3548 | }; |
| 3510 | __be32 *p; | 3549 | __be32 *p; |
| @@ -3547,12 +3586,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po | |||
| 3547 | return status; | 3586 | return status; |
| 3548 | } | 3587 | } |
| 3549 | 3588 | ||
| 3550 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3589 | static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
| 3590 | struct nfs4_setclientid_res *arg, | ||
| 3591 | struct rpc_cred *cred) | ||
| 3551 | { | 3592 | { |
| 3552 | struct nfs_fsinfo fsinfo; | 3593 | struct nfs_fsinfo fsinfo; |
| 3553 | struct rpc_message msg = { | 3594 | struct rpc_message msg = { |
| 3554 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], | 3595 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM], |
| 3555 | .rpc_argp = clp, | 3596 | .rpc_argp = arg, |
| 3556 | .rpc_resp = &fsinfo, | 3597 | .rpc_resp = &fsinfo, |
| 3557 | .rpc_cred = cred, | 3598 | .rpc_cred = cred, |
| 3558 | }; | 3599 | }; |
| @@ -3570,12 +3611,14 @@ static int _nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cre | |||
| 3570 | return status; | 3611 | return status; |
| 3571 | } | 3612 | } |
| 3572 | 3613 | ||
| 3573 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | 3614 | int nfs4_proc_setclientid_confirm(struct nfs_client *clp, |
| 3615 | struct nfs4_setclientid_res *arg, | ||
| 3616 | struct rpc_cred *cred) | ||
| 3574 | { | 3617 | { |
| 3575 | long timeout = 0; | 3618 | long timeout = 0; |
| 3576 | int err; | 3619 | int err; |
| 3577 | do { | 3620 | do { |
| 3578 | err = _nfs4_proc_setclientid_confirm(clp, cred); | 3621 | err = _nfs4_proc_setclientid_confirm(clp, arg, cred); |
| 3579 | switch (err) { | 3622 | switch (err) { |
| 3580 | case 0: | 3623 | case 0: |
| 3581 | return err; | 3624 | return err; |
| @@ -3603,8 +3646,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 3603 | { | 3646 | { |
| 3604 | struct nfs4_delegreturndata *data = calldata; | 3647 | struct nfs4_delegreturndata *data = calldata; |
| 3605 | 3648 | ||
| 3606 | nfs4_sequence_done(data->res.server, &data->res.seq_res, | 3649 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 3607 | task->tk_status); | 3650 | return; |
| 3608 | 3651 | ||
| 3609 | switch (task->tk_status) { | 3652 | switch (task->tk_status) { |
| 3610 | case -NFS4ERR_STALE_STATEID: | 3653 | case -NFS4ERR_STALE_STATEID: |
| @@ -3634,7 +3677,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
| 3634 | 3677 | ||
| 3635 | d_data = (struct nfs4_delegreturndata *)data; | 3678 | d_data = (struct nfs4_delegreturndata *)data; |
| 3636 | 3679 | ||
| 3637 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | 3680 | if (nfs4_setup_sequence(d_data->res.server, |
| 3638 | &d_data->args.seq_args, | 3681 | &d_data->args.seq_args, |
| 3639 | &d_data->res.seq_res, 1, task)) | 3682 | &d_data->res.seq_res, 1, task)) |
| 3640 | return; | 3683 | return; |
| @@ -3667,7 +3710,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 3667 | }; | 3710 | }; |
| 3668 | int status = 0; | 3711 | int status = 0; |
| 3669 | 3712 | ||
| 3670 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 3713 | data = kzalloc(sizeof(*data), GFP_NOFS); |
| 3671 | if (data == NULL) | 3714 | if (data == NULL) |
| 3672 | return -ENOMEM; | 3715 | return -ENOMEM; |
| 3673 | data->args.fhandle = &data->fh; | 3716 | data->args.fhandle = &data->fh; |
| @@ -3823,7 +3866,7 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
| 3823 | struct nfs4_unlockdata *p; | 3866 | struct nfs4_unlockdata *p; |
| 3824 | struct inode *inode = lsp->ls_state->inode; | 3867 | struct inode *inode = lsp->ls_state->inode; |
| 3825 | 3868 | ||
| 3826 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 3869 | p = kzalloc(sizeof(*p), GFP_NOFS); |
| 3827 | if (p == NULL) | 3870 | if (p == NULL) |
| 3828 | return NULL; | 3871 | return NULL; |
| 3829 | p->arg.fh = NFS_FH(inode); | 3872 | p->arg.fh = NFS_FH(inode); |
| @@ -3854,9 +3897,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
| 3854 | { | 3897 | { |
| 3855 | struct nfs4_unlockdata *calldata = data; | 3898 | struct nfs4_unlockdata *calldata = data; |
| 3856 | 3899 | ||
| 3857 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | 3900 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
| 3858 | task->tk_status); | ||
| 3859 | if (RPC_ASSASSINATED(task)) | ||
| 3860 | return; | 3901 | return; |
| 3861 | switch (task->tk_status) { | 3902 | switch (task->tk_status) { |
| 3862 | case 0: | 3903 | case 0: |
| @@ -3889,7 +3930,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
| 3889 | return; | 3930 | return; |
| 3890 | } | 3931 | } |
| 3891 | calldata->timestamp = jiffies; | 3932 | calldata->timestamp = jiffies; |
| 3892 | if (nfs4_setup_sequence(calldata->server->nfs_client, | 3933 | if (nfs4_setup_sequence(calldata->server, |
| 3893 | &calldata->arg.seq_args, | 3934 | &calldata->arg.seq_args, |
| 3894 | &calldata->res.seq_res, 1, task)) | 3935 | &calldata->res.seq_res, 1, task)) |
| 3895 | return; | 3936 | return; |
| @@ -3961,7 +4002,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * | |||
| 3961 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) | 4002 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) |
| 3962 | goto out; | 4003 | goto out; |
| 3963 | lsp = request->fl_u.nfs4_fl.owner; | 4004 | lsp = request->fl_u.nfs4_fl.owner; |
| 3964 | seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4005 | seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL); |
| 3965 | status = -ENOMEM; | 4006 | status = -ENOMEM; |
| 3966 | if (seqid == NULL) | 4007 | if (seqid == NULL) |
| 3967 | goto out; | 4008 | goto out; |
| @@ -3989,22 +4030,23 @@ struct nfs4_lockdata { | |||
| 3989 | }; | 4030 | }; |
| 3990 | 4031 | ||
| 3991 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 4032 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
| 3992 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp) | 4033 | struct nfs_open_context *ctx, struct nfs4_lock_state *lsp, |
| 4034 | gfp_t gfp_mask) | ||
| 3993 | { | 4035 | { |
| 3994 | struct nfs4_lockdata *p; | 4036 | struct nfs4_lockdata *p; |
| 3995 | struct inode *inode = lsp->ls_state->inode; | 4037 | struct inode *inode = lsp->ls_state->inode; |
| 3996 | struct nfs_server *server = NFS_SERVER(inode); | 4038 | struct nfs_server *server = NFS_SERVER(inode); |
| 3997 | 4039 | ||
| 3998 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 4040 | p = kzalloc(sizeof(*p), gfp_mask); |
| 3999 | if (p == NULL) | 4041 | if (p == NULL) |
| 4000 | return NULL; | 4042 | return NULL; |
| 4001 | 4043 | ||
| 4002 | p->arg.fh = NFS_FH(inode); | 4044 | p->arg.fh = NFS_FH(inode); |
| 4003 | p->arg.fl = &p->fl; | 4045 | p->arg.fl = &p->fl; |
| 4004 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid); | 4046 | p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask); |
| 4005 | if (p->arg.open_seqid == NULL) | 4047 | if (p->arg.open_seqid == NULL) |
| 4006 | goto out_free; | 4048 | goto out_free; |
| 4007 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid); | 4049 | p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask); |
| 4008 | if (p->arg.lock_seqid == NULL) | 4050 | if (p->arg.lock_seqid == NULL) |
| 4009 | goto out_free_seqid; | 4051 | goto out_free_seqid; |
| 4010 | p->arg.lock_stateid = &lsp->ls_stateid; | 4052 | p->arg.lock_stateid = &lsp->ls_stateid; |
| @@ -4043,7 +4085,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
| 4043 | } else | 4085 | } else |
| 4044 | data->arg.new_lock_owner = 0; | 4086 | data->arg.new_lock_owner = 0; |
| 4045 | data->timestamp = jiffies; | 4087 | data->timestamp = jiffies; |
| 4046 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | 4088 | if (nfs4_setup_sequence(data->server, |
| 4089 | &data->arg.seq_args, | ||
| 4047 | &data->res.seq_res, 1, task)) | 4090 | &data->res.seq_res, 1, task)) |
| 4048 | return; | 4091 | return; |
| 4049 | rpc_call_start(task); | 4092 | rpc_call_start(task); |
| @@ -4062,12 +4105,10 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
| 4062 | 4105 | ||
| 4063 | dprintk("%s: begin!\n", __func__); | 4106 | dprintk("%s: begin!\n", __func__); |
| 4064 | 4107 | ||
| 4065 | nfs4_sequence_done(data->server, &data->res.seq_res, | 4108 | if (!nfs4_sequence_done(task, &data->res.seq_res)) |
| 4066 | task->tk_status); | 4109 | return; |
| 4067 | 4110 | ||
| 4068 | data->rpc_status = task->tk_status; | 4111 | data->rpc_status = task->tk_status; |
| 4069 | if (RPC_ASSASSINATED(task)) | ||
| 4070 | goto out; | ||
| 4071 | if (data->arg.new_lock_owner != 0) { | 4112 | if (data->arg.new_lock_owner != 0) { |
| 4072 | if (data->rpc_status == 0) | 4113 | if (data->rpc_status == 0) |
| 4073 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); | 4114 | nfs_confirm_seqid(&data->lsp->ls_seqid, 0); |
| @@ -4158,7 +4199,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
| 4158 | 4199 | ||
| 4159 | dprintk("%s: begin!\n", __func__); | 4200 | dprintk("%s: begin!\n", __func__); |
| 4160 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), | 4201 | data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file), |
| 4161 | fl->fl_u.nfs4_fl.owner); | 4202 | fl->fl_u.nfs4_fl.owner, |
| 4203 | recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS); | ||
| 4162 | if (data == NULL) | 4204 | if (data == NULL) |
| 4163 | return -ENOMEM; | 4205 | return -ENOMEM; |
| 4164 | if (IS_SETLKW(cmd)) | 4206 | if (IS_SETLKW(cmd)) |
| @@ -4384,6 +4426,34 @@ out: | |||
| 4384 | return err; | 4426 | return err; |
| 4385 | } | 4427 | } |
| 4386 | 4428 | ||
| 4429 | static void nfs4_release_lockowner_release(void *calldata) | ||
| 4430 | { | ||
| 4431 | kfree(calldata); | ||
| 4432 | } | ||
| 4433 | |||
| 4434 | const struct rpc_call_ops nfs4_release_lockowner_ops = { | ||
| 4435 | .rpc_release = nfs4_release_lockowner_release, | ||
| 4436 | }; | ||
| 4437 | |||
| 4438 | void nfs4_release_lockowner(const struct nfs4_lock_state *lsp) | ||
| 4439 | { | ||
| 4440 | struct nfs_server *server = lsp->ls_state->owner->so_server; | ||
| 4441 | struct nfs_release_lockowner_args *args; | ||
| 4442 | struct rpc_message msg = { | ||
| 4443 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER], | ||
| 4444 | }; | ||
| 4445 | |||
| 4446 | if (server->nfs_client->cl_mvops->minor_version != 0) | ||
| 4447 | return; | ||
| 4448 | args = kmalloc(sizeof(*args), GFP_NOFS); | ||
| 4449 | if (!args) | ||
| 4450 | return; | ||
| 4451 | args->lock_owner.clientid = server->nfs_client->cl_clientid; | ||
| 4452 | args->lock_owner.id = lsp->ls_id.id; | ||
| 4453 | msg.rpc_argp = args; | ||
| 4454 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args); | ||
| 4455 | } | ||
| 4456 | |||
| 4387 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 4457 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
| 4388 | 4458 | ||
| 4389 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | 4459 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, |
| @@ -4571,7 +4641,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
| 4571 | (struct nfs4_get_lease_time_data *)calldata; | 4641 | (struct nfs4_get_lease_time_data *)calldata; |
| 4572 | 4642 | ||
| 4573 | dprintk("--> %s\n", __func__); | 4643 | dprintk("--> %s\n", __func__); |
| 4574 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | 4644 | if (!nfs41_sequence_done(task, &data->res->lr_seq_res)) |
| 4645 | return; | ||
| 4575 | switch (task->tk_status) { | 4646 | switch (task->tk_status) { |
| 4576 | case -NFS4ERR_DELAY: | 4647 | case -NFS4ERR_DELAY: |
| 4577 | case -NFS4ERR_GRACE: | 4648 | case -NFS4ERR_GRACE: |
| @@ -4647,7 +4718,7 @@ static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, | |||
| 4647 | if (max_reqs != tbl->max_slots) { | 4718 | if (max_reqs != tbl->max_slots) { |
| 4648 | ret = -ENOMEM; | 4719 | ret = -ENOMEM; |
| 4649 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), | 4720 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
| 4650 | GFP_KERNEL); | 4721 | GFP_NOFS); |
| 4651 | if (!new) | 4722 | if (!new) |
| 4652 | goto out; | 4723 | goto out; |
| 4653 | ret = 0; | 4724 | ret = 0; |
| @@ -4712,7 +4783,7 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
| 4712 | 4783 | ||
| 4713 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | 4784 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); |
| 4714 | 4785 | ||
| 4715 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4786 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS); |
| 4716 | if (!slot) | 4787 | if (!slot) |
| 4717 | goto out; | 4788 | goto out; |
| 4718 | ret = 0; | 4789 | ret = 0; |
| @@ -4761,17 +4832,10 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 4761 | struct nfs4_session *session; | 4832 | struct nfs4_session *session; |
| 4762 | struct nfs4_slot_table *tbl; | 4833 | struct nfs4_slot_table *tbl; |
| 4763 | 4834 | ||
| 4764 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | 4835 | session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS); |
| 4765 | if (!session) | 4836 | if (!session) |
| 4766 | return NULL; | 4837 | return NULL; |
| 4767 | 4838 | ||
| 4768 | /* | ||
| 4769 | * The create session reply races with the server back | ||
| 4770 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
| 4771 | * so that the client back channel can find the | ||
| 4772 | * nfs_client struct | ||
| 4773 | */ | ||
| 4774 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
| 4775 | init_completion(&session->complete); | 4839 | init_completion(&session->complete); |
| 4776 | 4840 | ||
| 4777 | tbl = &session->fc_slot_table; | 4841 | tbl = &session->fc_slot_table; |
| @@ -4784,6 +4848,8 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
| 4784 | spin_lock_init(&tbl->slot_tbl_lock); | 4848 | spin_lock_init(&tbl->slot_tbl_lock); |
| 4785 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4849 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
| 4786 | 4850 | ||
| 4851 | session->session_state = 1<<NFS4_SESSION_INITING; | ||
| 4852 | |||
| 4787 | session->clp = clp; | 4853 | session->clp = clp; |
| 4788 | return session; | 4854 | return session; |
| 4789 | } | 4855 | } |
| @@ -5000,6 +5066,10 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5000 | if (!nfs4_has_session(clp)) | 5066 | if (!nfs4_has_session(clp)) |
| 5001 | return 0; | 5067 | return 0; |
| 5002 | 5068 | ||
| 5069 | session = clp->cl_session; | ||
| 5070 | if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) | ||
| 5071 | return 0; | ||
| 5072 | |||
| 5003 | rsize = server->rsize; | 5073 | rsize = server->rsize; |
| 5004 | if (rsize == 0) | 5074 | if (rsize == 0) |
| 5005 | rsize = NFS_MAX_FILE_IO_SIZE; | 5075 | rsize = NFS_MAX_FILE_IO_SIZE; |
| @@ -5007,7 +5077,6 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5007 | if (wsize == 0) | 5077 | if (wsize == 0) |
| 5008 | wsize = NFS_MAX_FILE_IO_SIZE; | 5078 | wsize = NFS_MAX_FILE_IO_SIZE; |
| 5009 | 5079 | ||
| 5010 | session = clp->cl_session; | ||
| 5011 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | 5080 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; |
| 5012 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | 5081 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; |
| 5013 | 5082 | ||
| @@ -5020,69 +5089,70 @@ int nfs4_init_session(struct nfs_server *server) | |||
| 5020 | /* | 5089 | /* |
| 5021 | * Renew the cl_session lease. | 5090 | * Renew the cl_session lease. |
| 5022 | */ | 5091 | */ |
| 5023 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | 5092 | struct nfs4_sequence_data { |
| 5024 | { | 5093 | struct nfs_client *clp; |
| 5025 | struct nfs4_sequence_args args; | 5094 | struct nfs4_sequence_args args; |
| 5026 | struct nfs4_sequence_res res; | 5095 | struct nfs4_sequence_res res; |
| 5027 | 5096 | }; | |
| 5028 | struct rpc_message msg = { | ||
| 5029 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
| 5030 | .rpc_argp = &args, | ||
| 5031 | .rpc_resp = &res, | ||
| 5032 | .rpc_cred = cred, | ||
| 5033 | }; | ||
| 5034 | |||
| 5035 | args.sa_cache_this = 0; | ||
| 5036 | |||
| 5037 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
| 5038 | &res, args.sa_cache_this, 1); | ||
| 5039 | } | ||
| 5040 | 5097 | ||
| 5041 | static void nfs41_sequence_release(void *data) | 5098 | static void nfs41_sequence_release(void *data) |
| 5042 | { | 5099 | { |
| 5043 | struct nfs_client *clp = (struct nfs_client *)data; | 5100 | struct nfs4_sequence_data *calldata = data; |
| 5101 | struct nfs_client *clp = calldata->clp; | ||
| 5044 | 5102 | ||
| 5045 | if (atomic_read(&clp->cl_count) > 1) | 5103 | if (atomic_read(&clp->cl_count) > 1) |
| 5046 | nfs4_schedule_state_renewal(clp); | 5104 | nfs4_schedule_state_renewal(clp); |
| 5047 | nfs_put_client(clp); | 5105 | nfs_put_client(clp); |
| 5106 | kfree(calldata); | ||
| 5107 | } | ||
| 5108 | |||
| 5109 | static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
| 5110 | { | ||
| 5111 | switch(task->tk_status) { | ||
| 5112 | case -NFS4ERR_DELAY: | ||
| 5113 | case -EKEYEXPIRED: | ||
| 5114 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 5115 | return -EAGAIN; | ||
| 5116 | default: | ||
| 5117 | nfs4_schedule_state_recovery(clp); | ||
| 5118 | } | ||
| 5119 | return 0; | ||
| 5048 | } | 5120 | } |
| 5049 | 5121 | ||
| 5050 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5122 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
| 5051 | { | 5123 | { |
| 5052 | struct nfs_client *clp = (struct nfs_client *)data; | 5124 | struct nfs4_sequence_data *calldata = data; |
| 5125 | struct nfs_client *clp = calldata->clp; | ||
| 5053 | 5126 | ||
| 5054 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | 5127 | if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp)) |
| 5128 | return; | ||
| 5055 | 5129 | ||
| 5056 | if (task->tk_status < 0) { | 5130 | if (task->tk_status < 0) { |
| 5057 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5131 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
| 5058 | if (atomic_read(&clp->cl_count) == 1) | 5132 | if (atomic_read(&clp->cl_count) == 1) |
| 5059 | goto out; | 5133 | goto out; |
| 5060 | 5134 | ||
| 5061 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5135 | if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) { |
| 5062 | == -EAGAIN) { | 5136 | rpc_restart_call_prepare(task); |
| 5063 | nfs_restart_rpc(task, clp); | ||
| 5064 | return; | 5137 | return; |
| 5065 | } | 5138 | } |
| 5066 | } | 5139 | } |
| 5067 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5140 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
| 5068 | out: | 5141 | out: |
| 5069 | kfree(task->tk_msg.rpc_argp); | ||
| 5070 | kfree(task->tk_msg.rpc_resp); | ||
| 5071 | |||
| 5072 | dprintk("<-- %s\n", __func__); | 5142 | dprintk("<-- %s\n", __func__); |
| 5073 | } | 5143 | } |
| 5074 | 5144 | ||
| 5075 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | 5145 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) |
| 5076 | { | 5146 | { |
| 5077 | struct nfs_client *clp; | 5147 | struct nfs4_sequence_data *calldata = data; |
| 5148 | struct nfs_client *clp = calldata->clp; | ||
| 5078 | struct nfs4_sequence_args *args; | 5149 | struct nfs4_sequence_args *args; |
| 5079 | struct nfs4_sequence_res *res; | 5150 | struct nfs4_sequence_res *res; |
| 5080 | 5151 | ||
| 5081 | clp = (struct nfs_client *)data; | ||
| 5082 | args = task->tk_msg.rpc_argp; | 5152 | args = task->tk_msg.rpc_argp; |
| 5083 | res = task->tk_msg.rpc_resp; | 5153 | res = task->tk_msg.rpc_resp; |
| 5084 | 5154 | ||
| 5085 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | 5155 | if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task)) |
| 5086 | return; | 5156 | return; |
| 5087 | rpc_call_start(task); | 5157 | rpc_call_start(task); |
| 5088 | } | 5158 | } |
| @@ -5093,32 +5163,67 @@ static const struct rpc_call_ops nfs41_sequence_ops = { | |||
| 5093 | .rpc_release = nfs41_sequence_release, | 5163 | .rpc_release = nfs41_sequence_release, |
| 5094 | }; | 5164 | }; |
| 5095 | 5165 | ||
| 5096 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5166 | static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) |
| 5097 | struct rpc_cred *cred) | ||
| 5098 | { | 5167 | { |
| 5099 | struct nfs4_sequence_args *args; | 5168 | struct nfs4_sequence_data *calldata; |
| 5100 | struct nfs4_sequence_res *res; | ||
| 5101 | struct rpc_message msg = { | 5169 | struct rpc_message msg = { |
| 5102 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | 5170 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], |
| 5103 | .rpc_cred = cred, | 5171 | .rpc_cred = cred, |
| 5104 | }; | 5172 | }; |
| 5173 | struct rpc_task_setup task_setup_data = { | ||
| 5174 | .rpc_client = clp->cl_rpcclient, | ||
| 5175 | .rpc_message = &msg, | ||
| 5176 | .callback_ops = &nfs41_sequence_ops, | ||
| 5177 | .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT, | ||
| 5178 | }; | ||
| 5105 | 5179 | ||
| 5106 | if (!atomic_inc_not_zero(&clp->cl_count)) | 5180 | if (!atomic_inc_not_zero(&clp->cl_count)) |
| 5107 | return -EIO; | 5181 | return ERR_PTR(-EIO); |
| 5108 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5182 | calldata = kmalloc(sizeof(*calldata), GFP_NOFS); |
| 5109 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5183 | if (calldata == NULL) { |
| 5110 | if (!args || !res) { | ||
| 5111 | kfree(args); | ||
| 5112 | kfree(res); | ||
| 5113 | nfs_put_client(clp); | 5184 | nfs_put_client(clp); |
| 5114 | return -ENOMEM; | 5185 | return ERR_PTR(-ENOMEM); |
| 5115 | } | 5186 | } |
| 5116 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5187 | calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
| 5117 | msg.rpc_argp = args; | 5188 | msg.rpc_argp = &calldata->args; |
| 5118 | msg.rpc_resp = res; | 5189 | msg.rpc_resp = &calldata->res; |
| 5190 | calldata->clp = clp; | ||
| 5191 | task_setup_data.callback_data = calldata; | ||
| 5119 | 5192 | ||
| 5120 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 5193 | return rpc_run_task(&task_setup_data); |
| 5121 | &nfs41_sequence_ops, (void *)clp); | 5194 | } |
| 5195 | |||
| 5196 | static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 5197 | { | ||
| 5198 | struct rpc_task *task; | ||
| 5199 | int ret = 0; | ||
| 5200 | |||
| 5201 | task = _nfs41_proc_sequence(clp, cred); | ||
| 5202 | if (IS_ERR(task)) | ||
| 5203 | ret = PTR_ERR(task); | ||
| 5204 | else | ||
| 5205 | rpc_put_task(task); | ||
| 5206 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
| 5207 | return ret; | ||
| 5208 | } | ||
| 5209 | |||
| 5210 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
| 5211 | { | ||
| 5212 | struct rpc_task *task; | ||
| 5213 | int ret; | ||
| 5214 | |||
| 5215 | task = _nfs41_proc_sequence(clp, cred); | ||
| 5216 | if (IS_ERR(task)) { | ||
| 5217 | ret = PTR_ERR(task); | ||
| 5218 | goto out; | ||
| 5219 | } | ||
| 5220 | ret = rpc_wait_for_completion_task(task); | ||
| 5221 | if (!ret) | ||
| 5222 | ret = task->tk_status; | ||
| 5223 | rpc_put_task(task); | ||
| 5224 | out: | ||
| 5225 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
| 5226 | return ret; | ||
| 5122 | } | 5227 | } |
| 5123 | 5228 | ||
| 5124 | struct nfs4_reclaim_complete_data { | 5229 | struct nfs4_reclaim_complete_data { |
| @@ -5132,13 +5237,31 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | |||
| 5132 | struct nfs4_reclaim_complete_data *calldata = data; | 5237 | struct nfs4_reclaim_complete_data *calldata = data; |
| 5133 | 5238 | ||
| 5134 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | 5239 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); |
| 5135 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | 5240 | if (nfs41_setup_sequence(calldata->clp->cl_session, |
| 5241 | &calldata->arg.seq_args, | ||
| 5136 | &calldata->res.seq_res, 0, task)) | 5242 | &calldata->res.seq_res, 0, task)) |
| 5137 | return; | 5243 | return; |
| 5138 | 5244 | ||
| 5139 | rpc_call_start(task); | 5245 | rpc_call_start(task); |
| 5140 | } | 5246 | } |
| 5141 | 5247 | ||
| 5248 | static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp) | ||
| 5249 | { | ||
| 5250 | switch(task->tk_status) { | ||
| 5251 | case 0: | ||
| 5252 | case -NFS4ERR_COMPLETE_ALREADY: | ||
| 5253 | case -NFS4ERR_WRONG_CRED: /* What to do here? */ | ||
| 5254 | break; | ||
| 5255 | case -NFS4ERR_DELAY: | ||
| 5256 | case -EKEYEXPIRED: | ||
| 5257 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | ||
| 5258 | return -EAGAIN; | ||
| 5259 | default: | ||
| 5260 | nfs4_schedule_state_recovery(clp); | ||
| 5261 | } | ||
| 5262 | return 0; | ||
| 5263 | } | ||
| 5264 | |||
| 5142 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | 5265 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) |
| 5143 | { | 5266 | { |
| 5144 | struct nfs4_reclaim_complete_data *calldata = data; | 5267 | struct nfs4_reclaim_complete_data *calldata = data; |
| @@ -5146,32 +5269,13 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | |||
| 5146 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | 5269 | struct nfs4_sequence_res *res = &calldata->res.seq_res; |
| 5147 | 5270 | ||
| 5148 | dprintk("--> %s\n", __func__); | 5271 | dprintk("--> %s\n", __func__); |
| 5149 | nfs41_sequence_done(clp, res, task->tk_status); | 5272 | if (!nfs41_sequence_done(task, res)) |
| 5150 | switch (task->tk_status) { | 5273 | return; |
| 5151 | case 0: | ||
| 5152 | case -NFS4ERR_COMPLETE_ALREADY: | ||
| 5153 | break; | ||
| 5154 | case -NFS4ERR_BADSESSION: | ||
| 5155 | case -NFS4ERR_DEADSESSION: | ||
| 5156 | /* | ||
| 5157 | * Handle the session error, but do not retry the operation, as | ||
| 5158 | * we have no way of telling whether the clientid had to be | ||
| 5159 | * reset before we got our reply. If reset, a new wave of | ||
| 5160 | * reclaim operations will follow, containing their own reclaim | ||
| 5161 | * complete. We don't want our retry to get on the way of | ||
| 5162 | * recovery by incorrectly indicating to the server that we're | ||
| 5163 | * done reclaiming state since the process had to be restarted. | ||
| 5164 | */ | ||
| 5165 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
| 5166 | break; | ||
| 5167 | default: | ||
| 5168 | if (_nfs4_async_handle_error( | ||
| 5169 | task, NULL, clp, NULL) == -EAGAIN) { | ||
| 5170 | rpc_restart_call_prepare(task); | ||
| 5171 | return; | ||
| 5172 | } | ||
| 5173 | } | ||
| 5174 | 5274 | ||
| 5275 | if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) { | ||
| 5276 | rpc_restart_call_prepare(task); | ||
| 5277 | return; | ||
| 5278 | } | ||
| 5175 | dprintk("<-- %s\n", __func__); | 5279 | dprintk("<-- %s\n", __func__); |
| 5176 | } | 5280 | } |
| 5177 | 5281 | ||
| @@ -5207,7 +5311,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | |||
| 5207 | int status = -ENOMEM; | 5311 | int status = -ENOMEM; |
| 5208 | 5312 | ||
| 5209 | dprintk("--> %s\n", __func__); | 5313 | dprintk("--> %s\n", __func__); |
| 5210 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | 5314 | calldata = kzalloc(sizeof(*calldata), GFP_NOFS); |
| 5211 | if (calldata == NULL) | 5315 | if (calldata == NULL) |
| 5212 | goto out; | 5316 | goto out; |
| 5213 | calldata->clp = clp; | 5317 | calldata->clp = clp; |
| @@ -5285,28 +5389,30 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | |||
| 5285 | }; | 5389 | }; |
| 5286 | #endif | 5390 | #endif |
| 5287 | 5391 | ||
| 5288 | /* | 5392 | static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { |
| 5289 | * Per minor version reboot and network partition recovery ops | 5393 | .minor_version = 0, |
| 5290 | */ | 5394 | .call_sync = _nfs4_call_sync, |
| 5291 | 5395 | .validate_stateid = nfs4_validate_delegation_stateid, | |
| 5292 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | 5396 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
| 5293 | &nfs40_reboot_recovery_ops, | 5397 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
| 5294 | #if defined(CONFIG_NFS_V4_1) | 5398 | .state_renewal_ops = &nfs40_state_renewal_ops, |
| 5295 | &nfs41_reboot_recovery_ops, | ||
| 5296 | #endif | ||
| 5297 | }; | 5399 | }; |
| 5298 | 5400 | ||
| 5299 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
| 5300 | &nfs40_nograce_recovery_ops, | ||
| 5301 | #if defined(CONFIG_NFS_V4_1) | 5401 | #if defined(CONFIG_NFS_V4_1) |
| 5302 | &nfs41_nograce_recovery_ops, | 5402 | static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { |
| 5303 | #endif | 5403 | .minor_version = 1, |
| 5404 | .call_sync = _nfs4_call_sync_session, | ||
| 5405 | .validate_stateid = nfs41_validate_delegation_stateid, | ||
| 5406 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | ||
| 5407 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | ||
| 5408 | .state_renewal_ops = &nfs41_state_renewal_ops, | ||
| 5304 | }; | 5409 | }; |
| 5410 | #endif | ||
| 5305 | 5411 | ||
| 5306 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | 5412 | const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = { |
| 5307 | &nfs40_state_renewal_ops, | 5413 | [0] = &nfs_v4_0_minor_ops, |
| 5308 | #if defined(CONFIG_NFS_V4_1) | 5414 | #if defined(CONFIG_NFS_V4_1) |
| 5309 | &nfs41_state_renewal_ops, | 5415 | [1] = &nfs_v4_1_minor_ops, |
| 5310 | #endif | 5416 | #endif |
| 5311 | }; | 5417 | }; |
| 5312 | 5418 | ||
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index d87f10327b72..72b6c580af13 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
| @@ -54,14 +54,14 @@ | |||
| 54 | void | 54 | void |
| 55 | nfs4_renew_state(struct work_struct *work) | 55 | nfs4_renew_state(struct work_struct *work) |
| 56 | { | 56 | { |
| 57 | struct nfs4_state_maintenance_ops *ops; | 57 | const struct nfs4_state_maintenance_ops *ops; |
| 58 | struct nfs_client *clp = | 58 | struct nfs_client *clp = |
| 59 | container_of(work, struct nfs_client, cl_renewd.work); | 59 | container_of(work, struct nfs_client, cl_renewd.work); |
| 60 | struct rpc_cred *cred; | 60 | struct rpc_cred *cred; |
| 61 | long lease; | 61 | long lease; |
| 62 | unsigned long last, now; | 62 | unsigned long last, now; |
| 63 | 63 | ||
| 64 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | 64 | ops = clp->cl_mvops->state_renewal_ops; |
| 65 | dprintk("%s: start\n", __func__); | 65 | dprintk("%s: start\n", __func__); |
| 66 | /* Are there any active superblocks? */ | 66 | /* Are there any active superblocks? */ |
| 67 | if (list_empty(&clp->cl_superblocks)) | 67 | if (list_empty(&clp->cl_superblocks)) |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 6c5ed51f105e..3e2f19b04c06 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 | ||
| @@ -140,7 +145,9 @@ static void nfs4_end_drain_session(struct nfs_client *clp) | |||
| 140 | struct nfs4_session *ses = clp->cl_session; | 145 | struct nfs4_session *ses = clp->cl_session; |
| 141 | int max_slots; | 146 | int max_slots; |
| 142 | 147 | ||
| 143 | if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) { | 148 | if (ses == NULL) |
| 149 | return; | ||
| 150 | if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) { | ||
| 144 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); | 151 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); |
| 145 | max_slots = ses->fc_slot_table.max_slots; | 152 | max_slots = ses->fc_slot_table.max_slots; |
| 146 | while (max_slots--) { | 153 | while (max_slots--) { |
| @@ -162,7 +169,7 @@ static int nfs4_begin_drain_session(struct nfs_client *clp) | |||
| 162 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; | 169 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; |
| 163 | 170 | ||
| 164 | spin_lock(&tbl->slot_tbl_lock); | 171 | spin_lock(&tbl->slot_tbl_lock); |
| 165 | set_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state); | 172 | set_bit(NFS4_SESSION_DRAINING, &ses->session_state); |
| 166 | if (tbl->highest_used_slotid != -1) { | 173 | if (tbl->highest_used_slotid != -1) { |
| 167 | INIT_COMPLETION(ses->complete); | 174 | INIT_COMPLETION(ses->complete); |
| 168 | spin_unlock(&tbl->slot_tbl_lock); | 175 | spin_unlock(&tbl->slot_tbl_lock); |
| @@ -361,12 +368,11 @@ nfs4_alloc_state_owner(void) | |||
| 361 | { | 368 | { |
| 362 | struct nfs4_state_owner *sp; | 369 | struct nfs4_state_owner *sp; |
| 363 | 370 | ||
| 364 | sp = kzalloc(sizeof(*sp),GFP_KERNEL); | 371 | sp = kzalloc(sizeof(*sp),GFP_NOFS); |
| 365 | if (!sp) | 372 | if (!sp) |
| 366 | return NULL; | 373 | return NULL; |
| 367 | spin_lock_init(&sp->so_lock); | 374 | spin_lock_init(&sp->so_lock); |
| 368 | INIT_LIST_HEAD(&sp->so_states); | 375 | INIT_LIST_HEAD(&sp->so_states); |
| 369 | INIT_LIST_HEAD(&sp->so_delegations); | ||
| 370 | rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); | 376 | rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); |
| 371 | sp->so_seqid.sequence = &sp->so_sequence; | 377 | sp->so_seqid.sequence = &sp->so_sequence; |
| 372 | spin_lock_init(&sp->so_sequence.lock); | 378 | spin_lock_init(&sp->so_sequence.lock); |
| @@ -379,7 +385,7 @@ static void | |||
| 379 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) | 385 | nfs4_drop_state_owner(struct nfs4_state_owner *sp) |
| 380 | { | 386 | { |
| 381 | if (!RB_EMPTY_NODE(&sp->so_client_node)) { | 387 | if (!RB_EMPTY_NODE(&sp->so_client_node)) { |
| 382 | struct nfs_client *clp = sp->so_client; | 388 | struct nfs_client *clp = sp->so_server->nfs_client; |
| 383 | 389 | ||
| 384 | spin_lock(&clp->cl_lock); | 390 | spin_lock(&clp->cl_lock); |
| 385 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); | 391 | rb_erase(&sp->so_client_node, &clp->cl_state_owners); |
| @@ -401,7 +407,6 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 401 | new = nfs4_alloc_state_owner(); | 407 | new = nfs4_alloc_state_owner(); |
| 402 | if (new == NULL) | 408 | if (new == NULL) |
| 403 | return NULL; | 409 | return NULL; |
| 404 | new->so_client = clp; | ||
| 405 | new->so_server = server; | 410 | new->so_server = server; |
| 406 | new->so_cred = cred; | 411 | new->so_cred = cred; |
| 407 | spin_lock(&clp->cl_lock); | 412 | spin_lock(&clp->cl_lock); |
| @@ -418,7 +423,7 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct | |||
| 418 | 423 | ||
| 419 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) | 424 | void nfs4_put_state_owner(struct nfs4_state_owner *sp) |
| 420 | { | 425 | { |
| 421 | struct nfs_client *clp = sp->so_client; | 426 | struct nfs_client *clp = sp->so_server->nfs_client; |
| 422 | struct rpc_cred *cred = sp->so_cred; | 427 | struct rpc_cred *cred = sp->so_cred; |
| 423 | 428 | ||
| 424 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock)) | 429 | if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_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 | /* |
| @@ -596,12 +602,21 @@ void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode) | |||
| 596 | * that is compatible with current->files | 602 | * that is compatible with current->files |
| 597 | */ | 603 | */ |
| 598 | static struct nfs4_lock_state * | 604 | static struct nfs4_lock_state * |
| 599 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 605 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) |
| 600 | { | 606 | { |
| 601 | struct nfs4_lock_state *pos; | 607 | struct nfs4_lock_state *pos; |
| 602 | list_for_each_entry(pos, &state->lock_states, ls_locks) { | 608 | list_for_each_entry(pos, &state->lock_states, ls_locks) { |
| 603 | if (pos->ls_owner != fl_owner) | 609 | if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type) |
| 604 | continue; | 610 | continue; |
| 611 | switch (pos->ls_owner.lo_type) { | ||
| 612 | case NFS4_POSIX_LOCK_TYPE: | ||
| 613 | if (pos->ls_owner.lo_u.posix_owner != fl_owner) | ||
| 614 | continue; | ||
| 615 | break; | ||
| 616 | case NFS4_FLOCK_LOCK_TYPE: | ||
| 617 | if (pos->ls_owner.lo_u.flock_owner != fl_pid) | ||
| 618 | continue; | ||
| 619 | } | ||
| 605 | atomic_inc(&pos->ls_count); | 620 | atomic_inc(&pos->ls_count); |
| 606 | return pos; | 621 | return pos; |
| 607 | } | 622 | } |
| @@ -613,12 +628,12 @@ __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | |||
| 613 | * exists, return an uninitialized one. | 628 | * exists, return an uninitialized one. |
| 614 | * | 629 | * |
| 615 | */ | 630 | */ |
| 616 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) | 631 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) |
| 617 | { | 632 | { |
| 618 | struct nfs4_lock_state *lsp; | 633 | struct nfs4_lock_state *lsp; |
| 619 | struct nfs_client *clp = state->owner->so_client; | 634 | struct nfs_client *clp = state->owner->so_server->nfs_client; |
| 620 | 635 | ||
| 621 | lsp = kzalloc(sizeof(*lsp), GFP_KERNEL); | 636 | lsp = kzalloc(sizeof(*lsp), GFP_NOFS); |
| 622 | if (lsp == NULL) | 637 | if (lsp == NULL) |
| 623 | return NULL; | 638 | return NULL; |
| 624 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); | 639 | rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue"); |
| @@ -627,7 +642,18 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 627 | lsp->ls_seqid.sequence = &lsp->ls_sequence; | 642 | lsp->ls_seqid.sequence = &lsp->ls_sequence; |
| 628 | atomic_set(&lsp->ls_count, 1); | 643 | atomic_set(&lsp->ls_count, 1); |
| 629 | lsp->ls_state = state; | 644 | lsp->ls_state = state; |
| 630 | lsp->ls_owner = fl_owner; | 645 | lsp->ls_owner.lo_type = type; |
| 646 | switch (lsp->ls_owner.lo_type) { | ||
| 647 | case NFS4_FLOCK_LOCK_TYPE: | ||
| 648 | lsp->ls_owner.lo_u.flock_owner = fl_pid; | ||
| 649 | break; | ||
| 650 | case NFS4_POSIX_LOCK_TYPE: | ||
| 651 | lsp->ls_owner.lo_u.posix_owner = fl_owner; | ||
| 652 | break; | ||
| 653 | default: | ||
| 654 | kfree(lsp); | ||
| 655 | return NULL; | ||
| 656 | } | ||
| 631 | spin_lock(&clp->cl_lock); | 657 | spin_lock(&clp->cl_lock); |
| 632 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); | 658 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); |
| 633 | spin_unlock(&clp->cl_lock); | 659 | spin_unlock(&clp->cl_lock); |
| @@ -637,7 +663,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 637 | 663 | ||
| 638 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | 664 | static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) |
| 639 | { | 665 | { |
| 640 | struct nfs_client *clp = lsp->ls_state->owner->so_client; | 666 | struct nfs_client *clp = lsp->ls_state->owner->so_server->nfs_client; |
| 641 | 667 | ||
| 642 | spin_lock(&clp->cl_lock); | 668 | spin_lock(&clp->cl_lock); |
| 643 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); | 669 | nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id); |
| @@ -651,13 +677,13 @@ static void nfs4_free_lock_state(struct nfs4_lock_state *lsp) | |||
| 651 | * exists, return an uninitialized one. | 677 | * exists, return an uninitialized one. |
| 652 | * | 678 | * |
| 653 | */ | 679 | */ |
| 654 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) | 680 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type) |
| 655 | { | 681 | { |
| 656 | struct nfs4_lock_state *lsp, *new = NULL; | 682 | struct nfs4_lock_state *lsp, *new = NULL; |
| 657 | 683 | ||
| 658 | for(;;) { | 684 | for(;;) { |
| 659 | spin_lock(&state->state_lock); | 685 | spin_lock(&state->state_lock); |
| 660 | lsp = __nfs4_find_lock_state(state, owner); | 686 | lsp = __nfs4_find_lock_state(state, owner, pid, type); |
| 661 | if (lsp != NULL) | 687 | if (lsp != NULL) |
| 662 | break; | 688 | break; |
| 663 | if (new != NULL) { | 689 | if (new != NULL) { |
| @@ -668,7 +694,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
| 668 | break; | 694 | break; |
| 669 | } | 695 | } |
| 670 | spin_unlock(&state->state_lock); | 696 | spin_unlock(&state->state_lock); |
| 671 | new = nfs4_alloc_lock_state(state, owner); | 697 | new = nfs4_alloc_lock_state(state, owner, pid, type); |
| 672 | if (new == NULL) | 698 | if (new == NULL) |
| 673 | return NULL; | 699 | return NULL; |
| 674 | } | 700 | } |
| @@ -695,6 +721,8 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
| 695 | if (list_empty(&state->lock_states)) | 721 | if (list_empty(&state->lock_states)) |
| 696 | clear_bit(LK_STATE_IN_USE, &state->flags); | 722 | clear_bit(LK_STATE_IN_USE, &state->flags); |
| 697 | spin_unlock(&state->state_lock); | 723 | spin_unlock(&state->state_lock); |
| 724 | if (lsp->ls_flags & NFS_LOCK_INITIALIZED) | ||
| 725 | nfs4_release_lockowner(lsp); | ||
| 698 | nfs4_free_lock_state(lsp); | 726 | nfs4_free_lock_state(lsp); |
| 699 | } | 727 | } |
| 700 | 728 | ||
| @@ -722,7 +750,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
| 722 | 750 | ||
| 723 | if (fl->fl_ops != NULL) | 751 | if (fl->fl_ops != NULL) |
| 724 | return 0; | 752 | return 0; |
| 725 | lsp = nfs4_get_lock_state(state, fl->fl_owner); | 753 | if (fl->fl_flags & FL_POSIX) |
| 754 | lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE); | ||
| 755 | else if (fl->fl_flags & FL_FLOCK) | ||
| 756 | lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE); | ||
| 757 | else | ||
| 758 | return -EINVAL; | ||
| 726 | if (lsp == NULL) | 759 | if (lsp == NULL) |
| 727 | return -ENOMEM; | 760 | return -ENOMEM; |
| 728 | fl->fl_u.nfs4_fl.owner = lsp; | 761 | fl->fl_u.nfs4_fl.owner = lsp; |
| @@ -734,7 +767,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
| 734 | * Byte-range lock aware utility to initialize the stateid of read/write | 767 | * Byte-range lock aware utility to initialize the stateid of read/write |
| 735 | * requests. | 768 | * requests. |
| 736 | */ | 769 | */ |
| 737 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | 770 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid) |
| 738 | { | 771 | { |
| 739 | struct nfs4_lock_state *lsp; | 772 | struct nfs4_lock_state *lsp; |
| 740 | int seq; | 773 | int seq; |
| @@ -747,18 +780,18 @@ void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t f | |||
| 747 | return; | 780 | return; |
| 748 | 781 | ||
| 749 | spin_lock(&state->state_lock); | 782 | spin_lock(&state->state_lock); |
| 750 | lsp = __nfs4_find_lock_state(state, fl_owner); | 783 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); |
| 751 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | 784 | if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) |
| 752 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); | 785 | memcpy(dst, &lsp->ls_stateid, sizeof(*dst)); |
| 753 | spin_unlock(&state->state_lock); | 786 | spin_unlock(&state->state_lock); |
| 754 | nfs4_put_lock_state(lsp); | 787 | nfs4_put_lock_state(lsp); |
| 755 | } | 788 | } |
| 756 | 789 | ||
| 757 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | 790 | struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) |
| 758 | { | 791 | { |
| 759 | struct nfs_seqid *new; | 792 | struct nfs_seqid *new; |
| 760 | 793 | ||
| 761 | new = kmalloc(sizeof(*new), GFP_KERNEL); | 794 | new = kmalloc(sizeof(*new), gfp_mask); |
| 762 | if (new != NULL) { | 795 | if (new != NULL) { |
| 763 | new->sequence = counter; | 796 | new->sequence = counter; |
| 764 | INIT_LIST_HEAD(&new->list); | 797 | INIT_LIST_HEAD(&new->list); |
| @@ -1035,11 +1068,11 @@ restart: | |||
| 1035 | case -NFS4ERR_BAD_STATEID: | 1068 | case -NFS4ERR_BAD_STATEID: |
| 1036 | case -NFS4ERR_RECLAIM_BAD: | 1069 | case -NFS4ERR_RECLAIM_BAD: |
| 1037 | case -NFS4ERR_RECLAIM_CONFLICT: | 1070 | case -NFS4ERR_RECLAIM_CONFLICT: |
| 1038 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 1071 | nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); |
| 1039 | break; | 1072 | break; |
| 1040 | case -NFS4ERR_EXPIRED: | 1073 | case -NFS4ERR_EXPIRED: |
| 1041 | case -NFS4ERR_NO_GRACE: | 1074 | case -NFS4ERR_NO_GRACE: |
| 1042 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 1075 | nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state); |
| 1043 | case -NFS4ERR_STALE_CLIENTID: | 1076 | case -NFS4ERR_STALE_CLIENTID: |
| 1044 | case -NFS4ERR_BADSESSION: | 1077 | case -NFS4ERR_BADSESSION: |
| 1045 | case -NFS4ERR_BADSLOT: | 1078 | case -NFS4ERR_BADSLOT: |
| @@ -1114,8 +1147,7 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | |||
| 1114 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1147 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
| 1115 | return; | 1148 | return; |
| 1116 | 1149 | ||
| 1117 | nfs4_reclaim_complete(clp, | 1150 | nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); |
| 1118 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
| 1119 | 1151 | ||
| 1120 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1152 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { |
| 1121 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1153 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
| @@ -1205,8 +1237,8 @@ restart: | |||
| 1205 | static int nfs4_check_lease(struct nfs_client *clp) | 1237 | static int nfs4_check_lease(struct nfs_client *clp) |
| 1206 | { | 1238 | { |
| 1207 | struct rpc_cred *cred; | 1239 | struct rpc_cred *cred; |
| 1208 | struct nfs4_state_maintenance_ops *ops = | 1240 | const struct nfs4_state_maintenance_ops *ops = |
| 1209 | nfs4_state_renewal_ops[clp->cl_minorversion]; | 1241 | clp->cl_mvops->state_renewal_ops; |
| 1210 | int status = -NFS4ERR_EXPIRED; | 1242 | int status = -NFS4ERR_EXPIRED; |
| 1211 | 1243 | ||
| 1212 | /* Is the client already known to have an expired lease? */ | 1244 | /* Is the client already known to have an expired lease? */ |
| @@ -1229,8 +1261,8 @@ out: | |||
| 1229 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1261 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
| 1230 | { | 1262 | { |
| 1231 | struct rpc_cred *cred; | 1263 | struct rpc_cred *cred; |
| 1232 | struct nfs4_state_recovery_ops *ops = | 1264 | const struct nfs4_state_recovery_ops *ops = |
| 1233 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | 1265 | clp->cl_mvops->reboot_recovery_ops; |
| 1234 | int status = -ENOENT; | 1266 | int status = -ENOENT; |
| 1235 | 1267 | ||
| 1236 | cred = ops->get_clid_cred(clp); | 1268 | cred = ops->get_clid_cred(clp); |
| @@ -1347,7 +1379,7 @@ static int nfs4_recall_slot(struct nfs_client *clp) | |||
| 1347 | 1379 | ||
| 1348 | nfs4_begin_drain_session(clp); | 1380 | nfs4_begin_drain_session(clp); |
| 1349 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | 1381 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), |
| 1350 | GFP_KERNEL); | 1382 | GFP_NOFS); |
| 1351 | if (!new) | 1383 | if (!new) |
| 1352 | return -ENOMEM; | 1384 | return -ENOMEM; |
| 1353 | 1385 | ||
| @@ -1438,7 +1470,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1438 | /* First recover reboot state... */ | 1470 | /* First recover reboot state... */ |
| 1439 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1471 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
| 1440 | status = nfs4_do_reclaim(clp, | 1472 | status = nfs4_do_reclaim(clp, |
| 1441 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | 1473 | clp->cl_mvops->reboot_recovery_ops); |
| 1442 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1474 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
| 1443 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) | 1475 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) |
| 1444 | continue; | 1476 | continue; |
| @@ -1452,7 +1484,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
| 1452 | /* Now recover expired state... */ | 1484 | /* Now recover expired state... */ |
| 1453 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1485 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
| 1454 | status = nfs4_do_reclaim(clp, | 1486 | status = nfs4_do_reclaim(clp, |
| 1455 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | 1487 | clp->cl_mvops->nograce_recovery_ops); |
| 1456 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || | 1488 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
| 1457 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || | 1489 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || |
| 1458 | test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1490 | test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 38f3b582e7c2..08ef91291132 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -202,14 +202,17 @@ static int nfs4_stat_to_errno(int); | |||
| 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
| 203 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
| 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
| 205 | #define encode_lockowner_maxsz (7) | ||
| 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 206 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
| 206 | 7 + \ | 207 | 7 + \ |
| 207 | 1 + encode_stateid_maxsz + 8) | 208 | 1 + encode_stateid_maxsz + 1 + \ |
| 209 | encode_lockowner_maxsz) | ||
| 208 | #define decode_lock_denied_maxsz \ | 210 | #define decode_lock_denied_maxsz \ |
| 209 | (8 + decode_lockowner_maxsz) | 211 | (8 + decode_lockowner_maxsz) |
| 210 | #define decode_lock_maxsz (op_decode_hdr_maxsz + \ | 212 | #define decode_lock_maxsz (op_decode_hdr_maxsz + \ |
| 211 | decode_lock_denied_maxsz) | 213 | decode_lock_denied_maxsz) |
| 212 | #define encode_lockt_maxsz (op_encode_hdr_maxsz + 12) | 214 | #define encode_lockt_maxsz (op_encode_hdr_maxsz + 5 + \ |
| 215 | encode_lockowner_maxsz) | ||
| 213 | #define decode_lockt_maxsz (op_decode_hdr_maxsz + \ | 216 | #define decode_lockt_maxsz (op_decode_hdr_maxsz + \ |
| 214 | decode_lock_denied_maxsz) | 217 | decode_lock_denied_maxsz) |
| 215 | #define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \ | 218 | #define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \ |
| @@ -217,6 +220,11 @@ static int nfs4_stat_to_errno(int); | |||
| 217 | 4) | 220 | 4) |
| 218 | #define decode_locku_maxsz (op_decode_hdr_maxsz + \ | 221 | #define decode_locku_maxsz (op_decode_hdr_maxsz + \ |
| 219 | decode_stateid_maxsz) | 222 | decode_stateid_maxsz) |
| 223 | #define encode_release_lockowner_maxsz \ | ||
| 224 | (op_encode_hdr_maxsz + \ | ||
| 225 | encode_lockowner_maxsz) | ||
| 226 | #define decode_release_lockowner_maxsz \ | ||
| 227 | (op_decode_hdr_maxsz) | ||
| 220 | #define encode_access_maxsz (op_encode_hdr_maxsz + 1) | 228 | #define encode_access_maxsz (op_encode_hdr_maxsz + 1) |
| 221 | #define decode_access_maxsz (op_decode_hdr_maxsz + 2) | 229 | #define decode_access_maxsz (op_decode_hdr_maxsz + 2) |
| 222 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ | 230 | #define encode_symlink_maxsz (op_encode_hdr_maxsz + \ |
| @@ -471,6 +479,12 @@ static int nfs4_stat_to_errno(int); | |||
| 471 | decode_sequence_maxsz + \ | 479 | decode_sequence_maxsz + \ |
| 472 | decode_putfh_maxsz + \ | 480 | decode_putfh_maxsz + \ |
| 473 | decode_locku_maxsz) | 481 | decode_locku_maxsz) |
| 482 | #define NFS4_enc_release_lockowner_sz \ | ||
| 483 | (compound_encode_hdr_maxsz + \ | ||
| 484 | encode_lockowner_maxsz) | ||
| 485 | #define NFS4_dec_release_lockowner_sz \ | ||
| 486 | (compound_decode_hdr_maxsz + \ | ||
| 487 | decode_lockowner_maxsz) | ||
| 474 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 488 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
| 475 | encode_sequence_maxsz + \ | 489 | encode_sequence_maxsz + \ |
| 476 | encode_putfh_maxsz + \ | 490 | encode_putfh_maxsz + \ |
| @@ -744,7 +758,7 @@ static void encode_compound_hdr(struct xdr_stream *xdr, | |||
| 744 | struct compound_hdr *hdr) | 758 | struct compound_hdr *hdr) |
| 745 | { | 759 | { |
| 746 | __be32 *p; | 760 | __be32 *p; |
| 747 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 761 | struct rpc_auth *auth = req->rq_cred->cr_auth; |
| 748 | 762 | ||
| 749 | /* initialize running count of expected bytes in reply. | 763 | /* initialize running count of expected bytes in reply. |
| 750 | * NOTE: the replied tag SHOULD be the same is the one sent, | 764 | * NOTE: the replied tag SHOULD be the same is the one sent, |
| @@ -862,8 +876,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const | |||
| 862 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 876 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
| 863 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); | 877 | *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME); |
| 864 | *p++ = cpu_to_be32(0); | 878 | *p++ = cpu_to_be32(0); |
| 865 | *p++ = cpu_to_be32(iap->ia_mtime.tv_sec); | 879 | *p++ = cpu_to_be32(iap->ia_atime.tv_sec); |
| 866 | *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec); | 880 | *p++ = cpu_to_be32(iap->ia_atime.tv_nsec); |
| 867 | } | 881 | } |
| 868 | else if (iap->ia_valid & ATTR_ATIME) { | 882 | else if (iap->ia_valid & ATTR_ATIME) { |
| 869 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; | 883 | bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET; |
| @@ -1042,6 +1056,17 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl) | |||
| 1042 | return fl->fl_end - fl->fl_start + 1; | 1056 | return fl->fl_end - fl->fl_start + 1; |
| 1043 | } | 1057 | } |
| 1044 | 1058 | ||
| 1059 | static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner) | ||
| 1060 | { | ||
| 1061 | __be32 *p; | ||
| 1062 | |||
| 1063 | p = reserve_space(xdr, 28); | ||
| 1064 | p = xdr_encode_hyper(p, lowner->clientid); | ||
| 1065 | *p++ = cpu_to_be32(16); | ||
| 1066 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
| 1067 | xdr_encode_hyper(p, lowner->id); | ||
| 1068 | } | ||
| 1069 | |||
| 1045 | /* | 1070 | /* |
| 1046 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 | 1071 | * opcode,type,reclaim,offset,length,new_lock_owner = 32 |
| 1047 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 | 1072 | * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40 |
| @@ -1058,14 +1083,11 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
| 1058 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1083 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1059 | *p = cpu_to_be32(args->new_lock_owner); | 1084 | *p = cpu_to_be32(args->new_lock_owner); |
| 1060 | if (args->new_lock_owner){ | 1085 | if (args->new_lock_owner){ |
| 1061 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32); | 1086 | p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4); |
| 1062 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); | 1087 | *p++ = cpu_to_be32(args->open_seqid->sequence->counter); |
| 1063 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); | 1088 | p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE); |
| 1064 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); | 1089 | *p++ = cpu_to_be32(args->lock_seqid->sequence->counter); |
| 1065 | p = xdr_encode_hyper(p, args->lock_owner.clientid); | 1090 | encode_lockowner(xdr, &args->lock_owner); |
| 1066 | *p++ = cpu_to_be32(16); | ||
| 1067 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
| 1068 | xdr_encode_hyper(p, args->lock_owner.id); | ||
| 1069 | } | 1091 | } |
| 1070 | else { | 1092 | else { |
| 1071 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); | 1093 | p = reserve_space(xdr, NFS4_STATEID_SIZE+4); |
| @@ -1080,15 +1102,12 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
| 1080 | { | 1102 | { |
| 1081 | __be32 *p; | 1103 | __be32 *p; |
| 1082 | 1104 | ||
| 1083 | p = reserve_space(xdr, 52); | 1105 | p = reserve_space(xdr, 24); |
| 1084 | *p++ = cpu_to_be32(OP_LOCKT); | 1106 | *p++ = cpu_to_be32(OP_LOCKT); |
| 1085 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); | 1107 | *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0)); |
| 1086 | p = xdr_encode_hyper(p, args->fl->fl_start); | 1108 | p = xdr_encode_hyper(p, args->fl->fl_start); |
| 1087 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); | 1109 | p = xdr_encode_hyper(p, nfs4_lock_length(args->fl)); |
| 1088 | p = xdr_encode_hyper(p, args->lock_owner.clientid); | 1110 | encode_lockowner(xdr, &args->lock_owner); |
| 1089 | *p++ = cpu_to_be32(16); | ||
| 1090 | p = xdr_encode_opaque_fixed(p, "lock id:", 8); | ||
| 1091 | xdr_encode_hyper(p, args->lock_owner.id); | ||
| 1092 | hdr->nops++; | 1111 | hdr->nops++; |
| 1093 | hdr->replen += decode_lockt_maxsz; | 1112 | hdr->replen += decode_lockt_maxsz; |
| 1094 | } | 1113 | } |
| @@ -1108,6 +1127,17 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
| 1108 | hdr->replen += decode_locku_maxsz; | 1127 | hdr->replen += decode_locku_maxsz; |
| 1109 | } | 1128 | } |
| 1110 | 1129 | ||
| 1130 | static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr) | ||
| 1131 | { | ||
| 1132 | __be32 *p; | ||
| 1133 | |||
| 1134 | p = reserve_space(xdr, 4); | ||
| 1135 | *p = cpu_to_be32(OP_RELEASE_LOCKOWNER); | ||
| 1136 | encode_lockowner(xdr, lowner); | ||
| 1137 | hdr->nops++; | ||
| 1138 | hdr->replen += decode_release_lockowner_maxsz; | ||
| 1139 | } | ||
| 1140 | |||
| 1111 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1141 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
| 1112 | { | 1142 | { |
| 1113 | int len = name->len; | 1143 | int len = name->len; |
| @@ -1172,7 +1202,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
| 1172 | break; | 1202 | break; |
| 1173 | default: | 1203 | default: |
| 1174 | clp = arg->server->nfs_client; | 1204 | clp = arg->server->nfs_client; |
| 1175 | if (clp->cl_minorversion > 0) { | 1205 | if (clp->cl_mvops->minor_version > 0) { |
| 1176 | if (nfs4_has_persistent_session(clp)) { | 1206 | if (nfs4_has_persistent_session(clp)) { |
| 1177 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); | 1207 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); |
| 1178 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1208 | encode_attrs(xdr, arg->u.attrs, arg->server); |
| @@ -1324,14 +1354,14 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
| 1324 | hdr->replen += decode_putrootfh_maxsz; | 1354 | hdr->replen += decode_putrootfh_maxsz; |
| 1325 | } | 1355 | } |
| 1326 | 1356 | ||
| 1327 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1357 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx) |
| 1328 | { | 1358 | { |
| 1329 | nfs4_stateid stateid; | 1359 | nfs4_stateid stateid; |
| 1330 | __be32 *p; | 1360 | __be32 *p; |
| 1331 | 1361 | ||
| 1332 | p = reserve_space(xdr, NFS4_STATEID_SIZE); | 1362 | p = reserve_space(xdr, NFS4_STATEID_SIZE); |
| 1333 | if (ctx->state != NULL) { | 1363 | if (ctx->state != NULL) { |
| 1334 | nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner); | 1364 | nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid); |
| 1335 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); | 1365 | xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE); |
| 1336 | } else | 1366 | } else |
| 1337 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); | 1367 | xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE); |
| @@ -1344,7 +1374,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
| 1344 | p = reserve_space(xdr, 4); | 1374 | p = reserve_space(xdr, 4); |
| 1345 | *p = cpu_to_be32(OP_READ); | 1375 | *p = cpu_to_be32(OP_READ); |
| 1346 | 1376 | ||
| 1347 | encode_stateid(xdr, args->context); | 1377 | encode_stateid(xdr, args->context, args->lock_context); |
| 1348 | 1378 | ||
| 1349 | p = reserve_space(xdr, 12); | 1379 | p = reserve_space(xdr, 12); |
| 1350 | p = xdr_encode_hyper(p, args->offset); | 1380 | p = xdr_encode_hyper(p, args->offset); |
| @@ -1504,14 +1534,14 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
| 1504 | hdr->replen += decode_setclientid_maxsz; | 1534 | hdr->replen += decode_setclientid_maxsz; |
| 1505 | } | 1535 | } |
| 1506 | 1536 | ||
| 1507 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1537 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr) |
| 1508 | { | 1538 | { |
| 1509 | __be32 *p; | 1539 | __be32 *p; |
| 1510 | 1540 | ||
| 1511 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); | 1541 | p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE); |
| 1512 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); | 1542 | *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM); |
| 1513 | p = xdr_encode_hyper(p, client_state->cl_clientid); | 1543 | p = xdr_encode_hyper(p, arg->clientid); |
| 1514 | xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1544 | xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE); |
| 1515 | hdr->nops++; | 1545 | hdr->nops++; |
| 1516 | hdr->replen += decode_setclientid_confirm_maxsz; | 1546 | hdr->replen += decode_setclientid_confirm_maxsz; |
| 1517 | } | 1547 | } |
| @@ -1523,7 +1553,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
| 1523 | p = reserve_space(xdr, 4); | 1553 | p = reserve_space(xdr, 4); |
| 1524 | *p = cpu_to_be32(OP_WRITE); | 1554 | *p = cpu_to_be32(OP_WRITE); |
| 1525 | 1555 | ||
| 1526 | encode_stateid(xdr, args->context); | 1556 | encode_stateid(xdr, args->context, args->lock_context); |
| 1527 | 1557 | ||
| 1528 | p = reserve_space(xdr, 16); | 1558 | p = reserve_space(xdr, 16); |
| 1529 | p = xdr_encode_hyper(p, args->offset); | 1559 | p = xdr_encode_hyper(p, args->offset); |
| @@ -1704,7 +1734,7 @@ static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | |||
| 1704 | { | 1734 | { |
| 1705 | #if defined(CONFIG_NFS_V4_1) | 1735 | #if defined(CONFIG_NFS_V4_1) |
| 1706 | if (args->sa_session) | 1736 | if (args->sa_session) |
| 1707 | return args->sa_session->clp->cl_minorversion; | 1737 | return args->sa_session->clp->cl_mvops->minor_version; |
| 1708 | #endif /* CONFIG_NFS_V4_1 */ | 1738 | #endif /* CONFIG_NFS_V4_1 */ |
| 1709 | return 0; | 1739 | return 0; |
| 1710 | } | 1740 | } |
| @@ -2048,6 +2078,20 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
| 2048 | return 0; | 2078 | return 0; |
| 2049 | } | 2079 | } |
| 2050 | 2080 | ||
| 2081 | static int nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req, __be32 *p, struct nfs_release_lockowner_args *args) | ||
| 2082 | { | ||
| 2083 | struct xdr_stream xdr; | ||
| 2084 | struct compound_hdr hdr = { | ||
| 2085 | .minorversion = 0, | ||
| 2086 | }; | ||
| 2087 | |||
| 2088 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
| 2089 | encode_compound_hdr(&xdr, req, &hdr); | ||
| 2090 | encode_release_lockowner(&xdr, &args->lock_owner, &hdr); | ||
| 2091 | encode_nops(&hdr); | ||
| 2092 | return 0; | ||
| 2093 | } | ||
| 2094 | |||
| 2051 | /* | 2095 | /* |
| 2052 | * Encode a READLINK request | 2096 | * Encode a READLINK request |
| 2053 | */ | 2097 | */ |
| @@ -2324,7 +2368,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
| 2324 | /* | 2368 | /* |
| 2325 | * a SETCLIENTID_CONFIRM request | 2369 | * a SETCLIENTID_CONFIRM request |
| 2326 | */ | 2370 | */ |
| 2327 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp) | 2371 | static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg) |
| 2328 | { | 2372 | { |
| 2329 | struct xdr_stream xdr; | 2373 | struct xdr_stream xdr; |
| 2330 | struct compound_hdr hdr = { | 2374 | struct compound_hdr hdr = { |
| @@ -2334,7 +2378,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
| 2334 | 2378 | ||
| 2335 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2379 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| 2336 | encode_compound_hdr(&xdr, req, &hdr); | 2380 | encode_compound_hdr(&xdr, req, &hdr); |
| 2337 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2381 | encode_setclientid_confirm(&xdr, arg, &hdr); |
| 2338 | encode_putrootfh(&xdr, &hdr); | 2382 | encode_putrootfh(&xdr, &hdr); |
| 2339 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2383 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
| 2340 | encode_nops(&hdr); | 2384 | encode_nops(&hdr); |
| @@ -2395,7 +2439,7 @@ static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | |||
| 2395 | { | 2439 | { |
| 2396 | struct xdr_stream xdr; | 2440 | struct xdr_stream xdr; |
| 2397 | struct compound_hdr hdr = { | 2441 | struct compound_hdr hdr = { |
| 2398 | .minorversion = args->client->cl_minorversion, | 2442 | .minorversion = args->client->cl_mvops->minor_version, |
| 2399 | }; | 2443 | }; |
| 2400 | 2444 | ||
| 2401 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2445 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| @@ -2413,7 +2457,7 @@ static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | |||
| 2413 | { | 2457 | { |
| 2414 | struct xdr_stream xdr; | 2458 | struct xdr_stream xdr; |
| 2415 | struct compound_hdr hdr = { | 2459 | struct compound_hdr hdr = { |
| 2416 | .minorversion = args->client->cl_minorversion, | 2460 | .minorversion = args->client->cl_mvops->minor_version, |
| 2417 | }; | 2461 | }; |
| 2418 | 2462 | ||
| 2419 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2463 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| @@ -2431,7 +2475,7 @@ static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | |||
| 2431 | { | 2475 | { |
| 2432 | struct xdr_stream xdr; | 2476 | struct xdr_stream xdr; |
| 2433 | struct compound_hdr hdr = { | 2477 | struct compound_hdr hdr = { |
| 2434 | .minorversion = session->clp->cl_minorversion, | 2478 | .minorversion = session->clp->cl_mvops->minor_version, |
| 2435 | }; | 2479 | }; |
| 2436 | 2480 | ||
| 2437 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2481 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
| @@ -3973,6 +4017,11 @@ static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res) | |||
| 3973 | return status; | 4017 | return status; |
| 3974 | } | 4018 | } |
| 3975 | 4019 | ||
| 4020 | static int decode_release_lockowner(struct xdr_stream *xdr) | ||
| 4021 | { | ||
| 4022 | return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER); | ||
| 4023 | } | ||
| 4024 | |||
| 3976 | static int decode_lookup(struct xdr_stream *xdr) | 4025 | static int decode_lookup(struct xdr_stream *xdr) |
| 3977 | { | 4026 | { |
| 3978 | return decode_op_hdr(xdr, OP_LOOKUP); | 4027 | return decode_op_hdr(xdr, OP_LOOKUP); |
| @@ -4397,7 +4446,7 @@ out_overflow: | |||
| 4397 | return -EIO; | 4446 | return -EIO; |
| 4398 | } | 4447 | } |
| 4399 | 4448 | ||
| 4400 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | 4449 | static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res) |
| 4401 | { | 4450 | { |
| 4402 | __be32 *p; | 4451 | __be32 *p; |
| 4403 | uint32_t opnum; | 4452 | uint32_t opnum; |
| @@ -4417,8 +4466,8 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp) | |||
| 4417 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); | 4466 | p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE); |
| 4418 | if (unlikely(!p)) | 4467 | if (unlikely(!p)) |
| 4419 | goto out_overflow; | 4468 | goto out_overflow; |
| 4420 | p = xdr_decode_hyper(p, &clp->cl_clientid); | 4469 | p = xdr_decode_hyper(p, &res->clientid); |
| 4421 | memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE); | 4470 | memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE); |
| 4422 | } else if (nfserr == NFSERR_CLID_INUSE) { | 4471 | } else if (nfserr == NFSERR_CLID_INUSE) { |
| 4423 | uint32_t len; | 4472 | uint32_t len; |
| 4424 | 4473 | ||
| @@ -4815,7 +4864,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
| 4815 | goto out; | 4864 | goto out; |
| 4816 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) | 4865 | if ((status = decode_remove(&xdr, &res->cinfo)) != 0) |
| 4817 | goto out; | 4866 | goto out; |
| 4818 | decode_getfattr(&xdr, &res->dir_attr, res->server, | 4867 | decode_getfattr(&xdr, res->dir_attr, res->server, |
| 4819 | !RPC_IS_ASYNC(rqstp->rq_task)); | 4868 | !RPC_IS_ASYNC(rqstp->rq_task)); |
| 4820 | out: | 4869 | out: |
| 4821 | return status; | 4870 | return status; |
| @@ -5259,6 +5308,19 @@ out: | |||
| 5259 | return status; | 5308 | return status; |
| 5260 | } | 5309 | } |
| 5261 | 5310 | ||
| 5311 | static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | ||
| 5312 | { | ||
| 5313 | struct xdr_stream xdr; | ||
| 5314 | struct compound_hdr hdr; | ||
| 5315 | int status; | ||
| 5316 | |||
| 5317 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
| 5318 | status = decode_compound_hdr(&xdr, &hdr); | ||
| 5319 | if (!status) | ||
| 5320 | status = decode_release_lockowner(&xdr); | ||
| 5321 | return status; | ||
| 5322 | } | ||
| 5323 | |||
| 5262 | /* | 5324 | /* |
| 5263 | * Decode READLINK response | 5325 | * Decode READLINK response |
| 5264 | */ | 5326 | */ |
| @@ -5498,7 +5560,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | |||
| 5498 | * Decode SETCLIENTID response | 5560 | * Decode SETCLIENTID response |
| 5499 | */ | 5561 | */ |
| 5500 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | 5562 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, |
| 5501 | struct nfs_client *clp) | 5563 | struct nfs4_setclientid_res *res) |
| 5502 | { | 5564 | { |
| 5503 | struct xdr_stream xdr; | 5565 | struct xdr_stream xdr; |
| 5504 | struct compound_hdr hdr; | 5566 | struct compound_hdr hdr; |
| @@ -5507,7 +5569,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
| 5507 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5569 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
| 5508 | status = decode_compound_hdr(&xdr, &hdr); | 5570 | status = decode_compound_hdr(&xdr, &hdr); |
| 5509 | if (!status) | 5571 | if (!status) |
| 5510 | status = decode_setclientid(&xdr, clp); | 5572 | status = decode_setclientid(&xdr, res); |
| 5511 | return status; | 5573 | return status; |
| 5512 | } | 5574 | } |
| 5513 | 5575 | ||
| @@ -5866,6 +5928,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
| 5866 | PROC(GETACL, enc_getacl, dec_getacl), | 5928 | PROC(GETACL, enc_getacl, dec_getacl), |
| 5867 | PROC(SETACL, enc_setacl, dec_setacl), | 5929 | PROC(SETACL, enc_setacl, dec_setacl), |
| 5868 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5930 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
| 5931 | PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner), | ||
| 5869 | #if defined(CONFIG_NFS_V4_1) | 5932 | #if defined(CONFIG_NFS_V4_1) |
| 5870 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 5933 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
| 5871 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 5934 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8c55b27c0de4..df101d9f546a 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -105,7 +105,7 @@ static char nfs_root_name[256] __initdata = ""; | |||
| 105 | static __be32 servaddr __initdata = 0; | 105 | static __be32 servaddr __initdata = 0; |
| 106 | 106 | ||
| 107 | /* Name of directory to mount */ | 107 | /* Name of directory to mount */ |
| 108 | static char nfs_export_path[NFS_MAXPATHLEN] __initdata = { 0, }; | 108 | static char nfs_export_path[NFS_MAXPATHLEN + 1] __initdata = { 0, }; |
| 109 | 109 | ||
| 110 | /* NFS-related data */ | 110 | /* NFS-related data */ |
| 111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ | 111 | static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */ |
| @@ -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..919490232e17 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 |
| @@ -85,6 +79,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode, | |||
| 85 | req->wb_pgbase = offset; | 79 | req->wb_pgbase = offset; |
| 86 | req->wb_bytes = count; | 80 | req->wb_bytes = count; |
| 87 | req->wb_context = get_nfs_open_context(ctx); | 81 | req->wb_context = get_nfs_open_context(ctx); |
| 82 | req->wb_lock_context = nfs_get_lock_context(ctx); | ||
| 88 | kref_init(&req->wb_kref); | 83 | kref_init(&req->wb_kref); |
| 89 | return req; | 84 | return req; |
| 90 | } | 85 | } |
| @@ -147,11 +142,16 @@ void nfs_clear_request(struct nfs_page *req) | |||
| 147 | { | 142 | { |
| 148 | struct page *page = req->wb_page; | 143 | struct page *page = req->wb_page; |
| 149 | struct nfs_open_context *ctx = req->wb_context; | 144 | struct nfs_open_context *ctx = req->wb_context; |
| 145 | struct nfs_lock_context *l_ctx = req->wb_lock_context; | ||
| 150 | 146 | ||
| 151 | if (page != NULL) { | 147 | if (page != NULL) { |
| 152 | page_cache_release(page); | 148 | page_cache_release(page); |
| 153 | req->wb_page = NULL; | 149 | req->wb_page = NULL; |
| 154 | } | 150 | } |
| 151 | if (l_ctx != NULL) { | ||
| 152 | nfs_put_lock_context(l_ctx); | ||
| 153 | req->wb_lock_context = NULL; | ||
| 154 | } | ||
| 155 | if (ctx != NULL) { | 155 | if (ctx != NULL) { |
| 156 | put_nfs_open_context(ctx); | 156 | put_nfs_open_context(ctx); |
| 157 | req->wb_context = NULL; | 157 | req->wb_context = NULL; |
| @@ -241,7 +241,7 @@ static int nfs_can_coalesce_requests(struct nfs_page *prev, | |||
| 241 | { | 241 | { |
| 242 | if (req->wb_context->cred != prev->wb_context->cred) | 242 | if (req->wb_context->cred != prev->wb_context->cred) |
| 243 | return 0; | 243 | return 0; |
| 244 | if (req->wb_context->lockowner != prev->wb_context->lockowner) | 244 | if (req->wb_lock_context->lockowner != prev->wb_lock_context->lockowner) |
| 245 | return 0; | 245 | return 0; |
| 246 | if (req->wb_context->state != prev->wb_context->state) | 246 | if (req->wb_context->state != prev->wb_context->state) |
| 247 | return 0; | 247 | return 0; |
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..87adc2744246 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; |
| @@ -190,6 +190,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, | |||
| 190 | data->args.pages = data->pagevec; | 190 | data->args.pages = data->pagevec; |
| 191 | data->args.count = count; | 191 | data->args.count = count; |
| 192 | data->args.context = get_nfs_open_context(req->wb_context); | 192 | data->args.context = get_nfs_open_context(req->wb_context); |
| 193 | data->args.lock_context = req->wb_lock_context; | ||
| 193 | 194 | ||
| 194 | data->res.fattr = &data->fattr; | 195 | data->res.fattr = &data->fattr; |
| 195 | data->res.count = count; | 196 | data->res.count = count; |
| @@ -410,7 +411,7 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata) | |||
| 410 | { | 411 | { |
| 411 | struct nfs_read_data *data = calldata; | 412 | struct nfs_read_data *data = calldata; |
| 412 | 413 | ||
| 413 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | 414 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), |
| 414 | &data->args.seq_args, &data->res.seq_res, | 415 | &data->args.seq_args, &data->res.seq_res, |
| 415 | 0, task)) | 416 | 0, task)) |
| 416 | return; | 417 | return; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b4148fc00f9f..ee26316ad1f4 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 | }; |
| @@ -270,7 +270,7 @@ static const struct super_operations nfs_sops = { | |||
| 270 | .write_inode = nfs_write_inode, | 270 | .write_inode = nfs_write_inode, |
| 271 | .put_super = nfs_put_super, | 271 | .put_super = nfs_put_super, |
| 272 | .statfs = nfs_statfs, | 272 | .statfs = nfs_statfs, |
| 273 | .clear_inode = nfs_clear_inode, | 273 | .evict_inode = nfs_evict_inode, |
| 274 | .umount_begin = nfs_umount_begin, | 274 | .umount_begin = nfs_umount_begin, |
| 275 | .show_options = nfs_show_options, | 275 | .show_options = nfs_show_options, |
| 276 | .show_stats = nfs_show_stats, | 276 | .show_stats = nfs_show_stats, |
| @@ -340,7 +340,7 @@ static const struct super_operations nfs4_sops = { | |||
| 340 | .write_inode = nfs_write_inode, | 340 | .write_inode = nfs_write_inode, |
| 341 | .put_super = nfs_put_super, | 341 | .put_super = nfs_put_super, |
| 342 | .statfs = nfs_statfs, | 342 | .statfs = nfs_statfs, |
| 343 | .clear_inode = nfs4_clear_inode, | 343 | .evict_inode = nfs4_evict_inode, |
| 344 | .umount_begin = nfs_umount_begin, | 344 | .umount_begin = nfs_umount_begin, |
| 345 | .show_options = nfs_show_options, | 345 | .show_options = nfs_show_options, |
| 346 | .show_stats = nfs_show_stats, | 346 | .show_stats = nfs_show_stats, |
| @@ -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 | /* |
| @@ -542,6 +546,9 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 542 | { | 546 | { |
| 543 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; | 547 | struct sockaddr *sap = (struct sockaddr *)&nfss->mountd_address; |
| 544 | 548 | ||
| 549 | if (nfss->flags & NFS_MOUNT_LEGACY_INTERFACE) | ||
| 550 | return; | ||
| 551 | |||
| 545 | switch (sap->sa_family) { | 552 | switch (sap->sa_family) { |
| 546 | case AF_INET: { | 553 | case AF_INET: { |
| 547 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; | 554 | struct sockaddr_in *sin = (struct sockaddr_in *)sap; |
| @@ -566,6 +573,22 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 566 | nfs_show_mountd_netid(m, nfss, showdefaults); | 573 | nfs_show_mountd_netid(m, nfss, showdefaults); |
| 567 | } | 574 | } |
| 568 | 575 | ||
| 576 | #ifdef CONFIG_NFS_V4 | ||
| 577 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | ||
| 578 | int showdefaults) | ||
| 579 | { | ||
| 580 | struct nfs_client *clp = nfss->nfs_client; | ||
| 581 | |||
| 582 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
| 583 | seq_printf(m, ",minorversion=%u", clp->cl_minorversion); | ||
| 584 | } | ||
| 585 | #else | ||
| 586 | static void nfs_show_nfsv4_options(struct seq_file *m, struct nfs_server *nfss, | ||
| 587 | int showdefaults) | ||
| 588 | { | ||
| 589 | } | ||
| 590 | #endif | ||
| 591 | |||
| 569 | /* | 592 | /* |
| 570 | * Describe the mount options in force on this server representation | 593 | * Describe the mount options in force on this server representation |
| 571 | */ | 594 | */ |
| @@ -627,11 +650,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 627 | 650 | ||
| 628 | if (version != 4) | 651 | if (version != 4) |
| 629 | nfs_show_mountd_options(m, nfss, showdefaults); | 652 | nfs_show_mountd_options(m, nfss, showdefaults); |
| 653 | else | ||
| 654 | nfs_show_nfsv4_options(m, nfss, showdefaults); | ||
| 630 | 655 | ||
| 631 | #ifdef CONFIG_NFS_V4 | ||
| 632 | if (clp->rpc_ops->version == 4) | ||
| 633 | seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr); | ||
| 634 | #endif | ||
| 635 | if (nfss->options & NFS_OPTION_FSCACHE) | 656 | if (nfss->options & NFS_OPTION_FSCACHE) |
| 636 | seq_printf(m, ",fsc"); | 657 | seq_printf(m, ",fsc"); |
| 637 | } | 658 | } |
| @@ -1046,14 +1067,6 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1046 | kfree(mnt->fscache_uniq); | 1067 | kfree(mnt->fscache_uniq); |
| 1047 | mnt->fscache_uniq = NULL; | 1068 | mnt->fscache_uniq = NULL; |
| 1048 | break; | 1069 | 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 | 1070 | ||
| 1058 | /* | 1071 | /* |
| 1059 | * options that take numeric values | 1072 | * options that take numeric values |
| @@ -1064,7 +1077,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1064 | goto out_nomem; | 1077 | goto out_nomem; |
| 1065 | rc = strict_strtoul(string, 10, &option); | 1078 | rc = strict_strtoul(string, 10, &option); |
| 1066 | kfree(string); | 1079 | kfree(string); |
| 1067 | if (rc != 0 || option > USHORT_MAX) | 1080 | if (rc != 0 || option > USHRT_MAX) |
| 1068 | goto out_invalid_value; | 1081 | goto out_invalid_value; |
| 1069 | mnt->nfs_server.port = option; | 1082 | mnt->nfs_server.port = option; |
| 1070 | break; | 1083 | break; |
| @@ -1185,7 +1198,7 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1185 | goto out_nomem; | 1198 | goto out_nomem; |
| 1186 | rc = strict_strtoul(string, 10, &option); | 1199 | rc = strict_strtoul(string, 10, &option); |
| 1187 | kfree(string); | 1200 | kfree(string); |
| 1188 | if (rc != 0 || option > USHORT_MAX) | 1201 | if (rc != 0 || option > USHRT_MAX) |
| 1189 | goto out_invalid_value; | 1202 | goto out_invalid_value; |
| 1190 | mnt->mount_server.port = option; | 1203 | mnt->mount_server.port = option; |
| 1191 | break; | 1204 | break; |
| @@ -1384,6 +1397,14 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1384 | return 0; | 1397 | return 0; |
| 1385 | }; | 1398 | }; |
| 1386 | break; | 1399 | break; |
| 1400 | case Opt_fscache_uniq: | ||
| 1401 | string = match_strdup(args); | ||
| 1402 | if (string == NULL) | ||
| 1403 | goto out_nomem; | ||
| 1404 | kfree(mnt->fscache_uniq); | ||
| 1405 | mnt->fscache_uniq = string; | ||
| 1406 | mnt->options |= NFS_OPTION_FSCACHE; | ||
| 1407 | break; | ||
| 1387 | 1408 | ||
| 1388 | /* | 1409 | /* |
| 1389 | * Special options | 1410 | * Special options |
| @@ -1762,6 +1783,7 @@ static int nfs_validate_mount_data(void *options, | |||
| 1762 | * can deal with. | 1783 | * can deal with. |
| 1763 | */ | 1784 | */ |
| 1764 | args->flags = data->flags & NFS_MOUNT_FLAGMASK; | 1785 | args->flags = data->flags & NFS_MOUNT_FLAGMASK; |
| 1786 | args->flags |= NFS_MOUNT_LEGACY_INTERFACE; | ||
| 1765 | args->rsize = data->rsize; | 1787 | args->rsize = data->rsize; |
| 1766 | args->wsize = data->wsize; | 1788 | args->wsize = data->wsize; |
| 1767 | args->timeo = data->timeo; | 1789 | args->timeo = data->timeo; |
| @@ -2172,7 +2194,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2172 | int error = -ENOMEM; | 2194 | int error = -ENOMEM; |
| 2173 | 2195 | ||
| 2174 | data = nfs_alloc_parsed_mount_data(3); | 2196 | data = nfs_alloc_parsed_mount_data(3); |
| 2175 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2197 | mntfh = nfs_alloc_fhandle(); |
| 2176 | if (data == NULL || mntfh == NULL) | 2198 | if (data == NULL || mntfh == NULL) |
| 2177 | goto out_free_fh; | 2199 | goto out_free_fh; |
| 2178 | 2200 | ||
| @@ -2247,7 +2269,7 @@ out: | |||
| 2247 | kfree(data->fscache_uniq); | 2269 | kfree(data->fscache_uniq); |
| 2248 | security_free_mnt_opts(&data->lsm_opts); | 2270 | security_free_mnt_opts(&data->lsm_opts); |
| 2249 | out_free_fh: | 2271 | out_free_fh: |
| 2250 | kfree(mntfh); | 2272 | nfs_free_fhandle(mntfh); |
| 2251 | kfree(data); | 2273 | kfree(data); |
| 2252 | return error; | 2274 | return error; |
| 2253 | 2275 | ||
| @@ -2556,7 +2578,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
| 2556 | }; | 2578 | }; |
| 2557 | int error = -ENOMEM; | 2579 | int error = -ENOMEM; |
| 2558 | 2580 | ||
| 2559 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2581 | mntfh = nfs_alloc_fhandle(); |
| 2560 | if (data == NULL || mntfh == NULL) | 2582 | if (data == NULL || mntfh == NULL) |
| 2561 | goto out_free_fh; | 2583 | goto out_free_fh; |
| 2562 | 2584 | ||
| @@ -2614,7 +2636,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
| 2614 | out: | 2636 | out: |
| 2615 | security_free_mnt_opts(&data->lsm_opts); | 2637 | security_free_mnt_opts(&data->lsm_opts); |
| 2616 | out_free_fh: | 2638 | out_free_fh: |
| 2617 | kfree(mntfh); | 2639 | nfs_free_fhandle(mntfh); |
| 2618 | return error; | 2640 | return error; |
| 2619 | 2641 | ||
| 2620 | out_free: | 2642 | out_free: |
| @@ -2669,41 +2691,120 @@ out_freepage: | |||
| 2669 | free_page((unsigned long)page); | 2691 | free_page((unsigned long)page); |
| 2670 | } | 2692 | } |
| 2671 | 2693 | ||
| 2694 | struct nfs_referral_count { | ||
| 2695 | struct list_head list; | ||
| 2696 | const struct task_struct *task; | ||
| 2697 | unsigned int referral_count; | ||
| 2698 | }; | ||
| 2699 | |||
| 2700 | static LIST_HEAD(nfs_referral_count_list); | ||
| 2701 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
| 2702 | |||
| 2703 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
| 2704 | { | ||
| 2705 | struct nfs_referral_count *p; | ||
| 2706 | |||
| 2707 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
| 2708 | if (p->task == current) | ||
| 2709 | return p; | ||
| 2710 | } | ||
| 2711 | return NULL; | ||
| 2712 | } | ||
| 2713 | |||
| 2714 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
| 2715 | |||
| 2716 | static int nfs_referral_loop_protect(void) | ||
| 2717 | { | ||
| 2718 | struct nfs_referral_count *p, *new; | ||
| 2719 | int ret = -ENOMEM; | ||
| 2720 | |||
| 2721 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
| 2722 | if (!new) | ||
| 2723 | goto out; | ||
| 2724 | new->task = current; | ||
| 2725 | new->referral_count = 1; | ||
| 2726 | |||
| 2727 | ret = 0; | ||
| 2728 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2729 | p = nfs_find_referral_count(); | ||
| 2730 | if (p != NULL) { | ||
| 2731 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
| 2732 | ret = -ELOOP; | ||
| 2733 | else | ||
| 2734 | p->referral_count++; | ||
| 2735 | } else { | ||
| 2736 | list_add(&new->list, &nfs_referral_count_list); | ||
| 2737 | new = NULL; | ||
| 2738 | } | ||
| 2739 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2740 | kfree(new); | ||
| 2741 | out: | ||
| 2742 | return ret; | ||
| 2743 | } | ||
| 2744 | |||
| 2745 | static void nfs_referral_loop_unprotect(void) | ||
| 2746 | { | ||
| 2747 | struct nfs_referral_count *p; | ||
| 2748 | |||
| 2749 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2750 | p = nfs_find_referral_count(); | ||
| 2751 | p->referral_count--; | ||
| 2752 | if (p->referral_count == 0) | ||
| 2753 | list_del(&p->list); | ||
| 2754 | else | ||
| 2755 | p = NULL; | ||
| 2756 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2757 | kfree(p); | ||
| 2758 | } | ||
| 2759 | |||
| 2672 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | 2760 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, |
| 2673 | const char *export_path, struct vfsmount *mnt_target) | 2761 | const char *export_path, struct vfsmount *mnt_target) |
| 2674 | { | 2762 | { |
| 2763 | struct nameidata *nd = NULL; | ||
| 2675 | struct mnt_namespace *ns_private; | 2764 | struct mnt_namespace *ns_private; |
| 2676 | struct nameidata nd; | ||
| 2677 | struct super_block *s; | 2765 | struct super_block *s; |
| 2678 | int ret; | 2766 | int ret; |
| 2679 | 2767 | ||
| 2768 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | ||
| 2769 | if (nd == NULL) | ||
| 2770 | return -ENOMEM; | ||
| 2771 | |||
| 2680 | ns_private = create_mnt_ns(root_mnt); | 2772 | ns_private = create_mnt_ns(root_mnt); |
| 2681 | ret = PTR_ERR(ns_private); | 2773 | ret = PTR_ERR(ns_private); |
| 2682 | if (IS_ERR(ns_private)) | 2774 | if (IS_ERR(ns_private)) |
| 2683 | goto out_mntput; | 2775 | goto out_mntput; |
| 2684 | 2776 | ||
| 2777 | ret = nfs_referral_loop_protect(); | ||
| 2778 | if (ret != 0) | ||
| 2779 | goto out_put_mnt_ns; | ||
| 2780 | |||
| 2685 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | 2781 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, |
| 2686 | export_path, LOOKUP_FOLLOW, &nd); | 2782 | export_path, LOOKUP_FOLLOW, nd); |
| 2687 | 2783 | ||
| 2784 | nfs_referral_loop_unprotect(); | ||
| 2688 | put_mnt_ns(ns_private); | 2785 | put_mnt_ns(ns_private); |
| 2689 | 2786 | ||
| 2690 | if (ret != 0) | 2787 | if (ret != 0) |
| 2691 | goto out_err; | 2788 | goto out_err; |
| 2692 | 2789 | ||
| 2693 | s = nd.path.mnt->mnt_sb; | 2790 | s = nd->path.mnt->mnt_sb; |
| 2694 | atomic_inc(&s->s_active); | 2791 | atomic_inc(&s->s_active); |
| 2695 | mnt_target->mnt_sb = s; | 2792 | mnt_target->mnt_sb = s; |
| 2696 | mnt_target->mnt_root = dget(nd.path.dentry); | 2793 | mnt_target->mnt_root = dget(nd->path.dentry); |
| 2697 | 2794 | ||
| 2698 | /* Correct the device pathname */ | 2795 | /* Correct the device pathname */ |
| 2699 | nfs_fix_devname(&nd.path, mnt_target); | 2796 | nfs_fix_devname(&nd->path, mnt_target); |
| 2700 | 2797 | ||
| 2701 | path_put(&nd.path); | 2798 | path_put(&nd->path); |
| 2799 | kfree(nd); | ||
| 2702 | down_write(&s->s_umount); | 2800 | down_write(&s->s_umount); |
| 2703 | return 0; | 2801 | return 0; |
| 2802 | out_put_mnt_ns: | ||
| 2803 | put_mnt_ns(ns_private); | ||
| 2704 | out_mntput: | 2804 | out_mntput: |
| 2705 | mntput(root_mnt); | 2805 | mntput(root_mnt); |
| 2706 | out_err: | 2806 | out_err: |
| 2807 | kfree(nd); | ||
| 2707 | return ret; | 2808 | return ret; |
| 2708 | } | 2809 | } |
| 2709 | 2810 | ||
| @@ -2874,17 +2975,21 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2874 | struct super_block *s; | 2975 | struct super_block *s; |
| 2875 | struct nfs_server *server; | 2976 | struct nfs_server *server; |
| 2876 | struct dentry *mntroot; | 2977 | struct dentry *mntroot; |
| 2877 | struct nfs_fh mntfh; | 2978 | struct nfs_fh *mntfh; |
| 2878 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2979 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
| 2879 | struct nfs_sb_mountdata sb_mntdata = { | 2980 | struct nfs_sb_mountdata sb_mntdata = { |
| 2880 | .mntflags = flags, | 2981 | .mntflags = flags, |
| 2881 | }; | 2982 | }; |
| 2882 | int error; | 2983 | int error = -ENOMEM; |
| 2883 | 2984 | ||
| 2884 | dprintk("--> nfs4_referral_get_sb()\n"); | 2985 | dprintk("--> nfs4_referral_get_sb()\n"); |
| 2885 | 2986 | ||
| 2987 | mntfh = nfs_alloc_fhandle(); | ||
| 2988 | if (mntfh == NULL) | ||
| 2989 | goto out_err_nofh; | ||
| 2990 | |||
| 2886 | /* create a new volume representation */ | 2991 | /* create a new volume representation */ |
| 2887 | server = nfs4_create_referral_server(data, &mntfh); | 2992 | server = nfs4_create_referral_server(data, mntfh); |
| 2888 | if (IS_ERR(server)) { | 2993 | if (IS_ERR(server)) { |
| 2889 | error = PTR_ERR(server); | 2994 | error = PTR_ERR(server); |
| 2890 | goto out_err_noserver; | 2995 | goto out_err_noserver; |
| @@ -2916,7 +3021,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2916 | nfs_fscache_get_super_cookie(s, NULL, data); | 3021 | nfs_fscache_get_super_cookie(s, NULL, data); |
| 2917 | } | 3022 | } |
| 2918 | 3023 | ||
| 2919 | mntroot = nfs4_get_root(s, &mntfh); | 3024 | mntroot = nfs4_get_root(s, mntfh); |
| 2920 | if (IS_ERR(mntroot)) { | 3025 | if (IS_ERR(mntroot)) { |
| 2921 | error = PTR_ERR(mntroot); | 3026 | error = PTR_ERR(mntroot); |
| 2922 | goto error_splat_super; | 3027 | goto error_splat_super; |
| @@ -2933,12 +3038,15 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
| 2933 | 3038 | ||
| 2934 | security_sb_clone_mnt_opts(data->sb, s); | 3039 | security_sb_clone_mnt_opts(data->sb, s); |
| 2935 | 3040 | ||
| 3041 | nfs_free_fhandle(mntfh); | ||
| 2936 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); | 3042 | dprintk("<-- nfs4_referral_get_sb() = 0\n"); |
| 2937 | return 0; | 3043 | return 0; |
| 2938 | 3044 | ||
| 2939 | out_err_nosb: | 3045 | out_err_nosb: |
| 2940 | nfs_free_server(server); | 3046 | nfs_free_server(server); |
| 2941 | out_err_noserver: | 3047 | out_err_noserver: |
| 3048 | nfs_free_fhandle(mntfh); | ||
| 3049 | out_err_nofh: | ||
| 2942 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); | 3050 | dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error); |
| 2943 | return error; | 3051 | return error; |
| 2944 | 3052 | ||
| @@ -2947,6 +3055,7 @@ error_splat_super: | |||
| 2947 | bdi_unregister(&server->backing_dev_info); | 3055 | bdi_unregister(&server->backing_dev_info); |
| 2948 | error_splat_bdi: | 3056 | error_splat_bdi: |
| 2949 | deactivate_locked_super(s); | 3057 | deactivate_locked_super(s); |
| 3058 | nfs_free_fhandle(mntfh); | ||
| 2950 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | 3059 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); |
| 2951 | return error; | 3060 | return error; |
| 2952 | } | 3061 | } |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 6da3d3ff6edd..2f84adaad427 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 | /** |
| @@ -109,7 +110,7 @@ void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | |||
| 109 | struct nfs_unlinkdata *data = calldata; | 110 | struct nfs_unlinkdata *data = calldata; |
| 110 | struct nfs_server *server = NFS_SERVER(data->dir); | 111 | struct nfs_server *server = NFS_SERVER(data->dir); |
| 111 | 112 | ||
| 112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | 113 | if (nfs4_setup_sequence(server, &data->args.seq_args, |
| 113 | &data->res.seq_res, 1, task)) | 114 | &data->res.seq_res, 1, task)) |
| 114 | return; | 115 | return; |
| 115 | rpc_call_start(task); | 116 | rpc_call_start(task); |
| @@ -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/fs/nfs/write.c b/fs/nfs/write.c index 3aea3ca98ab7..874972d9427c 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -222,7 +222,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
| 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page) | 225 | static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock) |
| 226 | { | 226 | { |
| 227 | struct inode *inode = page->mapping->host; | 227 | struct inode *inode = page->mapping->host; |
| 228 | struct nfs_page *req; | 228 | struct nfs_page *req; |
| @@ -241,7 +241,10 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
| 241 | * request as dirty (in which case we don't care). | 241 | * request as dirty (in which case we don't care). |
| 242 | */ | 242 | */ |
| 243 | spin_unlock(&inode->i_lock); | 243 | spin_unlock(&inode->i_lock); |
| 244 | ret = nfs_wait_on_request(req); | 244 | if (!nonblock) |
| 245 | ret = nfs_wait_on_request(req); | ||
| 246 | else | ||
| 247 | ret = -EAGAIN; | ||
| 245 | nfs_release_request(req); | 248 | nfs_release_request(req); |
| 246 | if (ret != 0) | 249 | if (ret != 0) |
| 247 | return ERR_PTR(ret); | 250 | return ERR_PTR(ret); |
| @@ -256,12 +259,12 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page) | |||
| 256 | * May return an error if the user signalled nfs_wait_on_request(). | 259 | * May return an error if the user signalled nfs_wait_on_request(). |
| 257 | */ | 260 | */ |
| 258 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | 261 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
| 259 | struct page *page) | 262 | struct page *page, bool nonblock) |
| 260 | { | 263 | { |
| 261 | struct nfs_page *req; | 264 | struct nfs_page *req; |
| 262 | int ret = 0; | 265 | int ret = 0; |
| 263 | 266 | ||
| 264 | req = nfs_find_and_lock_request(page); | 267 | req = nfs_find_and_lock_request(page, nonblock); |
| 265 | if (!req) | 268 | if (!req) |
| 266 | goto out; | 269 | goto out; |
| 267 | ret = PTR_ERR(req); | 270 | ret = PTR_ERR(req); |
| @@ -283,12 +286,20 @@ out: | |||
| 283 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) | 286 | static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio) |
| 284 | { | 287 | { |
| 285 | struct inode *inode = page->mapping->host; | 288 | struct inode *inode = page->mapping->host; |
| 289 | int ret; | ||
| 286 | 290 | ||
| 287 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 291 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
| 288 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 292 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
| 289 | 293 | ||
| 290 | nfs_pageio_cond_complete(pgio, page->index); | 294 | nfs_pageio_cond_complete(pgio, page->index); |
| 291 | return nfs_page_async_flush(pgio, page); | 295 | ret = nfs_page_async_flush(pgio, page, |
| 296 | wbc->sync_mode == WB_SYNC_NONE || | ||
| 297 | wbc->nonblocking != 0); | ||
| 298 | if (ret == -EAGAIN) { | ||
| 299 | redirty_page_for_writepage(wbc, page); | ||
| 300 | ret = 0; | ||
| 301 | } | ||
| 302 | return ret; | ||
| 292 | } | 303 | } |
| 293 | 304 | ||
| 294 | /* | 305 | /* |
| @@ -689,7 +700,9 @@ int nfs_flush_incompatible(struct file *file, struct page *page) | |||
| 689 | req = nfs_page_find_request(page); | 700 | req = nfs_page_find_request(page); |
| 690 | if (req == NULL) | 701 | if (req == NULL) |
| 691 | return 0; | 702 | return 0; |
| 692 | do_flush = req->wb_page != page || req->wb_context != ctx; | 703 | do_flush = req->wb_page != page || req->wb_context != ctx || |
| 704 | req->wb_lock_context->lockowner != current->files || | ||
| 705 | req->wb_lock_context->pid != current->tgid; | ||
| 693 | nfs_release_request(req); | 706 | nfs_release_request(req); |
| 694 | if (!do_flush) | 707 | if (!do_flush) |
| 695 | return 0; | 708 | return 0; |
| @@ -813,6 +826,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
| 813 | data->args.pages = data->pagevec; | 826 | data->args.pages = data->pagevec; |
| 814 | data->args.count = count; | 827 | data->args.count = count; |
| 815 | data->args.context = get_nfs_open_context(req->wb_context); | 828 | data->args.context = get_nfs_open_context(req->wb_context); |
| 829 | data->args.lock_context = req->wb_lock_context; | ||
| 816 | data->args.stable = NFS_UNSTABLE; | 830 | data->args.stable = NFS_UNSTABLE; |
| 817 | if (how & FLUSH_STABLE) { | 831 | if (how & FLUSH_STABLE) { |
| 818 | data->args.stable = NFS_DATA_SYNC; | 832 | data->args.stable = NFS_DATA_SYNC; |
| @@ -1036,9 +1050,9 @@ out: | |||
| 1036 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | 1050 | void nfs_write_prepare(struct rpc_task *task, void *calldata) |
| 1037 | { | 1051 | { |
| 1038 | struct nfs_write_data *data = calldata; | 1052 | struct nfs_write_data *data = calldata; |
| 1039 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
| 1040 | 1053 | ||
| 1041 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | 1054 | if (nfs4_setup_sequence(NFS_SERVER(data->inode), |
| 1055 | &data->args.seq_args, | ||
| 1042 | &data->res.seq_res, 1, task)) | 1056 | &data->res.seq_res, 1, task)) |
| 1043 | return; | 1057 | return; |
| 1044 | rpc_call_start(task); | 1058 | rpc_call_start(task); |
| @@ -1379,14 +1393,14 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
| 1379 | .rpc_release = nfs_commit_release, | 1393 | .rpc_release = nfs_commit_release, |
| 1380 | }; | 1394 | }; |
| 1381 | 1395 | ||
| 1382 | static int nfs_commit_inode(struct inode *inode, int how) | 1396 | int nfs_commit_inode(struct inode *inode, int how) |
| 1383 | { | 1397 | { |
| 1384 | LIST_HEAD(head); | 1398 | LIST_HEAD(head); |
| 1385 | int may_wait = how & FLUSH_SYNC; | 1399 | int may_wait = how & FLUSH_SYNC; |
| 1386 | int res = 0; | 1400 | int res = 0; |
| 1387 | 1401 | ||
| 1388 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | 1402 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) |
| 1389 | goto out; | 1403 | goto out_mark_dirty; |
| 1390 | spin_lock(&inode->i_lock); | 1404 | spin_lock(&inode->i_lock); |
| 1391 | res = nfs_scan_commit(inode, &head, 0, 0); | 1405 | res = nfs_scan_commit(inode, &head, 0, 0); |
| 1392 | spin_unlock(&inode->i_lock); | 1406 | spin_unlock(&inode->i_lock); |
| @@ -1398,9 +1412,18 @@ static int nfs_commit_inode(struct inode *inode, int how) | |||
| 1398 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | 1412 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, |
| 1399 | nfs_wait_bit_killable, | 1413 | nfs_wait_bit_killable, |
| 1400 | TASK_KILLABLE); | 1414 | TASK_KILLABLE); |
| 1415 | else | ||
| 1416 | goto out_mark_dirty; | ||
| 1401 | } else | 1417 | } else |
| 1402 | nfs_commit_clear_lock(NFS_I(inode)); | 1418 | nfs_commit_clear_lock(NFS_I(inode)); |
| 1403 | out: | 1419 | return res; |
| 1420 | /* Note: If we exit without ensuring that the commit is complete, | ||
| 1421 | * we must mark the inode as dirty. Otherwise, future calls to | ||
| 1422 | * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure | ||
| 1423 | * that the data is on the disk. | ||
| 1424 | */ | ||
| 1425 | out_mark_dirty: | ||
| 1426 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
| 1404 | return res; | 1427 | return res; |
| 1405 | } | 1428 | } |
| 1406 | 1429 | ||
| @@ -1434,11 +1457,6 @@ out_mark_dirty: | |||
| 1434 | return ret; | 1457 | return ret; |
| 1435 | } | 1458 | } |
| 1436 | #else | 1459 | #else |
| 1437 | static int nfs_commit_inode(struct inode *inode, int how) | ||
| 1438 | { | ||
| 1439 | return 0; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) | 1460 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
| 1443 | { | 1461 | { |
| 1444 | return 0; | 1462 | return 0; |
| @@ -1509,14 +1527,17 @@ int nfs_wb_page(struct inode *inode, struct page *page) | |||
| 1509 | }; | 1527 | }; |
| 1510 | int ret; | 1528 | int ret; |
| 1511 | 1529 | ||
| 1512 | while(PagePrivate(page)) { | 1530 | for (;;) { |
| 1513 | wait_on_page_writeback(page); | 1531 | wait_on_page_writeback(page); |
| 1514 | if (clear_page_dirty_for_io(page)) { | 1532 | if (clear_page_dirty_for_io(page)) { |
| 1515 | ret = nfs_writepage_locked(page, &wbc); | 1533 | ret = nfs_writepage_locked(page, &wbc); |
| 1516 | if (ret < 0) | 1534 | if (ret < 0) |
| 1517 | goto out_error; | 1535 | goto out_error; |
| 1536 | continue; | ||
| 1518 | } | 1537 | } |
| 1519 | ret = sync_inode(inode, &wbc); | 1538 | if (!PagePrivate(page)) |
| 1539 | break; | ||
| 1540 | ret = nfs_commit_inode(inode, FLUSH_SYNC); | ||
| 1520 | if (ret < 0) | 1541 | if (ret < 0) |
| 1521 | goto out_error; | 1542 | goto out_error; |
| 1522 | } | 1543 | } |
| @@ -1534,7 +1555,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
| 1534 | 1555 | ||
| 1535 | nfs_fscache_release_page(page, GFP_KERNEL); | 1556 | nfs_fscache_release_page(page, GFP_KERNEL); |
| 1536 | 1557 | ||
| 1537 | req = nfs_find_and_lock_request(page); | 1558 | req = nfs_find_and_lock_request(page, false); |
| 1538 | ret = PTR_ERR(req); | 1559 | ret = PTR_ERR(req); |
| 1539 | if (IS_ERR(req)) | 1560 | if (IS_ERR(req)) |
| 1540 | goto out; | 1561 | goto out; |
