aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/connect.c35
3 files changed, 34 insertions, 11 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b7fcb3151103..53e343d073bb 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -507,6 +507,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
507 507
508 seq_printf(s, ",rsize=%u", cifs_sb->rsize); 508 seq_printf(s, ",rsize=%u", cifs_sb->rsize);
509 seq_printf(s, ",wsize=%u", cifs_sb->wsize); 509 seq_printf(s, ",wsize=%u", cifs_sb->wsize);
510 seq_printf(s, ",echo_interval=%lu",
511 tcon->ses->server->echo_interval / HZ);
510 /* convert actimeo and display it in seconds */ 512 /* convert actimeo and display it in seconds */
511 seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); 513 seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ);
512 514
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 2b510c537a0d..9d14926531ba 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -70,8 +70,10 @@
70#define SERVER_NAME_LENGTH 40 70#define SERVER_NAME_LENGTH 40
71#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) 71#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
72 72
73/* SMB echo "timeout" -- FIXME: tunable? */ 73/* echo interval in seconds */
74#define SMB_ECHO_INTERVAL (60 * HZ) 74#define SMB_ECHO_INTERVAL_MIN 1
75#define SMB_ECHO_INTERVAL_MAX 600
76#define SMB_ECHO_INTERVAL_DEFAULT 60
75 77
76#include "cifspdu.h" 78#include "cifspdu.h"
77 79
@@ -507,6 +509,7 @@ struct smb_vol {
507 struct sockaddr_storage dstaddr; /* destination address */ 509 struct sockaddr_storage dstaddr; /* destination address */
508 struct sockaddr_storage srcaddr; /* allow binding to a local IP */ 510 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
509 struct nls_table *local_nls; 511 struct nls_table *local_nls;
512 unsigned int echo_interval; /* echo interval in secs */
510}; 513};
511 514
512#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \ 515#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
@@ -628,6 +631,7 @@ struct TCP_Server_Info {
628 unsigned int max_read; 631 unsigned int max_read;
629 unsigned int max_write; 632 unsigned int max_write;
630#endif /* CONFIG_CIFS_SMB2 */ 633#endif /* CONFIG_CIFS_SMB2 */
634 unsigned long echo_interval;
631}; 635};
632 636
633static inline unsigned int 637static inline unsigned int
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 103054af9713..de53c5558fe3 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -95,6 +95,7 @@ enum {
95 Opt_cruid, Opt_gid, Opt_file_mode, 95 Opt_cruid, Opt_gid, Opt_file_mode,
96 Opt_dirmode, Opt_port, 96 Opt_dirmode, Opt_port,
97 Opt_rsize, Opt_wsize, Opt_actimeo, 97 Opt_rsize, Opt_wsize, Opt_actimeo,
98 Opt_echo_interval,
98 99
99 /* Mount options which take string value */ 100 /* Mount options which take string value */
100 Opt_user, Opt_pass, Opt_ip, 101 Opt_user, Opt_pass, Opt_ip,
@@ -188,6 +189,7 @@ static const match_table_t cifs_mount_option_tokens = {
188 { Opt_rsize, "rsize=%s" }, 189 { Opt_rsize, "rsize=%s" },
189 { Opt_wsize, "wsize=%s" }, 190 { Opt_wsize, "wsize=%s" },
190 { Opt_actimeo, "actimeo=%s" }, 191 { Opt_actimeo, "actimeo=%s" },
192 { Opt_echo_interval, "echo_interval=%s" },
191 193
192 { Opt_blank_user, "user=" }, 194 { Opt_blank_user, "user=" },
193 { Opt_blank_user, "username=" }, 195 { Opt_blank_user, "username=" },
@@ -418,6 +420,7 @@ cifs_echo_request(struct work_struct *work)
418 int rc; 420 int rc;
419 struct TCP_Server_Info *server = container_of(work, 421 struct TCP_Server_Info *server = container_of(work,
420 struct TCP_Server_Info, echo.work); 422 struct TCP_Server_Info, echo.work);
423 unsigned long echo_interval = server->echo_interval;
421 424
422 /* 425 /*
423 * We cannot send an echo if it is disabled or until the 426 * We cannot send an echo if it is disabled or until the
@@ -427,7 +430,7 @@ cifs_echo_request(struct work_struct *work)
427 */ 430 */
428 if (!server->ops->need_neg || server->ops->need_neg(server) || 431 if (!server->ops->need_neg || server->ops->need_neg(server) ||
429 (server->ops->can_echo && !server->ops->can_echo(server)) || 432 (server->ops->can_echo && !server->ops->can_echo(server)) ||
430 time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) 433 time_before(jiffies, server->lstrp + echo_interval - HZ))
431 goto requeue_echo; 434 goto requeue_echo;
432 435
433 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS; 436 rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
@@ -436,7 +439,7 @@ cifs_echo_request(struct work_struct *work)
436 server->hostname); 439 server->hostname);
437 440
438requeue_echo: 441requeue_echo:
439 queue_delayed_work(cifsiod_wq, &server->echo, SMB_ECHO_INTERVAL); 442 queue_delayed_work(cifsiod_wq, &server->echo, echo_interval);
440} 443}
441 444
442static bool 445static bool
@@ -487,12 +490,9 @@ server_unresponsive(struct TCP_Server_Info *server)
487 * a response in >60s. 490 * a response in >60s.
488 */ 491 */
489 if (server->tcpStatus == CifsGood && 492 if (server->tcpStatus == CifsGood &&
490 time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) { 493 time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
491 cifs_dbg(VFS, "Server %s (addr=%pISc) has not responded in " 494 cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
492 "%d seconds. Reconnecting...\n", 495 server->hostname, (2 * server->echo_interval) / HZ);
493 server->hostname,
494 (struct sockaddr *)&server->dstaddr,
495 (2 * SMB_ECHO_INTERVAL) / HZ);
496 cifs_reconnect(server); 496 cifs_reconnect(server);
497 wake_up(&server->response_q); 497 wake_up(&server->response_q);
498 return true; 498 return true;
@@ -1627,6 +1627,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
1627 goto cifs_parse_mount_err; 1627 goto cifs_parse_mount_err;
1628 } 1628 }
1629 break; 1629 break;
1630 case Opt_echo_interval:
1631 if (get_option_ul(args, &option)) {
1632 cifs_dbg(VFS, "%s: Invalid echo interval value\n",
1633 __func__);
1634 goto cifs_parse_mount_err;
1635 }
1636 vol->echo_interval = option;
1637 break;
1630 1638
1631 /* String Arguments */ 1639 /* String Arguments */
1632 1640
@@ -2092,6 +2100,9 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
2092 if (!match_security(server, vol)) 2100 if (!match_security(server, vol))
2093 return 0; 2101 return 0;
2094 2102
2103 if (server->echo_interval != vol->echo_interval)
2104 return 0;
2105
2095 return 1; 2106 return 1;
2096} 2107}
2097 2108
@@ -2211,6 +2222,12 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
2211 tcp_ses->tcpStatus = CifsNew; 2222 tcp_ses->tcpStatus = CifsNew;
2212 ++tcp_ses->srv_count; 2223 ++tcp_ses->srv_count;
2213 2224
2225 if (volume_info->echo_interval >= SMB_ECHO_INTERVAL_MIN &&
2226 volume_info->echo_interval <= SMB_ECHO_INTERVAL_MAX)
2227 tcp_ses->echo_interval = volume_info->echo_interval * HZ;
2228 else
2229 tcp_ses->echo_interval = SMB_ECHO_INTERVAL_DEFAULT * HZ;
2230
2214 rc = ip_connect(tcp_ses); 2231 rc = ip_connect(tcp_ses);
2215 if (rc < 0) { 2232 if (rc < 0) {
2216 cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n"); 2233 cifs_dbg(VFS, "Error connecting to socket. Aborting operation.\n");
@@ -2240,7 +2257,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
2240 cifs_fscache_get_client_cookie(tcp_ses); 2257 cifs_fscache_get_client_cookie(tcp_ses);
2241 2258
2242 /* queue echo request delayed work */ 2259 /* queue echo request delayed work */
2243 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL); 2260 queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
2244 2261
2245 return tcp_ses; 2262 return tcp_ses;
2246 2263