diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-20 19:36:38 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-20 19:36:38 -0500 |
| commit | 5cdec1fca2ff128ca0716dc1ef0fc0043e4ae8ab (patch) | |
| tree | 35dbfed2dc57b80d18276413361c34905fe8312c | |
| parent | e55fdbd7414a3ee991d7081a256153f61ea98b9f (diff) | |
| parent | 76dcc26f1d7f1c98c3f595379dcd9562f01bf38d (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
cifs: mangle existing header for SMB_COM_NT_CANCEL
cifs: remove code for setting timeouts on requests
[CIFS] cifs: reconnect unresponsive servers
cifs: set up recurring workqueue job to do SMB echo requests
cifs: add ability to send an echo request
cifs: add cifs_call_async
cifs: allow for different handling of received response
cifs: clean up sync_mid_result
cifs: don't reconnect server when we don't get a response
cifs: wait indefinitely for responses
cifs: Use mask of ACEs for SID Everyone to calculate all three permissions user, group, and other
cifs: Fix regression during share-level security mounts (Repost)
[CIFS] Update cifs version number
cifs: move mid result processing into common function
cifs: move locked sections out of DeleteMidQEntry and AllocMidQEntry
cifs: clean up accesses to midCount
cifs: make wait_for_free_request take a TCP_Server_Info pointer
cifs: no need to mark smb_ses_list as cifs_demultiplex_thread is exiting
cifs: don't fail writepages on -EAGAIN errors
CIFS: Fix oplock break handling (try #2)
| -rw-r--r-- | fs/cifs/cifs_debug.c | 10 | ||||
| -rw-r--r-- | fs/cifs/cifsacl.c | 13 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 6 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 28 | ||||
| -rw-r--r-- | fs/cifs/cifspdu.h | 15 | ||||
| -rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 59 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 149 | ||||
| -rw-r--r-- | fs/cifs/file.c | 114 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 2 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 2 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 427 |
13 files changed, 455 insertions, 381 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index ede98300a8c..65829d32128 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
| @@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
| 79 | spin_lock(&GlobalMid_Lock); | 79 | spin_lock(&GlobalMid_Lock); |
| 80 | list_for_each(tmp, &server->pending_mid_q) { | 80 | list_for_each(tmp, &server->pending_mid_q) { |
| 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 82 | cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", | 82 | cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d", |
| 83 | mid_entry->midState, | 83 | mid_entry->midState, |
| 84 | (int)mid_entry->command, | 84 | (int)mid_entry->command, |
| 85 | mid_entry->pid, | 85 | mid_entry->pid, |
| 86 | mid_entry->tsk, | 86 | mid_entry->callback_data, |
| 87 | mid_entry->mid); | 87 | mid_entry->mid); |
| 88 | #ifdef CONFIG_CIFS_STATS2 | 88 | #ifdef CONFIG_CIFS_STATS2 |
| 89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", | 89 | cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", |
| @@ -218,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 218 | mid_entry = list_entry(tmp3, struct mid_q_entry, | 218 | mid_entry = list_entry(tmp3, struct mid_q_entry, |
| 219 | qhead); | 219 | qhead); |
| 220 | seq_printf(m, "\tState: %d com: %d pid:" | 220 | seq_printf(m, "\tState: %d com: %d pid:" |
| 221 | " %d tsk: %p mid %d\n", | 221 | " %d cbdata: %p mid %d\n", |
| 222 | mid_entry->midState, | 222 | mid_entry->midState, |
| 223 | (int)mid_entry->command, | 223 | (int)mid_entry->command, |
| 224 | mid_entry->pid, | 224 | mid_entry->pid, |
| 225 | mid_entry->tsk, | 225 | mid_entry->callback_data, |
| 226 | mid_entry->mid); | 226 | mid_entry->mid); |
| 227 | } | 227 | } |
| 228 | spin_unlock(&GlobalMid_Lock); | 228 | spin_unlock(&GlobalMid_Lock); |
| @@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
| 331 | atomic_read(&totSmBufAllocCount)); | 331 | atomic_read(&totSmBufAllocCount)); |
| 332 | #endif /* CONFIG_CIFS_STATS2 */ | 332 | #endif /* CONFIG_CIFS_STATS2 */ |
| 333 | 333 | ||
| 334 | seq_printf(m, "Operations (MIDs): %d\n", midCount.counter); | 334 | seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount)); |
| 335 | seq_printf(m, | 335 | seq_printf(m, |
| 336 | "\n%d session %d share reconnects\n", | 336 | "\n%d session %d share reconnects\n", |
| 337 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); | 337 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a437ec391a0..1e7636b145a 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { | |||
| 41 | ; | 41 | ; |
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | /* security id for everyone */ | 44 | /* security id for everyone/world system group */ |
| 45 | static const struct cifs_sid sid_everyone = { | 45 | static const struct cifs_sid sid_everyone = { |
| 46 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; | 46 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; |
| 47 | /* security id for Authenticated Users system group */ | ||
| 48 | static const struct cifs_sid sid_authusers = { | ||
| 49 | 1, 1, {0, 0, 0, 0, 0, 5}, {11} }; | ||
| 47 | /* group users */ | 50 | /* group users */ |
| 48 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 51 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
| 49 | 52 | ||
| @@ -365,7 +368,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 365 | if (num_aces > 0) { | 368 | if (num_aces > 0) { |
| 366 | umode_t user_mask = S_IRWXU; | 369 | umode_t user_mask = S_IRWXU; |
| 367 | umode_t group_mask = S_IRWXG; | 370 | umode_t group_mask = S_IRWXG; |
| 368 | umode_t other_mask = S_IRWXO; | 371 | umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; |
| 369 | 372 | ||
| 370 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), | 373 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), |
| 371 | GFP_KERNEL); | 374 | GFP_KERNEL); |
| @@ -390,6 +393,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
| 390 | ppace[i]->type, | 393 | ppace[i]->type, |
| 391 | &fattr->cf_mode, | 394 | &fattr->cf_mode, |
| 392 | &other_mask); | 395 | &other_mask); |
| 396 | if (compare_sids(&(ppace[i]->sid), &sid_authusers)) | ||
| 397 | access_flags_to_mode(ppace[i]->access_req, | ||
| 398 | ppace[i]->type, | ||
| 399 | &fattr->cf_mode, | ||
| 400 | &other_mask); | ||
| 401 | |||
| 393 | 402 | ||
| 394 | /* memcpy((void *)(&(cifscred->aces[i])), | 403 | /* memcpy((void *)(&(cifscred->aces[i])), |
| 395 | (void *)ppace[i], | 404 | (void *)ppace[i], |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d9f652a522a..99d777a03dd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ; | |||
| 77 | module_param(cifs_max_pending, int, 0); | 77 | module_param(cifs_max_pending, int, 0); |
| 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
| 79 | "Default: 50 Range: 2 to 256"); | 79 | "Default: 50 Range: 2 to 256"); |
| 80 | 80 | unsigned short echo_retries = 5; | |
| 81 | module_param(echo_retries, ushort, 0644); | ||
| 82 | MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " | ||
| 83 | "reconnecting server. Default: 5. 0 means " | ||
| 84 | "never reconnect."); | ||
| 81 | extern mempool_t *cifs_sm_req_poolp; | 85 | extern mempool_t *cifs_sm_req_poolp; |
| 82 | extern mempool_t *cifs_req_poolp; | 86 | extern mempool_t *cifs_req_poolp; |
| 83 | extern mempool_t *cifs_mid_poolp; | 87 | extern mempool_t *cifs_mid_poolp; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 851030f7493..4739a531cde 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -118,5 +118,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 118 | extern const struct export_operations cifs_export_ops; | 118 | extern const struct export_operations cifs_export_ops; |
| 119 | #endif /* EXPERIMENTAL */ | 119 | #endif /* EXPERIMENTAL */ |
| 120 | 120 | ||
| 121 | #define CIFS_VERSION "1.68" | 121 | #define CIFS_VERSION "1.69" |
| 122 | #endif /* _CIFSFS_H */ | 122 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 606ca8bb710..571132c9523 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -218,6 +218,7 @@ struct TCP_Server_Info { | |||
| 218 | bool sec_kerberosu2u; /* supports U2U Kerberos */ | 218 | bool sec_kerberosu2u; /* supports U2U Kerberos */ |
| 219 | bool sec_ntlmssp; /* supports NTLMSSP */ | 219 | bool sec_ntlmssp; /* supports NTLMSSP */ |
| 220 | bool session_estab; /* mark when very first sess is established */ | 220 | bool session_estab; /* mark when very first sess is established */ |
| 221 | struct delayed_work echo; /* echo ping workqueue job */ | ||
| 221 | #ifdef CONFIG_CIFS_FSCACHE | 222 | #ifdef CONFIG_CIFS_FSCACHE |
| 222 | struct fscache_cookie *fscache; /* client index cache cookie */ | 223 | struct fscache_cookie *fscache; /* client index cache cookie */ |
| 223 | #endif | 224 | #endif |
| @@ -508,6 +509,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | |||
| 508 | 509 | ||
| 509 | #endif | 510 | #endif |
| 510 | 511 | ||
| 512 | struct mid_q_entry; | ||
| 513 | |||
| 514 | /* | ||
| 515 | * This is the prototype for the mid callback function. When creating one, | ||
| 516 | * take special care to avoid deadlocks. Things to bear in mind: | ||
| 517 | * | ||
| 518 | * - it will be called by cifsd | ||
| 519 | * - the GlobalMid_Lock will be held | ||
| 520 | * - the mid will be removed from the pending_mid_q list | ||
| 521 | */ | ||
| 522 | typedef void (mid_callback_t)(struct mid_q_entry *mid); | ||
| 523 | |||
| 511 | /* one of these for every pending CIFS request to the server */ | 524 | /* one of these for every pending CIFS request to the server */ |
| 512 | struct mid_q_entry { | 525 | struct mid_q_entry { |
| 513 | struct list_head qhead; /* mids waiting on reply from this server */ | 526 | struct list_head qhead; /* mids waiting on reply from this server */ |
| @@ -519,7 +532,8 @@ struct mid_q_entry { | |||
| 519 | unsigned long when_sent; /* time when smb send finished */ | 532 | unsigned long when_sent; /* time when smb send finished */ |
| 520 | unsigned long when_received; /* when demux complete (taken off wire) */ | 533 | unsigned long when_received; /* when demux complete (taken off wire) */ |
| 521 | #endif | 534 | #endif |
| 522 | struct task_struct *tsk; /* task waiting for response */ | 535 | mid_callback_t *callback; /* call completion callback */ |
| 536 | void *callback_data; /* general purpose pointer for callback */ | ||
| 523 | struct smb_hdr *resp_buf; /* response buffer */ | 537 | struct smb_hdr *resp_buf; /* response buffer */ |
| 524 | int midState; /* wish this were enum but can not pass to wait_event */ | 538 | int midState; /* wish this were enum but can not pass to wait_event */ |
| 525 | __u8 command; /* smb command code */ | 539 | __u8 command; /* smb command code */ |
| @@ -622,12 +636,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
| 622 | #define CIFS_IOVEC 4 /* array of response buffers */ | 636 | #define CIFS_IOVEC 4 /* array of response buffers */ |
| 623 | 637 | ||
| 624 | /* Type of Request to SendReceive2 */ | 638 | /* Type of Request to SendReceive2 */ |
| 625 | #define CIFS_STD_OP 0 /* normal request timeout */ | 639 | #define CIFS_BLOCKING_OP 1 /* operation can block */ |
| 626 | #define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ | 640 | #define CIFS_ASYNC_OP 2 /* do not wait for response */ |
| 627 | #define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ | 641 | #define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */ |
| 628 | #define CIFS_BLOCKING_OP 4 /* operation can block */ | ||
| 629 | #define CIFS_ASYNC_OP 8 /* do not wait for response */ | ||
| 630 | #define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */ | ||
| 631 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ | 642 | #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ |
| 632 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ | 643 | #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ |
| 633 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ | 644 | #define CIFS_NO_RESP 0x040 /* no response buffer required */ |
| @@ -790,6 +801,9 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
| 790 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 801 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
| 791 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 802 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
| 792 | 803 | ||
| 804 | /* reconnect after this many failed echo attempts */ | ||
| 805 | GLOBAL_EXTERN unsigned short echo_retries; | ||
| 806 | |||
| 793 | void cifs_oplock_break(struct work_struct *work); | 807 | void cifs_oplock_break(struct work_struct *work); |
| 794 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); | 808 | void cifs_oplock_break_get(struct cifsFileInfo *cfile); |
| 795 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); | 809 | void cifs_oplock_break_put(struct cifsFileInfo *cfile); |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index de36b09763a..ea205b4fcad 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 50 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
| 51 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 51 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
| 52 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 52 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
| 53 | #define SMB_COM_ECHO 0x2B /* echo request */ | ||
| 53 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | 54 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ |
| 54 | #define SMB_COM_READ_ANDX 0x2E | 55 | #define SMB_COM_READ_ANDX 0x2E |
| 55 | #define SMB_COM_WRITE_ANDX 0x2F | 56 | #define SMB_COM_WRITE_ANDX 0x2F |
| @@ -760,6 +761,20 @@ typedef struct smb_com_tconx_rsp_ext { | |||
| 760 | * | 761 | * |
| 761 | */ | 762 | */ |
| 762 | 763 | ||
| 764 | typedef struct smb_com_echo_req { | ||
| 765 | struct smb_hdr hdr; | ||
| 766 | __le16 EchoCount; | ||
| 767 | __le16 ByteCount; | ||
| 768 | char Data[1]; | ||
| 769 | } __attribute__((packed)) ECHO_REQ; | ||
| 770 | |||
| 771 | typedef struct smb_com_echo_rsp { | ||
| 772 | struct smb_hdr hdr; | ||
| 773 | __le16 SequenceNumber; | ||
| 774 | __le16 ByteCount; | ||
| 775 | char Data[1]; | ||
| 776 | } __attribute__((packed)) ECHO_RSP; | ||
| 777 | |||
| 763 | typedef struct smb_com_logoff_andx_req { | 778 | typedef struct smb_com_logoff_andx_req { |
| 764 | struct smb_hdr hdr; /* wct = 2 */ | 779 | struct smb_hdr hdr; /* wct = 2 */ |
| 765 | __u8 AndXCommand; | 780 | __u8 AndXCommand; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e6d1481b16c..982895fa761 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata, | |||
| 61 | const char *fullpath, const struct dfs_info3_param *ref, | 61 | const char *fullpath, const struct dfs_info3_param *ref, |
| 62 | char **devname); | 62 | char **devname); |
| 63 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ | 63 | /* extern void renew_parental_timestamps(struct dentry *direntry);*/ |
| 64 | extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer, | ||
| 65 | struct TCP_Server_Info *server); | ||
| 66 | extern void DeleteMidQEntry(struct mid_q_entry *midEntry); | ||
| 67 | extern int cifs_call_async(struct TCP_Server_Info *server, | ||
| 68 | struct smb_hdr *in_buf, mid_callback_t *callback, | ||
| 69 | void *cbdata); | ||
| 64 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | 70 | extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, |
| 65 | struct smb_hdr * /* input */ , | 71 | struct smb_hdr * /* input */ , |
| 66 | struct smb_hdr * /* out */ , | 72 | struct smb_hdr * /* out */ , |
| @@ -347,12 +353,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 347 | const __u16 netfid, const __u64 len, | 353 | const __u16 netfid, const __u64 len, |
| 348 | const __u64 offset, const __u32 numUnlock, | 354 | const __u64 offset, const __u32 numUnlock, |
| 349 | const __u32 numLock, const __u8 lockType, | 355 | const __u32 numLock, const __u8 lockType, |
| 350 | const bool waitFlag); | 356 | const bool waitFlag, const __u8 oplock_level); |
| 351 | extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, | 357 | extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, |
| 352 | const __u16 smb_file_id, const int get_flag, | 358 | const __u16 smb_file_id, const int get_flag, |
| 353 | const __u64 len, struct file_lock *, | 359 | const __u64 len, struct file_lock *, |
| 354 | const __u16 lock_type, const bool waitFlag); | 360 | const __u16 lock_type, const bool waitFlag); |
| 355 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); | 361 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); |
| 362 | extern int CIFSSMBEcho(struct TCP_Server_Info *server); | ||
| 356 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); | 363 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); |
| 357 | 364 | ||
| 358 | extern struct cifsSesInfo *sesInfoAlloc(void); | 365 | extern struct cifsSesInfo *sesInfoAlloc(void); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f6795e524d..37113450757 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -706,6 +706,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
| 706 | return rc; | 706 | return rc; |
| 707 | } | 707 | } |
| 708 | 708 | ||
| 709 | /* | ||
| 710 | * This is a no-op for now. We're not really interested in the reply, but | ||
| 711 | * rather in the fact that the server sent one and that server->lstrp | ||
| 712 | * gets updated. | ||
| 713 | * | ||
| 714 | * FIXME: maybe we should consider checking that the reply matches request? | ||
| 715 | */ | ||
| 716 | static void | ||
| 717 | cifs_echo_callback(struct mid_q_entry *mid) | ||
| 718 | { | ||
| 719 | struct TCP_Server_Info *server = mid->callback_data; | ||
| 720 | |||
| 721 | DeleteMidQEntry(mid); | ||
| 722 | atomic_dec(&server->inFlight); | ||
| 723 | wake_up(&server->request_q); | ||
| 724 | } | ||
| 725 | |||
| 726 | int | ||
| 727 | CIFSSMBEcho(struct TCP_Server_Info *server) | ||
| 728 | { | ||
| 729 | ECHO_REQ *smb; | ||
| 730 | int rc = 0; | ||
| 731 | |||
| 732 | cFYI(1, "In echo request"); | ||
| 733 | |||
| 734 | rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); | ||
| 735 | if (rc) | ||
| 736 | return rc; | ||
| 737 | |||
| 738 | /* set up echo request */ | ||
| 739 | smb->hdr.Tid = cpu_to_le16(0xffff); | ||
| 740 | smb->hdr.WordCount = cpu_to_le16(1); | ||
| 741 | smb->EchoCount = cpu_to_le16(1); | ||
| 742 | smb->ByteCount = cpu_to_le16(1); | ||
| 743 | smb->Data[0] = 'a'; | ||
| 744 | smb->hdr.smb_buf_length += 3; | ||
| 745 | |||
| 746 | rc = cifs_call_async(server, (struct smb_hdr *)smb, | ||
| 747 | cifs_echo_callback, server); | ||
| 748 | if (rc) | ||
| 749 | cFYI(1, "Echo request failed: %d", rc); | ||
| 750 | |||
| 751 | cifs_small_buf_release(smb); | ||
| 752 | |||
| 753 | return rc; | ||
| 754 | } | ||
| 755 | |||
| 709 | int | 756 | int |
| 710 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | 757 | CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) |
| 711 | { | 758 | { |
| @@ -1193,7 +1240,7 @@ OldOpenRetry: | |||
| 1193 | pSMB->ByteCount = cpu_to_le16(count); | 1240 | pSMB->ByteCount = cpu_to_le16(count); |
| 1194 | /* long_op set to 1 to allow for oplock break timeouts */ | 1241 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1195 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1242 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1196 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1243 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
| 1197 | cifs_stats_inc(&tcon->num_opens); | 1244 | cifs_stats_inc(&tcon->num_opens); |
| 1198 | if (rc) { | 1245 | if (rc) { |
| 1199 | cFYI(1, "Error in Open = %d", rc); | 1246 | cFYI(1, "Error in Open = %d", rc); |
| @@ -1306,7 +1353,7 @@ openRetry: | |||
| 1306 | pSMB->ByteCount = cpu_to_le16(count); | 1353 | pSMB->ByteCount = cpu_to_le16(count); |
| 1307 | /* long_op set to 1 to allow for oplock break timeouts */ | 1354 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 1308 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1355 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1309 | (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); | 1356 | (struct smb_hdr *)pSMBr, &bytes_returned, 0); |
| 1310 | cifs_stats_inc(&tcon->num_opens); | 1357 | cifs_stats_inc(&tcon->num_opens); |
| 1311 | if (rc) { | 1358 | if (rc) { |
| 1312 | cFYI(1, "Error in Open = %d", rc); | 1359 | cFYI(1, "Error in Open = %d", rc); |
| @@ -1388,7 +1435,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, | |||
| 1388 | iov[0].iov_base = (char *)pSMB; | 1435 | iov[0].iov_base = (char *)pSMB; |
| 1389 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 1436 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 1390 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, | 1437 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, |
| 1391 | &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); | 1438 | &resp_buf_type, CIFS_LOG_ERROR); |
| 1392 | cifs_stats_inc(&tcon->num_reads); | 1439 | cifs_stats_inc(&tcon->num_reads); |
| 1393 | pSMBr = (READ_RSP *)iov[0].iov_base; | 1440 | pSMBr = (READ_RSP *)iov[0].iov_base; |
| 1394 | if (rc) { | 1441 | if (rc) { |
| @@ -1663,7 +1710,8 @@ int | |||
| 1663 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1710 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, |
| 1664 | const __u16 smb_file_id, const __u64 len, | 1711 | const __u16 smb_file_id, const __u64 len, |
| 1665 | const __u64 offset, const __u32 numUnlock, | 1712 | const __u64 offset, const __u32 numUnlock, |
| 1666 | const __u32 numLock, const __u8 lockType, const bool waitFlag) | 1713 | const __u32 numLock, const __u8 lockType, |
| 1714 | const bool waitFlag, const __u8 oplock_level) | ||
| 1667 | { | 1715 | { |
| 1668 | int rc = 0; | 1716 | int rc = 0; |
| 1669 | LOCK_REQ *pSMB = NULL; | 1717 | LOCK_REQ *pSMB = NULL; |
| @@ -1691,6 +1739,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1691 | pSMB->NumberOfLocks = cpu_to_le16(numLock); | 1739 | pSMB->NumberOfLocks = cpu_to_le16(numLock); |
| 1692 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); | 1740 | pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); |
| 1693 | pSMB->LockType = lockType; | 1741 | pSMB->LockType = lockType; |
| 1742 | pSMB->OplockLevel = oplock_level; | ||
| 1694 | pSMB->AndXCommand = 0xFF; /* none */ | 1743 | pSMB->AndXCommand = 0xFF; /* none */ |
| 1695 | pSMB->Fid = smb_file_id; /* netfid stays le */ | 1744 | pSMB->Fid = smb_file_id; /* netfid stays le */ |
| 1696 | 1745 | ||
| @@ -3087,7 +3136,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | |||
| 3087 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | 3136 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
| 3088 | 3137 | ||
| 3089 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, | 3138 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, |
| 3090 | CIFS_STD_OP); | 3139 | 0); |
| 3091 | cifs_stats_inc(&tcon->num_acl_get); | 3140 | cifs_stats_inc(&tcon->num_acl_get); |
| 3092 | if (rc) { | 3141 | if (rc) { |
| 3093 | cFYI(1, "Send error in QuerySecDesc = %d", rc); | 3142 | cFYI(1, "Send error in QuerySecDesc = %d", rc); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9f59887badd..8d465759630 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -52,6 +52,9 @@ | |||
| 52 | #define CIFS_PORT 445 | 52 | #define CIFS_PORT 445 |
| 53 | #define RFC1001_PORT 139 | 53 | #define RFC1001_PORT 139 |
| 54 | 54 | ||
| 55 | /* SMB echo "timeout" -- FIXME: tunable? */ | ||
| 56 | #define SMB_ECHO_INTERVAL (60 * HZ) | ||
| 57 | |||
| 55 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 58 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 56 | unsigned char *p24); | 59 | unsigned char *p24); |
| 57 | 60 | ||
| @@ -152,6 +155,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 152 | 155 | ||
| 153 | /* before reconnecting the tcp session, mark the smb session (uid) | 156 | /* before reconnecting the tcp session, mark the smb session (uid) |
| 154 | and the tid bad so they are not used until reconnected */ | 157 | and the tid bad so they are not used until reconnected */ |
| 158 | cFYI(1, "%s: marking sessions and tcons for reconnect", __func__); | ||
| 155 | spin_lock(&cifs_tcp_ses_lock); | 159 | spin_lock(&cifs_tcp_ses_lock); |
| 156 | list_for_each(tmp, &server->smb_ses_list) { | 160 | list_for_each(tmp, &server->smb_ses_list) { |
| 157 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 161 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| @@ -163,7 +167,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 163 | } | 167 | } |
| 164 | } | 168 | } |
| 165 | spin_unlock(&cifs_tcp_ses_lock); | 169 | spin_unlock(&cifs_tcp_ses_lock); |
| 170 | |||
| 166 | /* do not want to be sending data on a socket we are freeing */ | 171 | /* do not want to be sending data on a socket we are freeing */ |
| 172 | cFYI(1, "%s: tearing down socket", __func__); | ||
| 167 | mutex_lock(&server->srv_mutex); | 173 | mutex_lock(&server->srv_mutex); |
| 168 | if (server->ssocket) { | 174 | if (server->ssocket) { |
| 169 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, | 175 | cFYI(1, "State: 0x%x Flags: 0x%lx", server->ssocket->state, |
| @@ -180,22 +186,20 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 180 | kfree(server->session_key.response); | 186 | kfree(server->session_key.response); |
| 181 | server->session_key.response = NULL; | 187 | server->session_key.response = NULL; |
| 182 | server->session_key.len = 0; | 188 | server->session_key.len = 0; |
| 189 | server->lstrp = jiffies; | ||
| 190 | mutex_unlock(&server->srv_mutex); | ||
| 183 | 191 | ||
| 192 | /* mark submitted MIDs for retry and issue callback */ | ||
| 193 | cFYI(1, "%s: issuing mid callbacks", __func__); | ||
| 184 | spin_lock(&GlobalMid_Lock); | 194 | spin_lock(&GlobalMid_Lock); |
| 185 | list_for_each(tmp, &server->pending_mid_q) { | 195 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 186 | mid_entry = list_entry(tmp, struct | 196 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 187 | mid_q_entry, | 197 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) |
| 188 | qhead); | ||
| 189 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
| 190 | /* Mark other intransit requests as needing | ||
| 191 | retry so we do not immediately mark the | ||
| 192 | session bad again (ie after we reconnect | ||
| 193 | below) as they timeout too */ | ||
| 194 | mid_entry->midState = MID_RETRY_NEEDED; | 198 | mid_entry->midState = MID_RETRY_NEEDED; |
| 195 | } | 199 | list_del_init(&mid_entry->qhead); |
| 200 | mid_entry->callback(mid_entry); | ||
| 196 | } | 201 | } |
| 197 | spin_unlock(&GlobalMid_Lock); | 202 | spin_unlock(&GlobalMid_Lock); |
| 198 | mutex_unlock(&server->srv_mutex); | ||
| 199 | 203 | ||
| 200 | while ((server->tcpStatus != CifsExiting) && | 204 | while ((server->tcpStatus != CifsExiting) && |
| 201 | (server->tcpStatus != CifsGood)) { | 205 | (server->tcpStatus != CifsGood)) { |
| @@ -212,10 +216,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 212 | if (server->tcpStatus != CifsExiting) | 216 | if (server->tcpStatus != CifsExiting) |
| 213 | server->tcpStatus = CifsGood; | 217 | server->tcpStatus = CifsGood; |
| 214 | spin_unlock(&GlobalMid_Lock); | 218 | spin_unlock(&GlobalMid_Lock); |
| 215 | /* atomic_set(&server->inFlight,0);*/ | ||
| 216 | wake_up(&server->response_q); | ||
| 217 | } | 219 | } |
| 218 | } | 220 | } |
| 221 | |||
| 219 | return rc; | 222 | return rc; |
| 220 | } | 223 | } |
| 221 | 224 | ||
| @@ -334,6 +337,26 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) | |||
| 334 | 337 | ||
| 335 | } | 338 | } |
| 336 | 339 | ||
| 340 | static void | ||
| 341 | cifs_echo_request(struct work_struct *work) | ||
| 342 | { | ||
| 343 | int rc; | ||
| 344 | struct TCP_Server_Info *server = container_of(work, | ||
| 345 | struct TCP_Server_Info, echo.work); | ||
| 346 | |||
| 347 | /* no need to ping if we got a response recently */ | ||
| 348 | if (time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) | ||
| 349 | goto requeue_echo; | ||
| 350 | |||
| 351 | rc = CIFSSMBEcho(server); | ||
| 352 | if (rc) | ||
| 353 | cFYI(1, "Unable to send echo request to server: %s", | ||
| 354 | server->hostname); | ||
| 355 | |||
| 356 | requeue_echo: | ||
| 357 | queue_delayed_work(system_nrt_wq, &server->echo, SMB_ECHO_INTERVAL); | ||
| 358 | } | ||
| 359 | |||
| 337 | static int | 360 | static int |
| 338 | cifs_demultiplex_thread(struct TCP_Server_Info *server) | 361 | cifs_demultiplex_thread(struct TCP_Server_Info *server) |
| 339 | { | 362 | { |
| @@ -345,8 +368,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 345 | struct msghdr smb_msg; | 368 | struct msghdr smb_msg; |
| 346 | struct kvec iov; | 369 | struct kvec iov; |
| 347 | struct socket *csocket = server->ssocket; | 370 | struct socket *csocket = server->ssocket; |
| 348 | struct list_head *tmp; | 371 | struct list_head *tmp, *tmp2; |
| 349 | struct cifsSesInfo *ses; | ||
| 350 | struct task_struct *task_to_wake = NULL; | 372 | struct task_struct *task_to_wake = NULL; |
| 351 | struct mid_q_entry *mid_entry; | 373 | struct mid_q_entry *mid_entry; |
| 352 | char temp; | 374 | char temp; |
| @@ -399,7 +421,20 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 399 | smb_msg.msg_control = NULL; | 421 | smb_msg.msg_control = NULL; |
| 400 | smb_msg.msg_controllen = 0; | 422 | smb_msg.msg_controllen = 0; |
| 401 | pdu_length = 4; /* enough to get RFC1001 header */ | 423 | pdu_length = 4; /* enough to get RFC1001 header */ |
| 424 | |||
| 402 | incomplete_rcv: | 425 | incomplete_rcv: |
| 426 | if (echo_retries > 0 && | ||
| 427 | time_after(jiffies, server->lstrp + | ||
| 428 | (echo_retries * SMB_ECHO_INTERVAL))) { | ||
| 429 | cERROR(1, "Server %s has not responded in %d seconds. " | ||
| 430 | "Reconnecting...", server->hostname, | ||
| 431 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | ||
| 432 | cifs_reconnect(server); | ||
| 433 | csocket = server->ssocket; | ||
| 434 | wake_up(&server->response_q); | ||
| 435 | continue; | ||
| 436 | } | ||
| 437 | |||
| 403 | length = | 438 | length = |
| 404 | kernel_recvmsg(csocket, &smb_msg, | 439 | kernel_recvmsg(csocket, &smb_msg, |
| 405 | &iov, 1, pdu_length, 0 /* BB other flags? */); | 440 | &iov, 1, pdu_length, 0 /* BB other flags? */); |
| @@ -559,10 +594,11 @@ incomplete_rcv: | |||
| 559 | continue; | 594 | continue; |
| 560 | } | 595 | } |
| 561 | 596 | ||
| 597 | mid_entry = NULL; | ||
| 598 | server->lstrp = jiffies; | ||
| 562 | 599 | ||
| 563 | task_to_wake = NULL; | ||
| 564 | spin_lock(&GlobalMid_Lock); | 600 | spin_lock(&GlobalMid_Lock); |
| 565 | list_for_each(tmp, &server->pending_mid_q) { | 601 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 566 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 602 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 567 | 603 | ||
| 568 | if ((mid_entry->mid == smb_buffer->Mid) && | 604 | if ((mid_entry->mid == smb_buffer->Mid) && |
| @@ -603,20 +639,19 @@ incomplete_rcv: | |||
| 603 | mid_entry->resp_buf = smb_buffer; | 639 | mid_entry->resp_buf = smb_buffer; |
| 604 | mid_entry->largeBuf = isLargeBuf; | 640 | mid_entry->largeBuf = isLargeBuf; |
| 605 | multi_t2_fnd: | 641 | multi_t2_fnd: |
| 606 | task_to_wake = mid_entry->tsk; | ||
| 607 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 642 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
| 643 | list_del_init(&mid_entry->qhead); | ||
| 644 | mid_entry->callback(mid_entry); | ||
| 608 | #ifdef CONFIG_CIFS_STATS2 | 645 | #ifdef CONFIG_CIFS_STATS2 |
| 609 | mid_entry->when_received = jiffies; | 646 | mid_entry->when_received = jiffies; |
| 610 | #endif | 647 | #endif |
| 611 | /* so we do not time out requests to server | ||
| 612 | which is still responding (since server could | ||
| 613 | be busy but not dead) */ | ||
| 614 | server->lstrp = jiffies; | ||
| 615 | break; | 648 | break; |
| 616 | } | 649 | } |
| 650 | mid_entry = NULL; | ||
| 617 | } | 651 | } |
| 618 | spin_unlock(&GlobalMid_Lock); | 652 | spin_unlock(&GlobalMid_Lock); |
| 619 | if (task_to_wake) { | 653 | |
| 654 | if (mid_entry != NULL) { | ||
| 620 | /* Was previous buf put in mpx struct for multi-rsp? */ | 655 | /* Was previous buf put in mpx struct for multi-rsp? */ |
| 621 | if (!isMultiRsp) { | 656 | if (!isMultiRsp) { |
| 622 | /* smb buffer will be freed by user thread */ | 657 | /* smb buffer will be freed by user thread */ |
| @@ -625,11 +660,10 @@ multi_t2_fnd: | |||
| 625 | else | 660 | else |
| 626 | smallbuf = NULL; | 661 | smallbuf = NULL; |
| 627 | } | 662 | } |
| 628 | wake_up_process(task_to_wake); | ||
| 629 | } else if (!is_valid_oplock_break(smb_buffer, server) && | 663 | } else if (!is_valid_oplock_break(smb_buffer, server) && |
| 630 | !isMultiRsp) { | 664 | !isMultiRsp) { |
| 631 | cERROR(1, "No task to wake, unknown frame received! " | 665 | cERROR(1, "No task to wake, unknown frame received! " |
| 632 | "NumMids %d", midCount.counter); | 666 | "NumMids %d", atomic_read(&midCount)); |
| 633 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, | 667 | cifs_dump_mem("Received Data is: ", (char *)smb_buffer, |
| 634 | sizeof(struct smb_hdr)); | 668 | sizeof(struct smb_hdr)); |
| 635 | #ifdef CONFIG_CIFS_DEBUG2 | 669 | #ifdef CONFIG_CIFS_DEBUG2 |
| @@ -677,44 +711,16 @@ multi_t2_fnd: | |||
| 677 | if (smallbuf) /* no sense logging a debug message if NULL */ | 711 | if (smallbuf) /* no sense logging a debug message if NULL */ |
| 678 | cifs_small_buf_release(smallbuf); | 712 | cifs_small_buf_release(smallbuf); |
| 679 | 713 | ||
| 680 | /* | 714 | if (!list_empty(&server->pending_mid_q)) { |
| 681 | * BB: we shouldn't have to do any of this. It shouldn't be | ||
| 682 | * possible to exit from the thread with active SMB sessions | ||
| 683 | */ | ||
| 684 | spin_lock(&cifs_tcp_ses_lock); | ||
| 685 | if (list_empty(&server->pending_mid_q)) { | ||
| 686 | /* loop through server session structures attached to this and | ||
| 687 | mark them dead */ | ||
| 688 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 689 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 690 | smb_ses_list); | ||
| 691 | ses->status = CifsExiting; | ||
| 692 | ses->server = NULL; | ||
| 693 | } | ||
| 694 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 695 | } else { | ||
| 696 | /* although we can not zero the server struct pointer yet, | ||
| 697 | since there are active requests which may depnd on them, | ||
| 698 | mark the corresponding SMB sessions as exiting too */ | ||
| 699 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 700 | ses = list_entry(tmp, struct cifsSesInfo, | ||
| 701 | smb_ses_list); | ||
| 702 | ses->status = CifsExiting; | ||
| 703 | } | ||
| 704 | |||
| 705 | spin_lock(&GlobalMid_Lock); | 715 | spin_lock(&GlobalMid_Lock); |
| 706 | list_for_each(tmp, &server->pending_mid_q) { | 716 | list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { |
| 707 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 717 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 708 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | 718 | cFYI(1, "Clearing Mid 0x%x - issuing callback", |
| 709 | cFYI(1, "Clearing Mid 0x%x - waking up ", | ||
| 710 | mid_entry->mid); | 719 | mid_entry->mid); |
| 711 | task_to_wake = mid_entry->tsk; | 720 | list_del_init(&mid_entry->qhead); |
| 712 | if (task_to_wake) | 721 | mid_entry->callback(mid_entry); |
| 713 | wake_up_process(task_to_wake); | ||
| 714 | } | ||
| 715 | } | 722 | } |
| 716 | spin_unlock(&GlobalMid_Lock); | 723 | spin_unlock(&GlobalMid_Lock); |
| 717 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 718 | /* 1/8th of sec is more than enough time for them to exit */ | 724 | /* 1/8th of sec is more than enough time for them to exit */ |
| 719 | msleep(125); | 725 | msleep(125); |
| 720 | } | 726 | } |
| @@ -732,18 +738,6 @@ multi_t2_fnd: | |||
| 732 | coming home not much else we can do but free the memory */ | 738 | coming home not much else we can do but free the memory */ |
| 733 | } | 739 | } |
| 734 | 740 | ||
| 735 | /* last chance to mark ses pointers invalid | ||
| 736 | if there are any pointing to this (e.g | ||
| 737 | if a crazy root user tried to kill cifsd | ||
| 738 | kernel thread explicitly this might happen) */ | ||
| 739 | /* BB: This shouldn't be necessary, see above */ | ||
| 740 | spin_lock(&cifs_tcp_ses_lock); | ||
| 741 | list_for_each(tmp, &server->smb_ses_list) { | ||
| 742 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | ||
| 743 | ses->server = NULL; | ||
| 744 | } | ||
| 745 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 746 | |||
| 747 | kfree(server->hostname); | 741 | kfree(server->hostname); |
| 748 | task_to_wake = xchg(&server->tsk, NULL); | 742 | task_to_wake = xchg(&server->tsk, NULL); |
| 749 | kfree(server); | 743 | kfree(server); |
| @@ -1612,6 +1606,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
| 1612 | list_del_init(&server->tcp_ses_list); | 1606 | list_del_init(&server->tcp_ses_list); |
| 1613 | spin_unlock(&cifs_tcp_ses_lock); | 1607 | spin_unlock(&cifs_tcp_ses_lock); |
| 1614 | 1608 | ||
| 1609 | cancel_delayed_work_sync(&server->echo); | ||
| 1610 | |||
| 1615 | spin_lock(&GlobalMid_Lock); | 1611 | spin_lock(&GlobalMid_Lock); |
| 1616 | server->tcpStatus = CifsExiting; | 1612 | server->tcpStatus = CifsExiting; |
| 1617 | spin_unlock(&GlobalMid_Lock); | 1613 | spin_unlock(&GlobalMid_Lock); |
| @@ -1701,8 +1697,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1701 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1697 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
| 1702 | tcp_ses->session_estab = false; | 1698 | tcp_ses->session_estab = false; |
| 1703 | tcp_ses->sequence_number = 0; | 1699 | tcp_ses->sequence_number = 0; |
| 1700 | tcp_ses->lstrp = jiffies; | ||
| 1704 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 1701 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
| 1705 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 1702 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
| 1703 | INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); | ||
| 1706 | 1704 | ||
| 1707 | /* | 1705 | /* |
| 1708 | * at this point we are the only ones with the pointer | 1706 | * at this point we are the only ones with the pointer |
| @@ -1751,6 +1749,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
| 1751 | 1749 | ||
| 1752 | cifs_fscache_get_client_cookie(tcp_ses); | 1750 | cifs_fscache_get_client_cookie(tcp_ses); |
| 1753 | 1751 | ||
| 1752 | /* queue echo request delayed work */ | ||
| 1753 | queue_delayed_work(system_nrt_wq, &tcp_ses->echo, SMB_ECHO_INTERVAL); | ||
| 1754 | |||
| 1754 | return tcp_ses; | 1755 | return tcp_ses; |
| 1755 | 1756 | ||
| 1756 | out_err_crypto_release: | 1757 | out_err_crypto_release: |
| @@ -2965,7 +2966,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2965 | bcc_ptr++; /* skip password */ | 2966 | bcc_ptr++; /* skip password */ |
| 2966 | /* already aligned so no need to do it below */ | 2967 | /* already aligned so no need to do it below */ |
| 2967 | } else { | 2968 | } else { |
| 2968 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 2969 | pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); |
| 2969 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos | 2970 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos |
| 2970 | specified as required (when that support is added to | 2971 | specified as required (when that support is added to |
| 2971 | the vfs in the future) as only NTLM or the much | 2972 | the vfs in the future) as only NTLM or the much |
| @@ -2983,7 +2984,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2983 | #endif /* CIFS_WEAK_PW_HASH */ | 2984 | #endif /* CIFS_WEAK_PW_HASH */ |
| 2984 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); | 2985 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); |
| 2985 | 2986 | ||
| 2986 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 2987 | bcc_ptr += CIFS_AUTH_RESP_SIZE; |
| 2987 | if (ses->capabilities & CAP_UNICODE) { | 2988 | if (ses->capabilities & CAP_UNICODE) { |
| 2988 | /* must align unicode strings */ | 2989 | /* must align unicode strings */ |
| 2989 | *bcc_ptr = 0; /* null byte password */ | 2990 | *bcc_ptr = 0; /* null byte password */ |
| @@ -3021,7 +3022,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3021 | pSMB->ByteCount = cpu_to_le16(count); | 3022 | pSMB->ByteCount = cpu_to_le16(count); |
| 3022 | 3023 | ||
| 3023 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 3024 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
| 3024 | CIFS_STD_OP); | 3025 | 0); |
| 3025 | 3026 | ||
| 3026 | /* above now done in SendReceive */ | 3027 | /* above now done in SendReceive */ |
| 3027 | if ((rc == 0) && (tcon != NULL)) { | 3028 | if ((rc == 0) && (tcon != NULL)) { |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d843631c028..bd2a028af83 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -726,12 +726,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 726 | 726 | ||
| 727 | /* BB we could chain these into one lock request BB */ | 727 | /* BB we could chain these into one lock request BB */ |
| 728 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, | 728 | rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, |
| 729 | 0, 1, lockType, 0 /* wait flag */ ); | 729 | 0, 1, lockType, 0 /* wait flag */, 0); |
| 730 | if (rc == 0) { | 730 | if (rc == 0) { |
| 731 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 731 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 732 | pfLock->fl_start, 1 /* numUnlock */ , | 732 | pfLock->fl_start, 1 /* numUnlock */ , |
| 733 | 0 /* numLock */ , lockType, | 733 | 0 /* numLock */ , lockType, |
| 734 | 0 /* wait flag */ ); | 734 | 0 /* wait flag */, 0); |
| 735 | pfLock->fl_type = F_UNLCK; | 735 | pfLock->fl_type = F_UNLCK; |
| 736 | if (rc != 0) | 736 | if (rc != 0) |
| 737 | cERROR(1, "Error unlocking previously locked " | 737 | cERROR(1, "Error unlocking previously locked " |
| @@ -748,13 +748,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 748 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 748 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 749 | pfLock->fl_start, 0, 1, | 749 | pfLock->fl_start, 0, 1, |
| 750 | lockType | LOCKING_ANDX_SHARED_LOCK, | 750 | lockType | LOCKING_ANDX_SHARED_LOCK, |
| 751 | 0 /* wait flag */); | 751 | 0 /* wait flag */, 0); |
| 752 | if (rc == 0) { | 752 | if (rc == 0) { |
| 753 | rc = CIFSSMBLock(xid, tcon, netfid, | 753 | rc = CIFSSMBLock(xid, tcon, netfid, |
| 754 | length, pfLock->fl_start, 1, 0, | 754 | length, pfLock->fl_start, 1, 0, |
| 755 | lockType | | 755 | lockType | |
| 756 | LOCKING_ANDX_SHARED_LOCK, | 756 | LOCKING_ANDX_SHARED_LOCK, |
| 757 | 0 /* wait flag */); | 757 | 0 /* wait flag */, 0); |
| 758 | pfLock->fl_type = F_RDLCK; | 758 | pfLock->fl_type = F_RDLCK; |
| 759 | if (rc != 0) | 759 | if (rc != 0) |
| 760 | cERROR(1, "Error unlocking " | 760 | cERROR(1, "Error unlocking " |
| @@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 797 | 797 | ||
| 798 | if (numLock) { | 798 | if (numLock) { |
| 799 | rc = CIFSSMBLock(xid, tcon, netfid, length, | 799 | rc = CIFSSMBLock(xid, tcon, netfid, length, |
| 800 | pfLock->fl_start, | 800 | pfLock->fl_start, 0, numLock, lockType, |
| 801 | 0, numLock, lockType, wait_flag); | 801 | wait_flag, 0); |
| 802 | 802 | ||
| 803 | if (rc == 0) { | 803 | if (rc == 0) { |
| 804 | /* For Windows locks we must store them. */ | 804 | /* For Windows locks we must store them. */ |
| @@ -818,9 +818,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 818 | (pfLock->fl_start + length) >= | 818 | (pfLock->fl_start + length) >= |
| 819 | (li->offset + li->length)) { | 819 | (li->offset + li->length)) { |
| 820 | stored_rc = CIFSSMBLock(xid, tcon, | 820 | stored_rc = CIFSSMBLock(xid, tcon, |
| 821 | netfid, | 821 | netfid, li->length, |
| 822 | li->length, li->offset, | 822 | li->offset, 1, 0, |
| 823 | 1, 0, li->type, false); | 823 | li->type, false, 0); |
| 824 | if (stored_rc) | 824 | if (stored_rc) |
| 825 | rc = stored_rc; | 825 | rc = stored_rc; |
| 826 | else { | 826 | else { |
| @@ -839,29 +839,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 839 | return rc; | 839 | return rc; |
| 840 | } | 840 | } |
| 841 | 841 | ||
| 842 | /* | ||
| 843 | * Set the timeout on write requests past EOF. For some servers (Windows) | ||
| 844 | * these calls can be very long. | ||
| 845 | * | ||
| 846 | * If we're writing >10M past the EOF we give a 180s timeout. Anything less | ||
| 847 | * than that gets a 45s timeout. Writes not past EOF get 15s timeouts. | ||
| 848 | * The 10M cutoff is totally arbitrary. A better scheme for this would be | ||
| 849 | * welcome if someone wants to suggest one. | ||
| 850 | * | ||
| 851 | * We may be able to do a better job with this if there were some way to | ||
| 852 | * declare that a file should be sparse. | ||
| 853 | */ | ||
| 854 | static int | ||
| 855 | cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset) | ||
| 856 | { | ||
| 857 | if (offset <= cifsi->server_eof) | ||
| 858 | return CIFS_STD_OP; | ||
| 859 | else if (offset > (cifsi->server_eof + (10 * 1024 * 1024))) | ||
| 860 | return CIFS_VLONG_OP; | ||
| 861 | else | ||
| 862 | return CIFS_LONG_OP; | ||
| 863 | } | ||
| 864 | |||
| 865 | /* update the file size (if needed) after a write */ | 842 | /* update the file size (if needed) after a write */ |
| 866 | static void | 843 | static void |
| 867 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 844 | cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
| @@ -882,7 +859,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 882 | unsigned int total_written; | 859 | unsigned int total_written; |
| 883 | struct cifs_sb_info *cifs_sb; | 860 | struct cifs_sb_info *cifs_sb; |
| 884 | struct cifsTconInfo *pTcon; | 861 | struct cifsTconInfo *pTcon; |
| 885 | int xid, long_op; | 862 | int xid; |
| 886 | struct cifsFileInfo *open_file; | 863 | struct cifsFileInfo *open_file; |
| 887 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 864 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
| 888 | 865 | ||
| @@ -903,7 +880,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 903 | 880 | ||
| 904 | xid = GetXid(); | 881 | xid = GetXid(); |
| 905 | 882 | ||
| 906 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
| 907 | for (total_written = 0; write_size > total_written; | 883 | for (total_written = 0; write_size > total_written; |
| 908 | total_written += bytes_written) { | 884 | total_written += bytes_written) { |
| 909 | rc = -EAGAIN; | 885 | rc = -EAGAIN; |
| @@ -931,7 +907,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 931 | min_t(const int, cifs_sb->wsize, | 907 | min_t(const int, cifs_sb->wsize, |
| 932 | write_size - total_written), | 908 | write_size - total_written), |
| 933 | *poffset, &bytes_written, | 909 | *poffset, &bytes_written, |
| 934 | NULL, write_data + total_written, long_op); | 910 | NULL, write_data + total_written, 0); |
| 935 | } | 911 | } |
| 936 | if (rc || (bytes_written == 0)) { | 912 | if (rc || (bytes_written == 0)) { |
| 937 | if (total_written) | 913 | if (total_written) |
| @@ -944,8 +920,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 944 | cifs_update_eof(cifsi, *poffset, bytes_written); | 920 | cifs_update_eof(cifsi, *poffset, bytes_written); |
| 945 | *poffset += bytes_written; | 921 | *poffset += bytes_written; |
| 946 | } | 922 | } |
| 947 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
| 948 | 15 seconds is plenty */ | ||
| 949 | } | 923 | } |
| 950 | 924 | ||
| 951 | cifs_stats_bytes_written(pTcon, total_written); | 925 | cifs_stats_bytes_written(pTcon, total_written); |
| @@ -974,7 +948,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 974 | unsigned int total_written; | 948 | unsigned int total_written; |
| 975 | struct cifs_sb_info *cifs_sb; | 949 | struct cifs_sb_info *cifs_sb; |
| 976 | struct cifsTconInfo *pTcon; | 950 | struct cifsTconInfo *pTcon; |
| 977 | int xid, long_op; | 951 | int xid; |
| 978 | struct dentry *dentry = open_file->dentry; | 952 | struct dentry *dentry = open_file->dentry; |
| 979 | struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); | 953 | struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); |
| 980 | 954 | ||
| @@ -987,7 +961,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 987 | 961 | ||
| 988 | xid = GetXid(); | 962 | xid = GetXid(); |
| 989 | 963 | ||
| 990 | long_op = cifs_write_timeout(cifsi, *poffset); | ||
| 991 | for (total_written = 0; write_size > total_written; | 964 | for (total_written = 0; write_size > total_written; |
| 992 | total_written += bytes_written) { | 965 | total_written += bytes_written) { |
| 993 | rc = -EAGAIN; | 966 | rc = -EAGAIN; |
| @@ -1017,7 +990,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1017 | rc = CIFSSMBWrite2(xid, pTcon, | 990 | rc = CIFSSMBWrite2(xid, pTcon, |
| 1018 | open_file->netfid, len, | 991 | open_file->netfid, len, |
| 1019 | *poffset, &bytes_written, | 992 | *poffset, &bytes_written, |
| 1020 | iov, 1, long_op); | 993 | iov, 1, 0); |
| 1021 | } else | 994 | } else |
| 1022 | rc = CIFSSMBWrite(xid, pTcon, | 995 | rc = CIFSSMBWrite(xid, pTcon, |
| 1023 | open_file->netfid, | 996 | open_file->netfid, |
| @@ -1025,7 +998,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1025 | write_size - total_written), | 998 | write_size - total_written), |
| 1026 | *poffset, &bytes_written, | 999 | *poffset, &bytes_written, |
| 1027 | write_data + total_written, | 1000 | write_data + total_written, |
| 1028 | NULL, long_op); | 1001 | NULL, 0); |
| 1029 | } | 1002 | } |
| 1030 | if (rc || (bytes_written == 0)) { | 1003 | if (rc || (bytes_written == 0)) { |
| 1031 | if (total_written) | 1004 | if (total_written) |
| @@ -1038,8 +1011,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
| 1038 | cifs_update_eof(cifsi, *poffset, bytes_written); | 1011 | cifs_update_eof(cifsi, *poffset, bytes_written); |
| 1039 | *poffset += bytes_written; | 1012 | *poffset += bytes_written; |
| 1040 | } | 1013 | } |
| 1041 | long_op = CIFS_STD_OP; /* subsequent writes fast - | ||
| 1042 | 15 seconds is plenty */ | ||
| 1043 | } | 1014 | } |
| 1044 | 1015 | ||
| 1045 | cifs_stats_bytes_written(pTcon, total_written); | 1016 | cifs_stats_bytes_written(pTcon, total_written); |
| @@ -1239,7 +1210,7 @@ static int cifs_writepages(struct address_space *mapping, | |||
| 1239 | struct pagevec pvec; | 1210 | struct pagevec pvec; |
| 1240 | int rc = 0; | 1211 | int rc = 0; |
| 1241 | int scanned = 0; | 1212 | int scanned = 0; |
| 1242 | int xid, long_op; | 1213 | int xid; |
| 1243 | 1214 | ||
| 1244 | cifs_sb = CIFS_SB(mapping->host->i_sb); | 1215 | cifs_sb = CIFS_SB(mapping->host->i_sb); |
| 1245 | 1216 | ||
| @@ -1377,43 +1348,67 @@ retry: | |||
| 1377 | break; | 1348 | break; |
| 1378 | } | 1349 | } |
| 1379 | if (n_iov) { | 1350 | if (n_iov) { |
| 1351 | retry_write: | ||
| 1380 | open_file = find_writable_file(CIFS_I(mapping->host), | 1352 | open_file = find_writable_file(CIFS_I(mapping->host), |
| 1381 | false); | 1353 | false); |
| 1382 | if (!open_file) { | 1354 | if (!open_file) { |
| 1383 | cERROR(1, "No writable handles for inode"); | 1355 | cERROR(1, "No writable handles for inode"); |
| 1384 | rc = -EBADF; | 1356 | rc = -EBADF; |
| 1385 | } else { | 1357 | } else { |
| 1386 | long_op = cifs_write_timeout(cifsi, offset); | ||
| 1387 | rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, | 1358 | rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, |
| 1388 | bytes_to_write, offset, | 1359 | bytes_to_write, offset, |
| 1389 | &bytes_written, iov, n_iov, | 1360 | &bytes_written, iov, n_iov, |
| 1390 | long_op); | 1361 | 0); |
| 1391 | cifsFileInfo_put(open_file); | 1362 | cifsFileInfo_put(open_file); |
| 1392 | cifs_update_eof(cifsi, offset, bytes_written); | ||
| 1393 | } | 1363 | } |
| 1394 | 1364 | ||
| 1395 | if (rc || bytes_written < bytes_to_write) { | 1365 | cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written); |
| 1396 | cERROR(1, "Write2 ret %d, wrote %d", | 1366 | |
| 1397 | rc, bytes_written); | 1367 | /* |
| 1398 | mapping_set_error(mapping, rc); | 1368 | * For now, treat a short write as if nothing got |
| 1399 | } else { | 1369 | * written. A zero length write however indicates |
| 1370 | * ENOSPC or EFBIG. We have no way to know which | ||
| 1371 | * though, so call it ENOSPC for now. EFBIG would | ||
| 1372 | * get translated to AS_EIO anyway. | ||
| 1373 | * | ||
| 1374 | * FIXME: make it take into account the data that did | ||
| 1375 | * get written | ||
| 1376 | */ | ||
| 1377 | if (rc == 0) { | ||
| 1378 | if (bytes_written == 0) | ||
| 1379 | rc = -ENOSPC; | ||
| 1380 | else if (bytes_written < bytes_to_write) | ||
| 1381 | rc = -EAGAIN; | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | /* retry on data-integrity flush */ | ||
| 1385 | if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) | ||
| 1386 | goto retry_write; | ||
| 1387 | |||
| 1388 | /* fix the stats and EOF */ | ||
| 1389 | if (bytes_written > 0) { | ||
| 1400 | cifs_stats_bytes_written(tcon, bytes_written); | 1390 | cifs_stats_bytes_written(tcon, bytes_written); |
| 1391 | cifs_update_eof(cifsi, offset, bytes_written); | ||
| 1401 | } | 1392 | } |
| 1402 | 1393 | ||
| 1403 | for (i = 0; i < n_iov; i++) { | 1394 | for (i = 0; i < n_iov; i++) { |
| 1404 | page = pvec.pages[first + i]; | 1395 | page = pvec.pages[first + i]; |
| 1405 | /* Should we also set page error on | 1396 | /* on retryable write error, redirty page */ |
| 1406 | success rc but too little data written? */ | 1397 | if (rc == -EAGAIN) |
| 1407 | /* BB investigate retry logic on temporary | 1398 | redirty_page_for_writepage(wbc, page); |
| 1408 | server crash cases and how recovery works | 1399 | else if (rc != 0) |
| 1409 | when page marked as error */ | ||
| 1410 | if (rc) | ||
| 1411 | SetPageError(page); | 1400 | SetPageError(page); |
| 1412 | kunmap(page); | 1401 | kunmap(page); |
| 1413 | unlock_page(page); | 1402 | unlock_page(page); |
| 1414 | end_page_writeback(page); | 1403 | end_page_writeback(page); |
| 1415 | page_cache_release(page); | 1404 | page_cache_release(page); |
| 1416 | } | 1405 | } |
| 1406 | |||
| 1407 | if (rc != -EAGAIN) | ||
| 1408 | mapping_set_error(mapping, rc); | ||
| 1409 | else | ||
| 1410 | rc = 0; | ||
| 1411 | |||
| 1417 | if ((wbc->nr_to_write -= n_iov) <= 0) | 1412 | if ((wbc->nr_to_write -= n_iov) <= 0) |
| 1418 | done = 1; | 1413 | done = 1; |
| 1419 | index = next; | 1414 | index = next; |
| @@ -2192,7 +2187,8 @@ void cifs_oplock_break(struct work_struct *work) | |||
| 2192 | */ | 2187 | */ |
| 2193 | if (!cfile->oplock_break_cancelled) { | 2188 | if (!cfile->oplock_break_cancelled) { |
| 2194 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, | 2189 | rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, |
| 2195 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); | 2190 | 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false, |
| 2191 | cinode->clientCanCacheRead ? 1 : 0); | ||
| 2196 | cFYI(1, "Oplock release rc = %d", rc); | 2192 | cFYI(1, "Oplock release rc = %d", rc); |
| 2197 | } | 2193 | } |
| 2198 | 2194 | ||
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 43f10281bc1..09bfcf08a90 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); | 571 | pCifsInode = CIFS_I(netfile->dentry->d_inode); |
| 572 | 572 | ||
| 573 | cifs_set_oplock_level(pCifsInode, | 573 | cifs_set_oplock_level(pCifsInode, |
| 574 | pSMB->OplockLevel); | 574 | pSMB->OplockLevel ? OPLOCK_READ : 0); |
| 575 | /* | 575 | /* |
| 576 | * cifs_oplock_break_put() can't be called | 576 | * cifs_oplock_break_put() can't be called |
| 577 | * from here. Get reference after queueing | 577 | * from here. Get reference after queueing |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index eb746486e49..1cffd82c4f1 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -879,7 +879,7 @@ ssetup_ntlmssp_authenticate: | |||
| 879 | BCC_LE(smb_buf) = cpu_to_le16(count); | 879 | BCC_LE(smb_buf) = cpu_to_le16(count); |
| 880 | 880 | ||
| 881 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, | 881 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, |
| 882 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | 882 | CIFS_LOG_ERROR); |
| 883 | /* SMB request buf freed in SendReceive2 */ | 883 | /* SMB request buf freed in SendReceive2 */ |
| 884 | 884 | ||
| 885 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; | 885 | pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 59ca81b1691..c8e2808cd5e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -36,7 +36,13 @@ | |||
| 36 | 36 | ||
| 37 | extern mempool_t *cifs_mid_poolp; | 37 | extern mempool_t *cifs_mid_poolp; |
| 38 | 38 | ||
| 39 | static struct mid_q_entry * | 39 | static void |
| 40 | wake_up_task(struct mid_q_entry *mid) | ||
| 41 | { | ||
| 42 | wake_up_process(mid->callback_data); | ||
| 43 | } | ||
| 44 | |||
| 45 | struct mid_q_entry * | ||
| 40 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | 46 | AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) |
| 41 | { | 47 | { |
| 42 | struct mid_q_entry *temp; | 48 | struct mid_q_entry *temp; |
| @@ -58,28 +64,28 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) | |||
| 58 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ | 64 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
| 59 | /* when mid allocated can be before when sent */ | 65 | /* when mid allocated can be before when sent */ |
| 60 | temp->when_alloc = jiffies; | 66 | temp->when_alloc = jiffies; |
| 61 | temp->tsk = current; | 67 | |
| 68 | /* | ||
| 69 | * The default is for the mid to be synchronous, so the | ||
| 70 | * default callback just wakes up the current task. | ||
| 71 | */ | ||
| 72 | temp->callback = wake_up_task; | ||
| 73 | temp->callback_data = current; | ||
| 62 | } | 74 | } |
| 63 | 75 | ||
| 64 | spin_lock(&GlobalMid_Lock); | ||
| 65 | list_add_tail(&temp->qhead, &server->pending_mid_q); | ||
| 66 | atomic_inc(&midCount); | 76 | atomic_inc(&midCount); |
| 67 | temp->midState = MID_REQUEST_ALLOCATED; | 77 | temp->midState = MID_REQUEST_ALLOCATED; |
| 68 | spin_unlock(&GlobalMid_Lock); | ||
| 69 | return temp; | 78 | return temp; |
| 70 | } | 79 | } |
| 71 | 80 | ||
| 72 | static void | 81 | void |
| 73 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 82 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
| 74 | { | 83 | { |
| 75 | #ifdef CONFIG_CIFS_STATS2 | 84 | #ifdef CONFIG_CIFS_STATS2 |
| 76 | unsigned long now; | 85 | unsigned long now; |
| 77 | #endif | 86 | #endif |
| 78 | spin_lock(&GlobalMid_Lock); | ||
| 79 | midEntry->midState = MID_FREE; | 87 | midEntry->midState = MID_FREE; |
| 80 | list_del(&midEntry->qhead); | ||
| 81 | atomic_dec(&midCount); | 88 | atomic_dec(&midCount); |
| 82 | spin_unlock(&GlobalMid_Lock); | ||
| 83 | if (midEntry->largeBuf) | 89 | if (midEntry->largeBuf) |
| 84 | cifs_buf_release(midEntry->resp_buf); | 90 | cifs_buf_release(midEntry->resp_buf); |
| 85 | else | 91 | else |
| @@ -103,6 +109,16 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
| 103 | mempool_free(midEntry, cifs_mid_poolp); | 109 | mempool_free(midEntry, cifs_mid_poolp); |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 112 | static void | ||
| 113 | delete_mid(struct mid_q_entry *mid) | ||
| 114 | { | ||
| 115 | spin_lock(&GlobalMid_Lock); | ||
| 116 | list_del(&mid->qhead); | ||
| 117 | spin_unlock(&GlobalMid_Lock); | ||
| 118 | |||
| 119 | DeleteMidQEntry(mid); | ||
| 120 | } | ||
| 121 | |||
| 106 | static int | 122 | static int |
| 107 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | 123 | smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) |
| 108 | { | 124 | { |
| @@ -244,31 +260,31 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
| 244 | return smb_sendv(server, &iov, 1); | 260 | return smb_sendv(server, &iov, 1); |
| 245 | } | 261 | } |
| 246 | 262 | ||
| 247 | static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | 263 | static int wait_for_free_request(struct TCP_Server_Info *server, |
| 264 | const int long_op) | ||
| 248 | { | 265 | { |
| 249 | if (long_op == CIFS_ASYNC_OP) { | 266 | if (long_op == CIFS_ASYNC_OP) { |
| 250 | /* oplock breaks must not be held up */ | 267 | /* oplock breaks must not be held up */ |
| 251 | atomic_inc(&ses->server->inFlight); | 268 | atomic_inc(&server->inFlight); |
| 252 | return 0; | 269 | return 0; |
| 253 | } | 270 | } |
| 254 | 271 | ||
| 255 | spin_lock(&GlobalMid_Lock); | 272 | spin_lock(&GlobalMid_Lock); |
| 256 | while (1) { | 273 | while (1) { |
| 257 | if (atomic_read(&ses->server->inFlight) >= | 274 | if (atomic_read(&server->inFlight) >= cifs_max_pending) { |
| 258 | cifs_max_pending){ | ||
| 259 | spin_unlock(&GlobalMid_Lock); | 275 | spin_unlock(&GlobalMid_Lock); |
| 260 | #ifdef CONFIG_CIFS_STATS2 | 276 | #ifdef CONFIG_CIFS_STATS2 |
| 261 | atomic_inc(&ses->server->num_waiters); | 277 | atomic_inc(&server->num_waiters); |
| 262 | #endif | 278 | #endif |
| 263 | wait_event(ses->server->request_q, | 279 | wait_event(server->request_q, |
| 264 | atomic_read(&ses->server->inFlight) | 280 | atomic_read(&server->inFlight) |
| 265 | < cifs_max_pending); | 281 | < cifs_max_pending); |
| 266 | #ifdef CONFIG_CIFS_STATS2 | 282 | #ifdef CONFIG_CIFS_STATS2 |
| 267 | atomic_dec(&ses->server->num_waiters); | 283 | atomic_dec(&server->num_waiters); |
| 268 | #endif | 284 | #endif |
| 269 | spin_lock(&GlobalMid_Lock); | 285 | spin_lock(&GlobalMid_Lock); |
| 270 | } else { | 286 | } else { |
| 271 | if (ses->server->tcpStatus == CifsExiting) { | 287 | if (server->tcpStatus == CifsExiting) { |
| 272 | spin_unlock(&GlobalMid_Lock); | 288 | spin_unlock(&GlobalMid_Lock); |
| 273 | return -ENOENT; | 289 | return -ENOENT; |
| 274 | } | 290 | } |
| @@ -278,7 +294,7 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op) | |||
| 278 | 294 | ||
| 279 | /* update # of requests on the wire to server */ | 295 | /* update # of requests on the wire to server */ |
| 280 | if (long_op != CIFS_BLOCKING_OP) | 296 | if (long_op != CIFS_BLOCKING_OP) |
| 281 | atomic_inc(&ses->server->inFlight); | 297 | atomic_inc(&server->inFlight); |
| 282 | spin_unlock(&GlobalMid_Lock); | 298 | spin_unlock(&GlobalMid_Lock); |
| 283 | break; | 299 | break; |
| 284 | } | 300 | } |
| @@ -308,53 +324,81 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, | |||
| 308 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); | 324 | *ppmidQ = AllocMidQEntry(in_buf, ses->server); |
| 309 | if (*ppmidQ == NULL) | 325 | if (*ppmidQ == NULL) |
| 310 | return -ENOMEM; | 326 | return -ENOMEM; |
| 327 | spin_lock(&GlobalMid_Lock); | ||
| 328 | list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); | ||
| 329 | spin_unlock(&GlobalMid_Lock); | ||
| 311 | return 0; | 330 | return 0; |
| 312 | } | 331 | } |
| 313 | 332 | ||
| 314 | static int wait_for_response(struct cifsSesInfo *ses, | 333 | static int |
| 315 | struct mid_q_entry *midQ, | 334 | wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) |
| 316 | unsigned long timeout, | ||
| 317 | unsigned long time_to_wait) | ||
| 318 | { | 335 | { |
| 319 | unsigned long curr_timeout; | 336 | int error; |
| 320 | 337 | ||
| 321 | for (;;) { | 338 | error = wait_event_killable(server->response_q, |
| 322 | curr_timeout = timeout + jiffies; | 339 | midQ->midState != MID_REQUEST_SUBMITTED); |
| 323 | wait_event_timeout(ses->server->response_q, | 340 | if (error < 0) |
| 324 | midQ->midState != MID_REQUEST_SUBMITTED, timeout); | 341 | return -ERESTARTSYS; |
| 325 | 342 | ||
| 326 | if (time_after(jiffies, curr_timeout) && | 343 | return 0; |
| 327 | (midQ->midState == MID_REQUEST_SUBMITTED) && | 344 | } |
| 328 | ((ses->server->tcpStatus == CifsGood) || | ||
| 329 | (ses->server->tcpStatus == CifsNew))) { | ||
| 330 | 345 | ||
| 331 | unsigned long lrt; | ||
| 332 | 346 | ||
| 333 | /* We timed out. Is the server still | 347 | /* |
| 334 | sending replies ? */ | 348 | * Send a SMB request and set the callback function in the mid to handle |
| 335 | spin_lock(&GlobalMid_Lock); | 349 | * the result. Caller is responsible for dealing with timeouts. |
| 336 | lrt = ses->server->lstrp; | 350 | */ |
| 337 | spin_unlock(&GlobalMid_Lock); | 351 | int |
| 352 | cifs_call_async(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
| 353 | mid_callback_t *callback, void *cbdata) | ||
| 354 | { | ||
| 355 | int rc; | ||
| 356 | struct mid_q_entry *mid; | ||
| 338 | 357 | ||
| 339 | /* Calculate time_to_wait past last receive time. | 358 | rc = wait_for_free_request(server, CIFS_ASYNC_OP); |
| 340 | Although we prefer not to time out if the | 359 | if (rc) |
| 341 | server is still responding - we will time | 360 | return rc; |
| 342 | out if the server takes more than 15 (or 45 | 361 | |
| 343 | or 180) seconds to respond to this request | 362 | mutex_lock(&server->srv_mutex); |
| 344 | and has not responded to any request from | 363 | mid = AllocMidQEntry(in_buf, server); |
| 345 | other threads on the client within 10 seconds */ | 364 | if (mid == NULL) { |
| 346 | lrt += time_to_wait; | 365 | mutex_unlock(&server->srv_mutex); |
| 347 | if (time_after(jiffies, lrt)) { | 366 | return -ENOMEM; |
| 348 | /* No replies for time_to_wait. */ | ||
| 349 | cERROR(1, "server not responding"); | ||
| 350 | return -1; | ||
| 351 | } | ||
| 352 | } else { | ||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | } | 367 | } |
| 356 | } | ||
| 357 | 368 | ||
| 369 | /* put it on the pending_mid_q */ | ||
| 370 | spin_lock(&GlobalMid_Lock); | ||
| 371 | list_add_tail(&mid->qhead, &server->pending_mid_q); | ||
| 372 | spin_unlock(&GlobalMid_Lock); | ||
| 373 | |||
| 374 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
| 375 | if (rc) { | ||
| 376 | mutex_unlock(&server->srv_mutex); | ||
| 377 | goto out_err; | ||
| 378 | } | ||
| 379 | |||
| 380 | mid->callback = callback; | ||
| 381 | mid->callback_data = cbdata; | ||
| 382 | mid->midState = MID_REQUEST_SUBMITTED; | ||
| 383 | #ifdef CONFIG_CIFS_STATS2 | ||
| 384 | atomic_inc(&server->inSend); | ||
| 385 | #endif | ||
| 386 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
| 387 | #ifdef CONFIG_CIFS_STATS2 | ||
| 388 | atomic_dec(&server->inSend); | ||
| 389 | mid->when_sent = jiffies; | ||
| 390 | #endif | ||
| 391 | mutex_unlock(&server->srv_mutex); | ||
| 392 | if (rc) | ||
| 393 | goto out_err; | ||
| 394 | |||
| 395 | return rc; | ||
| 396 | out_err: | ||
| 397 | delete_mid(mid); | ||
| 398 | atomic_dec(&server->inFlight); | ||
| 399 | wake_up(&server->request_q); | ||
| 400 | return rc; | ||
| 401 | } | ||
| 358 | 402 | ||
| 359 | /* | 403 | /* |
| 360 | * | 404 | * |
| @@ -382,6 +426,81 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 382 | return rc; | 426 | return rc; |
| 383 | } | 427 | } |
| 384 | 428 | ||
| 429 | static int | ||
| 430 | sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) | ||
| 431 | { | ||
| 432 | int rc = 0; | ||
| 433 | |||
| 434 | cFYI(1, "%s: cmd=%d mid=%d state=%d", __func__, mid->command, | ||
| 435 | mid->mid, mid->midState); | ||
| 436 | |||
| 437 | spin_lock(&GlobalMid_Lock); | ||
| 438 | /* ensure that it's no longer on the pending_mid_q */ | ||
| 439 | list_del_init(&mid->qhead); | ||
| 440 | |||
| 441 | switch (mid->midState) { | ||
| 442 | case MID_RESPONSE_RECEIVED: | ||
| 443 | spin_unlock(&GlobalMid_Lock); | ||
| 444 | return rc; | ||
| 445 | case MID_REQUEST_SUBMITTED: | ||
| 446 | /* socket is going down, reject all calls */ | ||
| 447 | if (server->tcpStatus == CifsExiting) { | ||
| 448 | cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d", | ||
| 449 | __func__, mid->mid, mid->command, mid->midState); | ||
| 450 | rc = -EHOSTDOWN; | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | case MID_RETRY_NEEDED: | ||
| 454 | rc = -EAGAIN; | ||
| 455 | break; | ||
| 456 | default: | ||
| 457 | cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, | ||
| 458 | mid->mid, mid->midState); | ||
| 459 | rc = -EIO; | ||
| 460 | } | ||
| 461 | spin_unlock(&GlobalMid_Lock); | ||
| 462 | |||
| 463 | DeleteMidQEntry(mid); | ||
| 464 | return rc; | ||
| 465 | } | ||
| 466 | |||
| 467 | /* | ||
| 468 | * An NT cancel request header looks just like the original request except: | ||
| 469 | * | ||
| 470 | * The Command is SMB_COM_NT_CANCEL | ||
| 471 | * The WordCount is zeroed out | ||
| 472 | * The ByteCount is zeroed out | ||
| 473 | * | ||
| 474 | * This function mangles an existing request buffer into a | ||
| 475 | * SMB_COM_NT_CANCEL request and then sends it. | ||
| 476 | */ | ||
| 477 | static int | ||
| 478 | send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, | ||
| 479 | struct mid_q_entry *mid) | ||
| 480 | { | ||
| 481 | int rc = 0; | ||
| 482 | |||
| 483 | /* -4 for RFC1001 length and +2 for BCC field */ | ||
| 484 | in_buf->smb_buf_length = sizeof(struct smb_hdr) - 4 + 2; | ||
| 485 | in_buf->Command = SMB_COM_NT_CANCEL; | ||
| 486 | in_buf->WordCount = 0; | ||
| 487 | BCC_LE(in_buf) = 0; | ||
| 488 | |||
| 489 | mutex_lock(&server->srv_mutex); | ||
| 490 | rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); | ||
| 491 | if (rc) { | ||
| 492 | mutex_unlock(&server->srv_mutex); | ||
| 493 | return rc; | ||
| 494 | } | ||
| 495 | rc = smb_send(server, in_buf, in_buf->smb_buf_length); | ||
| 496 | mutex_unlock(&server->srv_mutex); | ||
| 497 | |||
| 498 | cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", | ||
| 499 | in_buf->Mid, rc); | ||
| 500 | |||
| 501 | return rc; | ||
| 502 | } | ||
| 503 | |||
| 385 | int | 504 | int |
| 386 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 505 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
| 387 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, | 506 | struct kvec *iov, int n_vec, int *pRespBufType /* ret */, |
| @@ -390,7 +509,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 390 | int rc = 0; | 509 | int rc = 0; |
| 391 | int long_op; | 510 | int long_op; |
| 392 | unsigned int receive_len; | 511 | unsigned int receive_len; |
| 393 | unsigned long timeout; | ||
| 394 | struct mid_q_entry *midQ; | 512 | struct mid_q_entry *midQ; |
| 395 | struct smb_hdr *in_buf = iov[0].iov_base; | 513 | struct smb_hdr *in_buf = iov[0].iov_base; |
| 396 | 514 | ||
| @@ -413,7 +531,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 413 | to the same server. We may make this configurable later or | 531 | to the same server. We may make this configurable later or |
| 414 | use ses->maxReq */ | 532 | use ses->maxReq */ |
| 415 | 533 | ||
| 416 | rc = wait_for_free_request(ses, long_op); | 534 | rc = wait_for_free_request(ses->server, long_op); |
| 417 | if (rc) { | 535 | if (rc) { |
| 418 | cifs_small_buf_release(in_buf); | 536 | cifs_small_buf_release(in_buf); |
| 419 | return rc; | 537 | return rc; |
| @@ -457,65 +575,20 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 457 | if (rc < 0) | 575 | if (rc < 0) |
| 458 | goto out; | 576 | goto out; |
| 459 | 577 | ||
| 460 | if (long_op == CIFS_STD_OP) | 578 | if (long_op == CIFS_ASYNC_OP) |
| 461 | timeout = 15 * HZ; | ||
| 462 | else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */ | ||
| 463 | timeout = 180 * HZ; | ||
| 464 | else if (long_op == CIFS_LONG_OP) | ||
| 465 | timeout = 45 * HZ; /* should be greater than | ||
| 466 | servers oplock break timeout (about 43 seconds) */ | ||
| 467 | else if (long_op == CIFS_ASYNC_OP) | ||
| 468 | goto out; | 579 | goto out; |
| 469 | else if (long_op == CIFS_BLOCKING_OP) | ||
| 470 | timeout = 0x7FFFFFFF; /* large, but not so large as to wrap */ | ||
| 471 | else { | ||
| 472 | cERROR(1, "unknown timeout flag %d", long_op); | ||
| 473 | rc = -EIO; | ||
| 474 | goto out; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 478 | due to last connection to this server being unmounted */ | ||
| 479 | if (signal_pending(current)) { | ||
| 480 | /* if signal pending do not hold up user for full smb timeout | ||
| 481 | but we still give response a chance to complete */ | ||
| 482 | timeout = 2 * HZ; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
| 486 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
| 487 | |||
| 488 | spin_lock(&GlobalMid_Lock); | ||
| 489 | 580 | ||
| 490 | if (midQ->resp_buf == NULL) { | 581 | rc = wait_for_response(ses->server, midQ); |
| 491 | cERROR(1, "No response to cmd %d mid %d", | 582 | if (rc != 0) |
| 492 | midQ->command, midQ->mid); | 583 | goto out; |
| 493 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 494 | if (ses->server->tcpStatus == CifsExiting) | ||
| 495 | rc = -EHOSTDOWN; | ||
| 496 | else { | ||
| 497 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 498 | midQ->midState = MID_RETRY_NEEDED; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | 584 | ||
| 502 | if (rc != -EHOSTDOWN) { | 585 | rc = sync_mid_result(midQ, ses->server); |
| 503 | if (midQ->midState == MID_RETRY_NEEDED) { | 586 | if (rc != 0) { |
| 504 | rc = -EAGAIN; | ||
| 505 | cFYI(1, "marking request for retry"); | ||
| 506 | } else { | ||
| 507 | rc = -EIO; | ||
| 508 | } | ||
| 509 | } | ||
| 510 | spin_unlock(&GlobalMid_Lock); | ||
| 511 | DeleteMidQEntry(midQ); | ||
| 512 | /* Update # of requests on wire to server */ | ||
| 513 | atomic_dec(&ses->server->inFlight); | 587 | atomic_dec(&ses->server->inFlight); |
| 514 | wake_up(&ses->server->request_q); | 588 | wake_up(&ses->server->request_q); |
| 515 | return rc; | 589 | return rc; |
| 516 | } | 590 | } |
| 517 | 591 | ||
| 518 | spin_unlock(&GlobalMid_Lock); | ||
| 519 | receive_len = midQ->resp_buf->smb_buf_length; | 592 | receive_len = midQ->resp_buf->smb_buf_length; |
| 520 | 593 | ||
| 521 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 594 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| @@ -564,14 +637,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 564 | if ((flags & CIFS_NO_RESP) == 0) | 637 | if ((flags & CIFS_NO_RESP) == 0) |
| 565 | midQ->resp_buf = NULL; /* mark it so buf will | 638 | midQ->resp_buf = NULL; /* mark it so buf will |
| 566 | not be freed by | 639 | not be freed by |
| 567 | DeleteMidQEntry */ | 640 | delete_mid */ |
| 568 | } else { | 641 | } else { |
| 569 | rc = -EIO; | 642 | rc = -EIO; |
| 570 | cFYI(1, "Bad MID state?"); | 643 | cFYI(1, "Bad MID state?"); |
| 571 | } | 644 | } |
| 572 | 645 | ||
| 573 | out: | 646 | out: |
| 574 | DeleteMidQEntry(midQ); | 647 | delete_mid(midQ); |
| 575 | atomic_dec(&ses->server->inFlight); | 648 | atomic_dec(&ses->server->inFlight); |
| 576 | wake_up(&ses->server->request_q); | 649 | wake_up(&ses->server->request_q); |
| 577 | 650 | ||
| @@ -585,7 +658,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 585 | { | 658 | { |
| 586 | int rc = 0; | 659 | int rc = 0; |
| 587 | unsigned int receive_len; | 660 | unsigned int receive_len; |
| 588 | unsigned long timeout; | ||
| 589 | struct mid_q_entry *midQ; | 661 | struct mid_q_entry *midQ; |
| 590 | 662 | ||
| 591 | if (ses == NULL) { | 663 | if (ses == NULL) { |
| @@ -610,7 +682,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 610 | return -EIO; | 682 | return -EIO; |
| 611 | } | 683 | } |
| 612 | 684 | ||
| 613 | rc = wait_for_free_request(ses, long_op); | 685 | rc = wait_for_free_request(ses->server, long_op); |
| 614 | if (rc) | 686 | if (rc) |
| 615 | return rc; | 687 | return rc; |
| 616 | 688 | ||
| @@ -649,64 +721,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 649 | if (rc < 0) | 721 | if (rc < 0) |
| 650 | goto out; | 722 | goto out; |
| 651 | 723 | ||
| 652 | if (long_op == CIFS_STD_OP) | 724 | if (long_op == CIFS_ASYNC_OP) |
| 653 | timeout = 15 * HZ; | ||
| 654 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 655 | due to last connection to this server being unmounted */ | ||
| 656 | else if (long_op == CIFS_ASYNC_OP) | ||
| 657 | goto out; | 725 | goto out; |
| 658 | else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */ | ||
| 659 | timeout = 180 * HZ; | ||
| 660 | else if (long_op == CIFS_LONG_OP) | ||
| 661 | timeout = 45 * HZ; /* should be greater than | ||
| 662 | servers oplock break timeout (about 43 seconds) */ | ||
| 663 | else if (long_op == CIFS_BLOCKING_OP) | ||
| 664 | timeout = 0x7FFFFFFF; /* large but no so large as to wrap */ | ||
| 665 | else { | ||
| 666 | cERROR(1, "unknown timeout flag %d", long_op); | ||
| 667 | rc = -EIO; | ||
| 668 | goto out; | ||
| 669 | } | ||
| 670 | 726 | ||
| 671 | if (signal_pending(current)) { | 727 | rc = wait_for_response(ses->server, midQ); |
| 672 | /* if signal pending do not hold up user for full smb timeout | 728 | if (rc != 0) |
| 673 | but we still give response a chance to complete */ | 729 | goto out; |
| 674 | timeout = 2 * HZ; | ||
| 675 | } | ||
| 676 | |||
| 677 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
| 678 | wait_for_response(ses, midQ, timeout, 10 * HZ); | ||
| 679 | |||
| 680 | spin_lock(&GlobalMid_Lock); | ||
| 681 | if (midQ->resp_buf == NULL) { | ||
| 682 | cERROR(1, "No response for cmd %d mid %d", | ||
| 683 | midQ->command, midQ->mid); | ||
| 684 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 685 | if (ses->server->tcpStatus == CifsExiting) | ||
| 686 | rc = -EHOSTDOWN; | ||
| 687 | else { | ||
| 688 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 689 | midQ->midState = MID_RETRY_NEEDED; | ||
| 690 | } | ||
| 691 | } | ||
| 692 | 730 | ||
| 693 | if (rc != -EHOSTDOWN) { | 731 | rc = sync_mid_result(midQ, ses->server); |
| 694 | if (midQ->midState == MID_RETRY_NEEDED) { | 732 | if (rc != 0) { |
| 695 | rc = -EAGAIN; | ||
| 696 | cFYI(1, "marking request for retry"); | ||
| 697 | } else { | ||
| 698 | rc = -EIO; | ||
| 699 | } | ||
| 700 | } | ||
| 701 | spin_unlock(&GlobalMid_Lock); | ||
| 702 | DeleteMidQEntry(midQ); | ||
| 703 | /* Update # of requests on wire to server */ | ||
| 704 | atomic_dec(&ses->server->inFlight); | 733 | atomic_dec(&ses->server->inFlight); |
| 705 | wake_up(&ses->server->request_q); | 734 | wake_up(&ses->server->request_q); |
| 706 | return rc; | 735 | return rc; |
| 707 | } | 736 | } |
| 708 | 737 | ||
| 709 | spin_unlock(&GlobalMid_Lock); | ||
| 710 | receive_len = midQ->resp_buf->smb_buf_length; | 738 | receive_len = midQ->resp_buf->smb_buf_length; |
| 711 | 739 | ||
| 712 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 740 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| @@ -755,36 +783,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 755 | } | 783 | } |
| 756 | 784 | ||
| 757 | out: | 785 | out: |
| 758 | DeleteMidQEntry(midQ); | 786 | delete_mid(midQ); |
| 759 | atomic_dec(&ses->server->inFlight); | 787 | atomic_dec(&ses->server->inFlight); |
| 760 | wake_up(&ses->server->request_q); | 788 | wake_up(&ses->server->request_q); |
| 761 | 789 | ||
| 762 | return rc; | 790 | return rc; |
| 763 | } | 791 | } |
| 764 | 792 | ||
| 765 | /* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */ | ||
| 766 | |||
| 767 | static int | ||
| 768 | send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | ||
| 769 | struct mid_q_entry *midQ) | ||
| 770 | { | ||
| 771 | int rc = 0; | ||
| 772 | struct cifsSesInfo *ses = tcon->ses; | ||
| 773 | __u16 mid = in_buf->Mid; | ||
| 774 | |||
| 775 | header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0); | ||
| 776 | in_buf->Mid = mid; | ||
| 777 | mutex_lock(&ses->server->srv_mutex); | ||
| 778 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | ||
| 779 | if (rc) { | ||
| 780 | mutex_unlock(&ses->server->srv_mutex); | ||
| 781 | return rc; | ||
| 782 | } | ||
| 783 | rc = smb_send(ses->server, in_buf, in_buf->smb_buf_length); | ||
| 784 | mutex_unlock(&ses->server->srv_mutex); | ||
| 785 | return rc; | ||
| 786 | } | ||
| 787 | |||
| 788 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows | 793 | /* We send a LOCKINGX_CANCEL_LOCK to cause the Windows |
| 789 | blocking lock to return. */ | 794 | blocking lock to return. */ |
| 790 | 795 | ||
| @@ -807,7 +812,7 @@ send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 807 | pSMB->hdr.Mid = GetNextMid(ses->server); | 812 | pSMB->hdr.Mid = GetNextMid(ses->server); |
| 808 | 813 | ||
| 809 | return SendReceive(xid, ses, in_buf, out_buf, | 814 | return SendReceive(xid, ses, in_buf, out_buf, |
| 810 | &bytes_returned, CIFS_STD_OP); | 815 | &bytes_returned, 0); |
| 811 | } | 816 | } |
| 812 | 817 | ||
| 813 | int | 818 | int |
| @@ -845,7 +850,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 845 | return -EIO; | 850 | return -EIO; |
| 846 | } | 851 | } |
| 847 | 852 | ||
| 848 | rc = wait_for_free_request(ses, CIFS_BLOCKING_OP); | 853 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP); |
| 849 | if (rc) | 854 | if (rc) |
| 850 | return rc; | 855 | return rc; |
| 851 | 856 | ||
| @@ -863,7 +868,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 863 | 868 | ||
| 864 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 869 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
| 865 | if (rc) { | 870 | if (rc) { |
| 866 | DeleteMidQEntry(midQ); | 871 | delete_mid(midQ); |
| 867 | mutex_unlock(&ses->server->srv_mutex); | 872 | mutex_unlock(&ses->server->srv_mutex); |
| 868 | return rc; | 873 | return rc; |
| 869 | } | 874 | } |
| @@ -880,7 +885,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 880 | mutex_unlock(&ses->server->srv_mutex); | 885 | mutex_unlock(&ses->server->srv_mutex); |
| 881 | 886 | ||
| 882 | if (rc < 0) { | 887 | if (rc < 0) { |
| 883 | DeleteMidQEntry(midQ); | 888 | delete_mid(midQ); |
| 884 | return rc; | 889 | return rc; |
| 885 | } | 890 | } |
| 886 | 891 | ||
| @@ -899,10 +904,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 899 | if (in_buf->Command == SMB_COM_TRANSACTION2) { | 904 | if (in_buf->Command == SMB_COM_TRANSACTION2) { |
| 900 | /* POSIX lock. We send a NT_CANCEL SMB to cause the | 905 | /* POSIX lock. We send a NT_CANCEL SMB to cause the |
| 901 | blocking lock to return. */ | 906 | blocking lock to return. */ |
| 902 | 907 | rc = send_nt_cancel(ses->server, in_buf, midQ); | |
| 903 | rc = send_nt_cancel(tcon, in_buf, midQ); | ||
| 904 | if (rc) { | 908 | if (rc) { |
| 905 | DeleteMidQEntry(midQ); | 909 | delete_mid(midQ); |
| 906 | return rc; | 910 | return rc; |
| 907 | } | 911 | } |
| 908 | } else { | 912 | } else { |
| @@ -914,47 +918,22 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 914 | /* If we get -ENOLCK back the lock may have | 918 | /* If we get -ENOLCK back the lock may have |
| 915 | already been removed. Don't exit in this case. */ | 919 | already been removed. Don't exit in this case. */ |
| 916 | if (rc && rc != -ENOLCK) { | 920 | if (rc && rc != -ENOLCK) { |
| 917 | DeleteMidQEntry(midQ); | 921 | delete_mid(midQ); |
| 918 | return rc; | 922 | return rc; |
| 919 | } | 923 | } |
| 920 | } | 924 | } |
| 921 | 925 | ||
| 922 | /* Wait 5 seconds for the response. */ | 926 | if (wait_for_response(ses->server, midQ) == 0) { |
| 923 | if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) { | ||
| 924 | /* We got the response - restart system call. */ | 927 | /* We got the response - restart system call. */ |
| 925 | rstart = 1; | 928 | rstart = 1; |
| 926 | } | 929 | } |
| 927 | } | 930 | } |
| 928 | 931 | ||
| 929 | spin_lock(&GlobalMid_Lock); | 932 | rc = sync_mid_result(midQ, ses->server); |
| 930 | if (midQ->resp_buf) { | 933 | if (rc != 0) |
| 931 | spin_unlock(&GlobalMid_Lock); | ||
| 932 | receive_len = midQ->resp_buf->smb_buf_length; | ||
| 933 | } else { | ||
| 934 | cERROR(1, "No response for cmd %d mid %d", | ||
| 935 | midQ->command, midQ->mid); | ||
| 936 | if (midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 937 | if (ses->server->tcpStatus == CifsExiting) | ||
| 938 | rc = -EHOSTDOWN; | ||
| 939 | else { | ||
| 940 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 941 | midQ->midState = MID_RETRY_NEEDED; | ||
| 942 | } | ||
| 943 | } | ||
| 944 | |||
| 945 | if (rc != -EHOSTDOWN) { | ||
| 946 | if (midQ->midState == MID_RETRY_NEEDED) { | ||
| 947 | rc = -EAGAIN; | ||
| 948 | cFYI(1, "marking request for retry"); | ||
| 949 | } else { | ||
| 950 | rc = -EIO; | ||
| 951 | } | ||
| 952 | } | ||
| 953 | spin_unlock(&GlobalMid_Lock); | ||
| 954 | DeleteMidQEntry(midQ); | ||
| 955 | return rc; | 934 | return rc; |
| 956 | } | ||
| 957 | 935 | ||
| 936 | receive_len = midQ->resp_buf->smb_buf_length; | ||
| 958 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 937 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| 959 | cERROR(1, "Frame too large received. Length: %d Xid: %d", | 938 | cERROR(1, "Frame too large received. Length: %d Xid: %d", |
| 960 | receive_len, xid); | 939 | receive_len, xid); |
| @@ -1001,7 +980,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
| 1001 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 980 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); |
| 1002 | 981 | ||
| 1003 | out: | 982 | out: |
| 1004 | DeleteMidQEntry(midQ); | 983 | delete_mid(midQ); |
| 1005 | if (rstart && rc == -EACCES) | 984 | if (rstart && rc == -EACCES) |
| 1006 | return -ERESTARTSYS; | 985 | return -ERESTARTSYS; |
| 1007 | return rc; | 986 | return rc; |
