diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-28 11:46:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-28 11:46:44 -0500 |
commit | 2b2b15c32ae951c3609c01e74d22d6de64b2595c (patch) | |
tree | f23a1e0f6929312cc9b7f742dffc2a4999283c06 /net | |
parent | bf3d846b783327359ddc4bd4f52627b36abb4d1d (diff) | |
parent | ed7e5423014ad89720fcf315c0b73f2c5d0c7bd2 (diff) |
Merge tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
- stable fix for an infinite loop in RPC state machine
- stable fix for a use after free situation in the NFSv4 trunking discovery
- stable fix for error handling in the NFSv4 trunking discovery
- stable fix for the page write update code
- stable fix for the NFSv4.1 mount time security negotiation
- stable fix for the NFSv4 open code.
- O_DIRECT locking fixes
- fix an Oops in the pnfs file commit code
- RPC layer needs finer grained handling of connection errors
- more RPC GSS upcall fixes"
* tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (30 commits)
pnfs: Proper delay for NFS4ERR_RECALLCONFLICT in layout_get_done
pnfs: fix BUG in filelayout_recover_commit_reqs
nfs4: fix discover_server_trunking use after free
NFSv4.1: Handle errors correctly in nfs41_walk_client_list
nfs: always make sure page is up-to-date before extending a write to cover the entire page
nfs: page cache invalidation for dio
nfs: take i_mutex during direct I/O reads
nfs: merge nfs_direct_write into nfs_file_direct_write
nfs: merge nfs_direct_read into nfs_file_direct_read
nfs: increment i_dio_count for reads, too
nfs: defer inode_dio_done call until size update is done
nfs: fix size updates for aio writes
nfs4.1: properly handle ENOTSUP in SECINFO_NO_NAME
NFSv4.1: Fix a race in nfs4_write_inode
NFSv4.1: Don't trust attributes if a pNFS LAYOUTCOMMIT is outstanding
point to the right include file in a comment (left over from a9004abc3)
NFS: dprintk() should not print negative fileids and inode numbers
nfs: fix dead code of ipv6_addr_scope
sunrpc: Fix infinite loop in RPC state machine
SUNRPC: Add tracepoint for socket errors
...
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 17 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 15 | ||||
-rw-r--r-- | net/sunrpc/netns.h | 3 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 169 | ||||
-rw-r--r-- | net/sunrpc/sunrpc_syms.c | 8 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 5 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 42 |
7 files changed, 231 insertions, 28 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 42fdfc634e56..0a2aee060f9f 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -536,8 +536,7 @@ static void warn_gssd(void) | |||
536 | unsigned long now = jiffies; | 536 | unsigned long now = jiffies; |
537 | 537 | ||
538 | if (time_after(now, ratelimit)) { | 538 | if (time_after(now, ratelimit)) { |
539 | printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" | 539 | pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n"); |
540 | "Please check user daemon is running.\n"); | ||
541 | ratelimit = now + 15*HZ; | 540 | ratelimit = now + 15*HZ; |
542 | } | 541 | } |
543 | } | 542 | } |
@@ -600,7 +599,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
600 | struct rpc_pipe *pipe; | 599 | struct rpc_pipe *pipe; |
601 | struct rpc_cred *cred = &gss_cred->gc_base; | 600 | struct rpc_cred *cred = &gss_cred->gc_base; |
602 | struct gss_upcall_msg *gss_msg; | 601 | struct gss_upcall_msg *gss_msg; |
603 | unsigned long timeout; | ||
604 | DEFINE_WAIT(wait); | 602 | DEFINE_WAIT(wait); |
605 | int err; | 603 | int err; |
606 | 604 | ||
@@ -608,17 +606,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
608 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 606 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
609 | retry: | 607 | retry: |
610 | err = 0; | 608 | err = 0; |
611 | /* Default timeout is 15s unless we know that gssd is not running */ | 609 | /* if gssd is down, just skip upcalling altogether */ |
612 | timeout = 15 * HZ; | 610 | if (!gssd_running(net)) { |
613 | if (!sn->gssd_running) | 611 | warn_gssd(); |
614 | timeout = HZ >> 2; | 612 | return -EACCES; |
613 | } | ||
615 | gss_msg = gss_setup_upcall(gss_auth, cred); | 614 | gss_msg = gss_setup_upcall(gss_auth, cred); |
616 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 615 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
617 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 616 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
618 | sn->pipe_version >= 0, timeout); | 617 | sn->pipe_version >= 0, 15 * HZ); |
619 | if (sn->pipe_version < 0) { | 618 | if (sn->pipe_version < 0) { |
620 | if (err == 0) | ||
621 | sn->gssd_running = 0; | ||
622 | warn_gssd(); | 619 | warn_gssd(); |
623 | err = -EACCES; | 620 | err = -EACCES; |
624 | } | 621 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index f09b7db2c492..0edada973434 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1529,9 +1529,13 @@ call_refreshresult(struct rpc_task *task) | |||
1529 | task->tk_action = call_refresh; | 1529 | task->tk_action = call_refresh; |
1530 | switch (status) { | 1530 | switch (status) { |
1531 | case 0: | 1531 | case 0: |
1532 | if (rpcauth_uptodatecred(task)) | 1532 | if (rpcauth_uptodatecred(task)) { |
1533 | task->tk_action = call_allocate; | 1533 | task->tk_action = call_allocate; |
1534 | return; | 1534 | return; |
1535 | } | ||
1536 | /* Use rate-limiting and a max number of retries if refresh | ||
1537 | * had status 0 but failed to update the cred. | ||
1538 | */ | ||
1535 | case -ETIMEDOUT: | 1539 | case -ETIMEDOUT: |
1536 | rpc_delay(task, 3*HZ); | 1540 | rpc_delay(task, 3*HZ); |
1537 | case -EAGAIN: | 1541 | case -EAGAIN: |
@@ -1729,6 +1733,7 @@ call_bind_status(struct rpc_task *task) | |||
1729 | return; | 1733 | return; |
1730 | case -ECONNREFUSED: /* connection problems */ | 1734 | case -ECONNREFUSED: /* connection problems */ |
1731 | case -ECONNRESET: | 1735 | case -ECONNRESET: |
1736 | case -ECONNABORTED: | ||
1732 | case -ENOTCONN: | 1737 | case -ENOTCONN: |
1733 | case -EHOSTDOWN: | 1738 | case -EHOSTDOWN: |
1734 | case -EHOSTUNREACH: | 1739 | case -EHOSTUNREACH: |
@@ -1799,7 +1804,9 @@ call_connect_status(struct rpc_task *task) | |||
1799 | return; | 1804 | return; |
1800 | case -ECONNREFUSED: | 1805 | case -ECONNREFUSED: |
1801 | case -ECONNRESET: | 1806 | case -ECONNRESET: |
1807 | case -ECONNABORTED: | ||
1802 | case -ENETUNREACH: | 1808 | case -ENETUNREACH: |
1809 | case -EHOSTUNREACH: | ||
1803 | /* retry with existing socket, after a delay */ | 1810 | /* retry with existing socket, after a delay */ |
1804 | rpc_delay(task, 3*HZ); | 1811 | rpc_delay(task, 3*HZ); |
1805 | if (RPC_IS_SOFTCONN(task)) | 1812 | if (RPC_IS_SOFTCONN(task)) |
@@ -1902,6 +1909,7 @@ call_transmit_status(struct rpc_task *task) | |||
1902 | break; | 1909 | break; |
1903 | } | 1910 | } |
1904 | case -ECONNRESET: | 1911 | case -ECONNRESET: |
1912 | case -ECONNABORTED: | ||
1905 | case -ENOTCONN: | 1913 | case -ENOTCONN: |
1906 | case -EPIPE: | 1914 | case -EPIPE: |
1907 | rpc_task_force_reencode(task); | 1915 | rpc_task_force_reencode(task); |
@@ -2011,8 +2019,9 @@ call_status(struct rpc_task *task) | |||
2011 | xprt_conditional_disconnect(req->rq_xprt, | 2019 | xprt_conditional_disconnect(req->rq_xprt, |
2012 | req->rq_connect_cookie); | 2020 | req->rq_connect_cookie); |
2013 | break; | 2021 | break; |
2014 | case -ECONNRESET: | ||
2015 | case -ECONNREFUSED: | 2022 | case -ECONNREFUSED: |
2023 | case -ECONNRESET: | ||
2024 | case -ECONNABORTED: | ||
2016 | rpc_force_rebind(clnt); | 2025 | rpc_force_rebind(clnt); |
2017 | rpc_delay(task, 3*HZ); | 2026 | rpc_delay(task, 3*HZ); |
2018 | case -EPIPE: | 2027 | case -EPIPE: |
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 779742cfc1ff..94e506f9d72b 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
@@ -14,6 +14,7 @@ struct sunrpc_net { | |||
14 | struct cache_detail *rsi_cache; | 14 | struct cache_detail *rsi_cache; |
15 | 15 | ||
16 | struct super_block *pipefs_sb; | 16 | struct super_block *pipefs_sb; |
17 | struct rpc_pipe *gssd_dummy; | ||
17 | struct mutex pipefs_sb_lock; | 18 | struct mutex pipefs_sb_lock; |
18 | 19 | ||
19 | struct list_head all_clients; | 20 | struct list_head all_clients; |
@@ -32,8 +33,6 @@ struct sunrpc_net { | |||
32 | int pipe_version; | 33 | int pipe_version; |
33 | atomic_t pipe_users; | 34 | atomic_t pipe_users; |
34 | struct proc_dir_entry *use_gssp_proc; | 35 | struct proc_dir_entry *use_gssp_proc; |
35 | |||
36 | unsigned int gssd_running; | ||
37 | }; | 36 | }; |
38 | 37 | ||
39 | extern int sunrpc_net_id; | 38 | extern int sunrpc_net_id; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index bf04b30a788a..b18554898562 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fsnotify.h> | 17 | #include <linux/fsnotify.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/rcupdate.h> | 19 | #include <linux/rcupdate.h> |
20 | #include <linux/utsname.h> | ||
20 | 21 | ||
21 | #include <asm/ioctls.h> | 22 | #include <asm/ioctls.h> |
22 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
@@ -38,7 +39,7 @@ | |||
38 | #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") | 39 | #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") |
39 | 40 | ||
40 | static struct file_system_type rpc_pipe_fs_type; | 41 | static struct file_system_type rpc_pipe_fs_type; |
41 | 42 | static const struct rpc_pipe_ops gssd_dummy_pipe_ops; | |
42 | 43 | ||
43 | static struct kmem_cache *rpc_inode_cachep __read_mostly; | 44 | static struct kmem_cache *rpc_inode_cachep __read_mostly; |
44 | 45 | ||
@@ -216,14 +217,11 @@ rpc_destroy_inode(struct inode *inode) | |||
216 | static int | 217 | static int |
217 | rpc_pipe_open(struct inode *inode, struct file *filp) | 218 | rpc_pipe_open(struct inode *inode, struct file *filp) |
218 | { | 219 | { |
219 | struct net *net = inode->i_sb->s_fs_info; | ||
220 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
221 | struct rpc_pipe *pipe; | 220 | struct rpc_pipe *pipe; |
222 | int first_open; | 221 | int first_open; |
223 | int res = -ENXIO; | 222 | int res = -ENXIO; |
224 | 223 | ||
225 | mutex_lock(&inode->i_mutex); | 224 | mutex_lock(&inode->i_mutex); |
226 | sn->gssd_running = 1; | ||
227 | pipe = RPC_I(inode)->pipe; | 225 | pipe = RPC_I(inode)->pipe; |
228 | if (pipe == NULL) | 226 | if (pipe == NULL) |
229 | goto out; | 227 | goto out; |
@@ -1159,6 +1157,7 @@ enum { | |||
1159 | RPCAUTH_nfsd4_cb, | 1157 | RPCAUTH_nfsd4_cb, |
1160 | RPCAUTH_cache, | 1158 | RPCAUTH_cache, |
1161 | RPCAUTH_nfsd, | 1159 | RPCAUTH_nfsd, |
1160 | RPCAUTH_gssd, | ||
1162 | RPCAUTH_RootEOF | 1161 | RPCAUTH_RootEOF |
1163 | }; | 1162 | }; |
1164 | 1163 | ||
@@ -1195,6 +1194,10 @@ static const struct rpc_filelist files[] = { | |||
1195 | .name = "nfsd", | 1194 | .name = "nfsd", |
1196 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | 1195 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, |
1197 | }, | 1196 | }, |
1197 | [RPCAUTH_gssd] = { | ||
1198 | .name = "gssd", | ||
1199 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
1200 | }, | ||
1198 | }; | 1201 | }; |
1199 | 1202 | ||
1200 | /* | 1203 | /* |
@@ -1208,13 +1211,24 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb, | |||
1208 | } | 1211 | } |
1209 | EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); | 1212 | EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); |
1210 | 1213 | ||
1211 | void rpc_pipefs_init_net(struct net *net) | 1214 | int rpc_pipefs_init_net(struct net *net) |
1212 | { | 1215 | { |
1213 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1216 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1214 | 1217 | ||
1218 | sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); | ||
1219 | if (IS_ERR(sn->gssd_dummy)) | ||
1220 | return PTR_ERR(sn->gssd_dummy); | ||
1221 | |||
1215 | mutex_init(&sn->pipefs_sb_lock); | 1222 | mutex_init(&sn->pipefs_sb_lock); |
1216 | sn->gssd_running = 1; | ||
1217 | sn->pipe_version = -1; | 1223 | sn->pipe_version = -1; |
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | void rpc_pipefs_exit_net(struct net *net) | ||
1228 | { | ||
1229 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
1230 | |||
1231 | rpc_destroy_pipe_data(sn->gssd_dummy); | ||
1218 | } | 1232 | } |
1219 | 1233 | ||
1220 | /* | 1234 | /* |
@@ -1244,11 +1258,134 @@ void rpc_put_sb_net(const struct net *net) | |||
1244 | } | 1258 | } |
1245 | EXPORT_SYMBOL_GPL(rpc_put_sb_net); | 1259 | EXPORT_SYMBOL_GPL(rpc_put_sb_net); |
1246 | 1260 | ||
1261 | static const struct rpc_filelist gssd_dummy_clnt_dir[] = { | ||
1262 | [0] = { | ||
1263 | .name = "clntXX", | ||
1264 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
1265 | }, | ||
1266 | }; | ||
1267 | |||
1268 | static ssize_t | ||
1269 | dummy_downcall(struct file *filp, const char __user *src, size_t len) | ||
1270 | { | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | static const struct rpc_pipe_ops gssd_dummy_pipe_ops = { | ||
1275 | .upcall = rpc_pipe_generic_upcall, | ||
1276 | .downcall = dummy_downcall, | ||
1277 | }; | ||
1278 | |||
1279 | /* | ||
1280 | * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect | ||
1281 | * that it will ever use this info to handle an upcall, but rpc.gssd expects | ||
1282 | * that this file will be there and have a certain format. | ||
1283 | */ | ||
1284 | static int | ||
1285 | rpc_show_dummy_info(struct seq_file *m, void *v) | ||
1286 | { | ||
1287 | seq_printf(m, "RPC server: %s\n", utsname()->nodename); | ||
1288 | seq_printf(m, "service: foo (1) version 0\n"); | ||
1289 | seq_printf(m, "address: 127.0.0.1\n"); | ||
1290 | seq_printf(m, "protocol: tcp\n"); | ||
1291 | seq_printf(m, "port: 0\n"); | ||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | static int | ||
1296 | rpc_dummy_info_open(struct inode *inode, struct file *file) | ||
1297 | { | ||
1298 | return single_open(file, rpc_show_dummy_info, NULL); | ||
1299 | } | ||
1300 | |||
1301 | static const struct file_operations rpc_dummy_info_operations = { | ||
1302 | .owner = THIS_MODULE, | ||
1303 | .open = rpc_dummy_info_open, | ||
1304 | .read = seq_read, | ||
1305 | .llseek = seq_lseek, | ||
1306 | .release = single_release, | ||
1307 | }; | ||
1308 | |||
1309 | static const struct rpc_filelist gssd_dummy_info_file[] = { | ||
1310 | [0] = { | ||
1311 | .name = "info", | ||
1312 | .i_fop = &rpc_dummy_info_operations, | ||
1313 | .mode = S_IFREG | S_IRUSR, | ||
1314 | }, | ||
1315 | }; | ||
1316 | |||
1317 | /** | ||
1318 | * rpc_gssd_dummy_populate - create a dummy gssd pipe | ||
1319 | * @root: root of the rpc_pipefs filesystem | ||
1320 | * @pipe_data: pipe data created when netns is initialized | ||
1321 | * | ||
1322 | * Create a dummy set of directories and a pipe that gssd can hold open to | ||
1323 | * indicate that it is up and running. | ||
1324 | */ | ||
1325 | static struct dentry * | ||
1326 | rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data) | ||
1327 | { | ||
1328 | int ret = 0; | ||
1329 | struct dentry *gssd_dentry; | ||
1330 | struct dentry *clnt_dentry = NULL; | ||
1331 | struct dentry *pipe_dentry = NULL; | ||
1332 | struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name, | ||
1333 | strlen(files[RPCAUTH_gssd].name)); | ||
1334 | |||
1335 | /* We should never get this far if "gssd" doesn't exist */ | ||
1336 | gssd_dentry = d_hash_and_lookup(root, &q); | ||
1337 | if (!gssd_dentry) | ||
1338 | return ERR_PTR(-ENOENT); | ||
1339 | |||
1340 | ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL); | ||
1341 | if (ret) { | ||
1342 | pipe_dentry = ERR_PTR(ret); | ||
1343 | goto out; | ||
1344 | } | ||
1345 | |||
1346 | q.name = gssd_dummy_clnt_dir[0].name; | ||
1347 | q.len = strlen(gssd_dummy_clnt_dir[0].name); | ||
1348 | clnt_dentry = d_hash_and_lookup(gssd_dentry, &q); | ||
1349 | if (!clnt_dentry) { | ||
1350 | pipe_dentry = ERR_PTR(-ENOENT); | ||
1351 | goto out; | ||
1352 | } | ||
1353 | |||
1354 | ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL); | ||
1355 | if (ret) { | ||
1356 | __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); | ||
1357 | pipe_dentry = ERR_PTR(ret); | ||
1358 | goto out; | ||
1359 | } | ||
1360 | |||
1361 | pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data); | ||
1362 | if (IS_ERR(pipe_dentry)) { | ||
1363 | __rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1); | ||
1364 | __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1); | ||
1365 | } | ||
1366 | out: | ||
1367 | dput(clnt_dentry); | ||
1368 | dput(gssd_dentry); | ||
1369 | return pipe_dentry; | ||
1370 | } | ||
1371 | |||
1372 | static void | ||
1373 | rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) | ||
1374 | { | ||
1375 | struct dentry *clnt_dir = pipe_dentry->d_parent; | ||
1376 | struct dentry *gssd_dir = clnt_dir->d_parent; | ||
1377 | |||
1378 | __rpc_rmpipe(clnt_dir->d_inode, pipe_dentry); | ||
1379 | __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); | ||
1380 | __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); | ||
1381 | dput(pipe_dentry); | ||
1382 | } | ||
1383 | |||
1247 | static int | 1384 | static int |
1248 | rpc_fill_super(struct super_block *sb, void *data, int silent) | 1385 | rpc_fill_super(struct super_block *sb, void *data, int silent) |
1249 | { | 1386 | { |
1250 | struct inode *inode; | 1387 | struct inode *inode; |
1251 | struct dentry *root; | 1388 | struct dentry *root, *gssd_dentry; |
1252 | struct net *net = data; | 1389 | struct net *net = data; |
1253 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1390 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1254 | int err; | 1391 | int err; |
@@ -1266,6 +1403,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
1266 | return -ENOMEM; | 1403 | return -ENOMEM; |
1267 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) | 1404 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) |
1268 | return -ENOMEM; | 1405 | return -ENOMEM; |
1406 | |||
1407 | gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy); | ||
1408 | if (IS_ERR(gssd_dentry)) { | ||
1409 | __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); | ||
1410 | return PTR_ERR(gssd_dentry); | ||
1411 | } | ||
1412 | |||
1269 | dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", | 1413 | dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", |
1270 | net, NET_NAME(net)); | 1414 | net, NET_NAME(net)); |
1271 | mutex_lock(&sn->pipefs_sb_lock); | 1415 | mutex_lock(&sn->pipefs_sb_lock); |
@@ -1280,6 +1424,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
1280 | return 0; | 1424 | return 0; |
1281 | 1425 | ||
1282 | err_depopulate: | 1426 | err_depopulate: |
1427 | rpc_gssd_dummy_depopulate(gssd_dentry); | ||
1283 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, | 1428 | blocking_notifier_call_chain(&rpc_pipefs_notifier_list, |
1284 | RPC_PIPEFS_UMOUNT, | 1429 | RPC_PIPEFS_UMOUNT, |
1285 | sb); | 1430 | sb); |
@@ -1289,6 +1434,16 @@ err_depopulate: | |||
1289 | return err; | 1434 | return err; |
1290 | } | 1435 | } |
1291 | 1436 | ||
1437 | bool | ||
1438 | gssd_running(struct net *net) | ||
1439 | { | ||
1440 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
1441 | struct rpc_pipe *pipe = sn->gssd_dummy; | ||
1442 | |||
1443 | return pipe->nreaders || pipe->nwriters; | ||
1444 | } | ||
1445 | EXPORT_SYMBOL_GPL(gssd_running); | ||
1446 | |||
1292 | static struct dentry * | 1447 | static struct dentry * |
1293 | rpc_mount(struct file_system_type *fs_type, | 1448 | rpc_mount(struct file_system_type *fs_type, |
1294 | int flags, const char *dev_name, void *data) | 1449 | int flags, const char *dev_name, void *data) |
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 3d6498af9adc..cd30120de9e4 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c | |||
@@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net) | |||
44 | if (err) | 44 | if (err) |
45 | goto err_unixgid; | 45 | goto err_unixgid; |
46 | 46 | ||
47 | rpc_pipefs_init_net(net); | 47 | err = rpc_pipefs_init_net(net); |
48 | if (err) | ||
49 | goto err_pipefs; | ||
50 | |||
48 | INIT_LIST_HEAD(&sn->all_clients); | 51 | INIT_LIST_HEAD(&sn->all_clients); |
49 | spin_lock_init(&sn->rpc_client_lock); | 52 | spin_lock_init(&sn->rpc_client_lock); |
50 | spin_lock_init(&sn->rpcb_clnt_lock); | 53 | spin_lock_init(&sn->rpcb_clnt_lock); |
51 | return 0; | 54 | return 0; |
52 | 55 | ||
56 | err_pipefs: | ||
57 | unix_gid_cache_destroy(net); | ||
53 | err_unixgid: | 58 | err_unixgid: |
54 | ip_map_cache_destroy(net); | 59 | ip_map_cache_destroy(net); |
55 | err_ipmap: | 60 | err_ipmap: |
@@ -60,6 +65,7 @@ err_proc: | |||
60 | 65 | ||
61 | static __net_exit void sunrpc_exit_net(struct net *net) | 66 | static __net_exit void sunrpc_exit_net(struct net *net) |
62 | { | 67 | { |
68 | rpc_pipefs_exit_net(net); | ||
63 | unix_gid_cache_destroy(net); | 69 | unix_gid_cache_destroy(net); |
64 | ip_map_cache_destroy(net); | 70 | ip_map_cache_destroy(net); |
65 | rpc_proc_exit(net); | 71 | rpc_proc_exit(net); |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 1750048130a7..7d4df99f761f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -749,6 +749,11 @@ static void xprt_connect_status(struct rpc_task *task) | |||
749 | } | 749 | } |
750 | 750 | ||
751 | switch (task->tk_status) { | 751 | switch (task->tk_status) { |
752 | case -ECONNREFUSED: | ||
753 | case -ECONNRESET: | ||
754 | case -ECONNABORTED: | ||
755 | case -ENETUNREACH: | ||
756 | case -EHOSTUNREACH: | ||
752 | case -EAGAIN: | 757 | case -EAGAIN: |
753 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); | 758 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); |
754 | break; | 759 | break; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 75b045e1cd50..2a7ca8ffe83a 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -257,6 +257,7 @@ struct sock_xprt { | |||
257 | void (*old_data_ready)(struct sock *, int); | 257 | void (*old_data_ready)(struct sock *, int); |
258 | void (*old_state_change)(struct sock *); | 258 | void (*old_state_change)(struct sock *); |
259 | void (*old_write_space)(struct sock *); | 259 | void (*old_write_space)(struct sock *); |
260 | void (*old_error_report)(struct sock *); | ||
260 | }; | 261 | }; |
261 | 262 | ||
262 | /* | 263 | /* |
@@ -274,6 +275,11 @@ struct sock_xprt { | |||
274 | */ | 275 | */ |
275 | #define TCP_RPC_REPLY (1UL << 6) | 276 | #define TCP_RPC_REPLY (1UL << 6) |
276 | 277 | ||
278 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) | ||
279 | { | ||
280 | return (struct rpc_xprt *) sk->sk_user_data; | ||
281 | } | ||
282 | |||
277 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) | 283 | static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt) |
278 | { | 284 | { |
279 | return (struct sockaddr *) &xprt->addr; | 285 | return (struct sockaddr *) &xprt->addr; |
@@ -799,6 +805,7 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk) | |||
799 | transport->old_data_ready = sk->sk_data_ready; | 805 | transport->old_data_ready = sk->sk_data_ready; |
800 | transport->old_state_change = sk->sk_state_change; | 806 | transport->old_state_change = sk->sk_state_change; |
801 | transport->old_write_space = sk->sk_write_space; | 807 | transport->old_write_space = sk->sk_write_space; |
808 | transport->old_error_report = sk->sk_error_report; | ||
802 | } | 809 | } |
803 | 810 | ||
804 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) | 811 | static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk) |
@@ -806,6 +813,34 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s | |||
806 | sk->sk_data_ready = transport->old_data_ready; | 813 | sk->sk_data_ready = transport->old_data_ready; |
807 | sk->sk_state_change = transport->old_state_change; | 814 | sk->sk_state_change = transport->old_state_change; |
808 | sk->sk_write_space = transport->old_write_space; | 815 | sk->sk_write_space = transport->old_write_space; |
816 | sk->sk_error_report = transport->old_error_report; | ||
817 | } | ||
818 | |||
819 | /** | ||
820 | * xs_error_report - callback to handle TCP socket state errors | ||
821 | * @sk: socket | ||
822 | * | ||
823 | * Note: we don't call sock_error() since there may be a rpc_task | ||
824 | * using the socket, and so we don't want to clear sk->sk_err. | ||
825 | */ | ||
826 | static void xs_error_report(struct sock *sk) | ||
827 | { | ||
828 | struct rpc_xprt *xprt; | ||
829 | int err; | ||
830 | |||
831 | read_lock_bh(&sk->sk_callback_lock); | ||
832 | if (!(xprt = xprt_from_sock(sk))) | ||
833 | goto out; | ||
834 | |||
835 | err = -sk->sk_err; | ||
836 | if (err == 0) | ||
837 | goto out; | ||
838 | dprintk("RPC: xs_error_report client %p, error=%d...\n", | ||
839 | xprt, -err); | ||
840 | trace_rpc_socket_error(xprt, sk->sk_socket, err); | ||
841 | xprt_wake_pending_tasks(xprt, err); | ||
842 | out: | ||
843 | read_unlock_bh(&sk->sk_callback_lock); | ||
809 | } | 844 | } |
810 | 845 | ||
811 | static void xs_reset_transport(struct sock_xprt *transport) | 846 | static void xs_reset_transport(struct sock_xprt *transport) |
@@ -885,11 +920,6 @@ static void xs_destroy(struct rpc_xprt *xprt) | |||
885 | module_put(THIS_MODULE); | 920 | module_put(THIS_MODULE); |
886 | } | 921 | } |
887 | 922 | ||
888 | static inline struct rpc_xprt *xprt_from_sock(struct sock *sk) | ||
889 | { | ||
890 | return (struct rpc_xprt *) sk->sk_user_data; | ||
891 | } | ||
892 | |||
893 | static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) | 923 | static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb) |
894 | { | 924 | { |
895 | struct xdr_skb_reader desc = { | 925 | struct xdr_skb_reader desc = { |
@@ -1869,6 +1899,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt, | |||
1869 | sk->sk_user_data = xprt; | 1899 | sk->sk_user_data = xprt; |
1870 | sk->sk_data_ready = xs_local_data_ready; | 1900 | sk->sk_data_ready = xs_local_data_ready; |
1871 | sk->sk_write_space = xs_udp_write_space; | 1901 | sk->sk_write_space = xs_udp_write_space; |
1902 | sk->sk_error_report = xs_error_report; | ||
1872 | sk->sk_allocation = GFP_ATOMIC; | 1903 | sk->sk_allocation = GFP_ATOMIC; |
1873 | 1904 | ||
1874 | xprt_clear_connected(xprt); | 1905 | xprt_clear_connected(xprt); |
@@ -2146,6 +2177,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
2146 | sk->sk_data_ready = xs_tcp_data_ready; | 2177 | sk->sk_data_ready = xs_tcp_data_ready; |
2147 | sk->sk_state_change = xs_tcp_state_change; | 2178 | sk->sk_state_change = xs_tcp_state_change; |
2148 | sk->sk_write_space = xs_tcp_write_space; | 2179 | sk->sk_write_space = xs_tcp_write_space; |
2180 | sk->sk_error_report = xs_error_report; | ||
2149 | sk->sk_allocation = GFP_ATOMIC; | 2181 | sk->sk_allocation = GFP_ATOMIC; |
2150 | 2182 | ||
2151 | /* socket options */ | 2183 | /* socket options */ |