Commit 5cdec1fc authored by Linus Torvalds's avatar Linus Torvalds

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)
parents e55fdbd7 76dcc26f
...@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server) ...@@ -79,11 +79,11 @@ void cifs_dump_mids(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
list_for_each(tmp, &server->pending_mid_q) { list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead); mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
cERROR(1, "State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %d",
mid_entry->midState, mid_entry->midState,
(int)mid_entry->command, (int)mid_entry->command,
mid_entry->pid, mid_entry->pid,
mid_entry->tsk, mid_entry->callback_data,
mid_entry->mid); mid_entry->mid);
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
cERROR(1, "IsLarge: %d buf: %p time rcv: %ld now: %ld", 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,11 +218,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
mid_entry = list_entry(tmp3, struct mid_q_entry, mid_entry = list_entry(tmp3, struct mid_q_entry,
qhead); qhead);
seq_printf(m, "\tState: %d com: %d pid:" seq_printf(m, "\tState: %d com: %d pid:"
" %d tsk: %p mid %d\n", " %d cbdata: %p mid %d\n",
mid_entry->midState, mid_entry->midState,
(int)mid_entry->command, (int)mid_entry->command,
mid_entry->pid, mid_entry->pid,
mid_entry->tsk, mid_entry->callback_data,
mid_entry->mid); mid_entry->mid);
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) ...@@ -331,7 +331,7 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v)
atomic_read(&totSmBufAllocCount)); atomic_read(&totSmBufAllocCount));
#endif /* CONFIG_CIFS_STATS2 */ #endif /* CONFIG_CIFS_STATS2 */
seq_printf(m, "Operations (MIDs): %d\n", midCount.counter); seq_printf(m, "Operations (MIDs): %d\n", atomic_read(&midCount));
seq_printf(m, seq_printf(m,
"\n%d session %d share reconnects\n", "\n%d session %d share reconnects\n",
tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); tcpSesReconnectCount.counter, tconInfoReconnectCount.counter);
......
...@@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { ...@@ -41,9 +41,12 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
; ;
/* security id for everyone */ /* security id for everyone/world system group */
static const struct cifs_sid sid_everyone = { static const struct cifs_sid sid_everyone = {
1, 1, {0, 0, 0, 0, 0, 1}, {0} }; 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
/* security id for Authenticated Users system group */
static const struct cifs_sid sid_authusers = {
1, 1, {0, 0, 0, 0, 0, 5}, {11} };
/* group users */ /* group users */
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
...@@ -365,7 +368,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -365,7 +368,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
if (num_aces > 0) { if (num_aces > 0) {
umode_t user_mask = S_IRWXU; umode_t user_mask = S_IRWXU;
umode_t group_mask = S_IRWXG; umode_t group_mask = S_IRWXG;
umode_t other_mask = S_IRWXO; umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
GFP_KERNEL); GFP_KERNEL);
...@@ -390,6 +393,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, ...@@ -390,6 +393,12 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
ppace[i]->type, ppace[i]->type,
&fattr->cf_mode, &fattr->cf_mode,
&other_mask); &other_mask);
if (compare_sids(&(ppace[i]->sid), &sid_authusers))
access_flags_to_mode(ppace[i]->access_req,
ppace[i]->type,
&fattr->cf_mode,
&other_mask);
/* memcpy((void *)(&(cifscred->aces[i])), /* memcpy((void *)(&(cifscred->aces[i])),
(void *)ppace[i], (void *)ppace[i],
......
...@@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ; ...@@ -77,7 +77,11 @@ unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0); module_param(cifs_max_pending, int, 0);
MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
"Default: 50 Range: 2 to 256"); "Default: 50 Range: 2 to 256");
unsigned short echo_retries = 5;
module_param(echo_retries, ushort, 0644);
MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and "
"reconnecting server. Default: 5. 0 means "
"never reconnect.");
extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp; extern mempool_t *cifs_req_poolp;
extern mempool_t *cifs_mid_poolp; extern mempool_t *cifs_mid_poolp;
......
...@@ -118,5 +118,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -118,5 +118,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops; extern const struct export_operations cifs_export_ops;
#endif /* EXPERIMENTAL */ #endif /* EXPERIMENTAL */
#define CIFS_VERSION "1.68" #define CIFS_VERSION "1.69"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -218,6 +218,7 @@ struct TCP_Server_Info { ...@@ -218,6 +218,7 @@ struct TCP_Server_Info {
bool sec_kerberosu2u; /* supports U2U Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */
bool sec_ntlmssp; /* supports NTLMSSP */ bool sec_ntlmssp; /* supports NTLMSSP */
bool session_estab; /* mark when very first sess is established */ bool session_estab; /* mark when very first sess is established */
struct delayed_work echo; /* echo ping workqueue job */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
struct fscache_cookie *fscache; /* client index cache cookie */ struct fscache_cookie *fscache; /* client index cache cookie */
#endif #endif
...@@ -508,6 +509,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, ...@@ -508,6 +509,18 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
#endif #endif
struct mid_q_entry;
/*
* This is the prototype for the mid callback function. When creating one,
* take special care to avoid deadlocks. Things to bear in mind:
*
* - it will be called by cifsd
* - the GlobalMid_Lock will be held
* - the mid will be removed from the pending_mid_q list
*/
typedef void (mid_callback_t)(struct mid_q_entry *mid);
/* one of these for every pending CIFS request to the server */ /* one of these for every pending CIFS request to the server */
struct mid_q_entry { struct mid_q_entry {
struct list_head qhead; /* mids waiting on reply from this server */ struct list_head qhead; /* mids waiting on reply from this server */
...@@ -519,7 +532,8 @@ struct mid_q_entry { ...@@ -519,7 +532,8 @@ struct mid_q_entry {
unsigned long when_sent; /* time when smb send finished */ unsigned long when_sent; /* time when smb send finished */
unsigned long when_received; /* when demux complete (taken off wire) */ unsigned long when_received; /* when demux complete (taken off wire) */
#endif #endif
struct task_struct *tsk; /* task waiting for response */ mid_callback_t *callback; /* call completion callback */
void *callback_data; /* general purpose pointer for callback */
struct smb_hdr *resp_buf; /* response buffer */ struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this were enum but can not pass to wait_event */ int midState; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */ __u8 command; /* smb command code */
...@@ -622,12 +636,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, ...@@ -622,12 +636,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
#define CIFS_IOVEC 4 /* array of response buffers */ #define CIFS_IOVEC 4 /* array of response buffers */
/* Type of Request to SendReceive2 */ /* Type of Request to SendReceive2 */
#define CIFS_STD_OP 0 /* normal request timeout */ #define CIFS_BLOCKING_OP 1 /* operation can block */
#define CIFS_LONG_OP 1 /* long op (up to 45 sec, oplock time) */ #define CIFS_ASYNC_OP 2 /* do not wait for response */
#define CIFS_VLONG_OP 2 /* sloow op - can take up to 180 seconds */ #define CIFS_TIMEOUT_MASK 0x003 /* only one of above set in req */
#define CIFS_BLOCKING_OP 4 /* operation can block */
#define CIFS_ASYNC_OP 8 /* do not wait for response */
#define CIFS_TIMEOUT_MASK 0x00F /* only one of 5 above set in req */
#define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */ #define CIFS_LOG_ERROR 0x010 /* log NT STATUS if non-zero */
#define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */ #define CIFS_LARGE_BUF_OP 0x020 /* large request buffer */
#define CIFS_NO_RESP 0x040 /* no response buffer required */ #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,6 +801,9 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */
GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
/* reconnect after this many failed echo attempts */
GLOBAL_EXTERN unsigned short echo_retries;
void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break(struct work_struct *work);
void cifs_oplock_break_get(struct cifsFileInfo *cfile); void cifs_oplock_break_get(struct cifsFileInfo *cfile);
void cifs_oplock_break_put(struct cifsFileInfo *cfile); void cifs_oplock_break_put(struct cifsFileInfo *cfile);
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define SMB_COM_SETATTR 0x09 /* trivial response */ #define SMB_COM_SETATTR 0x09 /* trivial response */
#define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */
#define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/
#define SMB_COM_ECHO 0x2B /* echo request */
#define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */
#define SMB_COM_READ_ANDX 0x2E #define SMB_COM_READ_ANDX 0x2E
#define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_WRITE_ANDX 0x2F
...@@ -760,6 +761,20 @@ typedef struct smb_com_tconx_rsp_ext { ...@@ -760,6 +761,20 @@ typedef struct smb_com_tconx_rsp_ext {
* *
*/ */
typedef struct smb_com_echo_req {
struct smb_hdr hdr;
__le16 EchoCount;
__le16 ByteCount;
char Data[1];
} __attribute__((packed)) ECHO_REQ;
typedef struct smb_com_echo_rsp {
struct smb_hdr hdr;
__le16 SequenceNumber;
__le16 ByteCount;
char Data[1];
} __attribute__((packed)) ECHO_RSP;
typedef struct smb_com_logoff_andx_req { typedef struct smb_com_logoff_andx_req {
struct smb_hdr hdr; /* wct = 2 */ struct smb_hdr hdr; /* wct = 2 */
__u8 AndXCommand; __u8 AndXCommand;
......
...@@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata, ...@@ -61,6 +61,12 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
const char *fullpath, const struct dfs_info3_param *ref, const char *fullpath, const struct dfs_info3_param *ref,
char **devname); char **devname);
/* extern void renew_parental_timestamps(struct dentry *direntry);*/ /* extern void renew_parental_timestamps(struct dentry *direntry);*/
extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server);
extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
extern int cifs_call_async(struct TCP_Server_Info *server,
struct smb_hdr *in_buf, mid_callback_t *callback,
void *cbdata);
extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* input */ , struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
...@@ -347,12 +353,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -347,12 +353,13 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len, const __u16 netfid, const __u64 len,
const __u64 offset, const __u32 numUnlock, const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType, const __u32 numLock, const __u8 lockType,
const bool waitFlag); const bool waitFlag, const __u8 oplock_level);
extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const int get_flag, const __u16 smb_file_id, const int get_flag,
const __u64 len, struct file_lock *, const __u64 len, struct file_lock *,
const __u16 lock_type, const bool waitFlag); const __u16 lock_type, const bool waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
extern int CIFSSMBEcho(struct TCP_Server_Info *server);
extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
extern struct cifsSesInfo *sesInfoAlloc(void); extern struct cifsSesInfo *sesInfoAlloc(void);
......
...@@ -706,6 +706,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) ...@@ -706,6 +706,53 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
return rc; return rc;
} }
/*
* This is a no-op for now. We're not really interested in the reply, but
* rather in the fact that the server sent one and that server->lstrp
* gets updated.
*
* FIXME: maybe we should consider checking that the reply matches request?
*/
static void
cifs_echo_callback(struct mid_q_entry *mid)
{
struct TCP_Server_Info *server = mid->callback_data;
DeleteMidQEntry(mid);
atomic_dec(&server->inFlight);
wake_up(&server->request_q);
}
int
CIFSSMBEcho(struct TCP_Server_Info *server)
{
ECHO_REQ *smb;
int rc = 0;
cFYI(1, "In echo request");
rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
if (rc)
return rc;
/* set up echo request */
smb->hdr.Tid = cpu_to_le16(0xffff);
smb->hdr.WordCount = cpu_to_le16(1);
smb->EchoCount = cpu_to_le16(1);
smb->ByteCount = cpu_to_le16(1);
smb->Data[0] = 'a';
smb->hdr.smb_buf_length += 3;
rc = cifs_call_async(server, (struct smb_hdr *)smb,
cifs_echo_callback, server);
if (rc)
cFYI(1, "Echo request failed: %d", rc);
cifs_small_buf_release(smb);
return rc;
}
int int
CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
{ {
...@@ -1193,7 +1240,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1193,7 +1240,7 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */ /* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); (struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_opens); cifs_stats_inc(&tcon->num_opens);
if (rc) { if (rc) {
cFYI(1, "Error in Open = %d", rc); cFYI(1, "Error in Open = %d", rc);
...@@ -1306,7 +1353,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1306,7 +1353,7 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
pSMB->ByteCount = cpu_to_le16(count); pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */ /* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP); (struct smb_hdr *)pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_opens); cifs_stats_inc(&tcon->num_opens);
if (rc) { if (rc) {
cFYI(1, "Error in Open = %d", rc); cFYI(1, "Error in Open = %d", rc);
...@@ -1388,7 +1435,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, ...@@ -1388,7 +1435,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
iov[0].iov_base = (char *)pSMB; iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
&resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR); &resp_buf_type, CIFS_LOG_ERROR);
cifs_stats_inc(&tcon->num_reads); cifs_stats_inc(&tcon->num_reads);
pSMBr = (READ_RSP *)iov[0].iov_base; pSMBr = (READ_RSP *)iov[0].iov_base;
if (rc) { if (rc) {
...@@ -1663,7 +1710,8 @@ int ...@@ -1663,7 +1710,8 @@ int
CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const __u64 len, const __u16 smb_file_id, const __u64 len,
const __u64 offset, const __u32 numUnlock, const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType, const bool waitFlag) const __u32 numLock, const __u8 lockType,
const bool waitFlag, const __u8 oplock_level)
{ {
int rc = 0; int rc = 0;
LOCK_REQ *pSMB = NULL; LOCK_REQ *pSMB = NULL;
...@@ -1691,6 +1739,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -1691,6 +1739,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->NumberOfLocks = cpu_to_le16(numLock); pSMB->NumberOfLocks = cpu_to_le16(numLock);
pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock); pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
pSMB->LockType = lockType; pSMB->LockType = lockType;
pSMB->OplockLevel = oplock_level;
pSMB->AndXCommand = 0xFF; /* none */ pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Fid = smb_file_id; /* netfid stays le */
...@@ -3087,7 +3136,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, ...@@ -3087,7 +3136,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
CIFS_STD_OP); 0);
cifs_stats_inc(&tcon->num_acl_get); cifs_stats_inc(&tcon->num_acl_get);
if (rc) { if (rc) {
cFYI(1, "Send error in QuerySecDesc = %d", rc); cFYI(1, "Send error in QuerySecDesc = %d", rc);
......
This diff is collapsed.
...@@ -726,12 +726,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -726,12 +726,12 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
/* BB we could chain these into one lock request BB */ /* BB we could chain these into one lock request BB */
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start, rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
0, 1, lockType, 0 /* wait flag */ ); 0, 1, lockType, 0 /* wait flag */, 0);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ , pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType, 0 /* numLock */ , lockType,
0 /* wait flag */ ); 0 /* wait flag */, 0);
pfLock->fl_type = F_UNLCK; pfLock->fl_type = F_UNLCK;
if (rc != 0) if (rc != 0)
cERROR(1, "Error unlocking previously locked " cERROR(1, "Error unlocking previously locked "
...@@ -748,13 +748,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -748,13 +748,13 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, 0, 1, pfLock->fl_start, 0, 1,
lockType | LOCKING_ANDX_SHARED_LOCK, lockType | LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */); 0 /* wait flag */, 0);
if (rc == 0) { if (rc == 0) {
rc = CIFSSMBLock(xid, tcon, netfid, rc = CIFSSMBLock(xid, tcon, netfid,
length, pfLock->fl_start, 1, 0, length, pfLock->fl_start, 1, 0,
lockType | lockType |
LOCKING_ANDX_SHARED_LOCK, LOCKING_ANDX_SHARED_LOCK,
0 /* wait flag */); 0 /* wait flag */, 0);
pfLock->fl_type = F_RDLCK; pfLock->fl_type = F_RDLCK;
if (rc != 0) if (rc != 0)
cERROR(1, "Error unlocking " cERROR(1, "Error unlocking "
...@@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -797,8 +797,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (numLock) { if (numLock) {
rc = CIFSSMBLock(xid, tcon, netfid, length, rc = CIFSSMBLock(xid, tcon, netfid, length,
pfLock->fl_start, pfLock->fl_start, 0, numLock, lockType,
0, numLock, lockType, wait_flag); wait_flag, 0);
if (rc == 0) { if (rc == 0) {
/* For Windows locks we must store them. */ /* For Windows locks we must store them. */
...@@ -818,9 +818,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -818,9 +818,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
(pfLock->fl_start + length) >= (pfLock->fl_start + length) >=
(li->offset + li->length)) { (li->offset + li->length)) {
stored_rc = CIFSSMBLock(xid, tcon, stored_rc = CIFSSMBLock(xid, tcon,
netfid, netfid, li->length,
li->length, li->offset, li->offset, 1, 0,
1, 0, li->type, false); li->type, false, 0);
if (stored_rc) if (stored_rc)
rc = stored_rc; rc = stored_rc;
else { else {
...@@ -839,29 +839,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ...@@ -839,29 +839,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
return rc; return rc;
} }
/*
* Set the timeout on write requests past EOF. For some servers (Windows)
* these calls can be very long.
*
* If we're writing >10M past the EOF we give a 180s timeout. Anything less
* than that gets a 45s timeout. Writes not past EOF get 15s timeouts.
* The 10M cutoff is totally arbitrary. A better scheme for this would be
* welcome if someone wants to suggest one.
*
* We may be able to do a better job with this if there were some way to
* declare that a file should be sparse.
*/
static int
cifs_write_timeout(struct cifsInodeInfo *cifsi, loff_t offset)
{
if (offset <= cifsi->server_eof)
return CIFS_STD_OP;
else if (offset > (cifsi->server_eof + (10 * 1024 * 1024)))
return CIFS_VLONG_OP;
else
return CIFS_LONG_OP;
}
/* update the file size (if needed) after a write */ /* update the file size (if needed) after a write */
static void static void
cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, 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,7 +859,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
unsigned int total_written; unsigned int total_written;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int xid, long_op; int xid;
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsInodeInfo *cifsi = CIFS_I(inode);
...@@ -903,7 +880,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -903,7 +880,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
xid = GetXid(); xid = GetXid();
long_op = cifs_write_timeout(cifsi, *poffset);
for (total_written = 0; write_size > total_written; for (total_written = 0; write_size > total_written;
total_written += bytes_written) { total_written += bytes_written) {
rc = -EAGAIN; rc = -EAGAIN;
...@@ -931,7 +907,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -931,7 +907,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
min_t(const int, cifs_sb->wsize, min_t(const int, cifs_sb->wsize,
write_size - total_written), write_size - total_written),
*poffset, &bytes_written, *poffset, &bytes_written,
NULL, write_data + total_written, long_op); NULL, write_data + total_written, 0);
} }
if (rc || (bytes_written == 0)) { if (rc || (bytes_written == 0)) {
if (total_written) if (total_written)
...@@ -944,8 +920,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, ...@@ -944,8 +920,6 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
cifs_update_eof(cifsi, *poffset, bytes_written); cifs_update_eof(cifsi, *poffset, bytes_written);
*poffset += bytes_written; *poffset += bytes_written;
} }
long_op = CIFS_STD_OP; /* subsequent writes fast -
15 seconds is plenty */
} }
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
...@@ -974,7 +948,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, ...@@ -974,7 +948,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
unsigned int total_written; unsigned int total_written;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon; struct cifsTconInfo *pTcon;
int xid, long_op; int xid;
struct dentry *dentry = open_file->dentry; struct dentry *dentry = open_file->dentry;
struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode); struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
...@@ -987,7 +961,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, ...@@ -987,7 +961,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
xid = GetXid(); xid = GetXid();
long_op = cifs_write_timeout(cifsi, *poffset);
for (total_written = 0; write_size > total_written; for (total_written = 0; write_size > total_written;
total_written += bytes_written) { total_written += bytes_written) {
rc = -EAGAIN; rc = -EAGAIN;
...@@ -1017,7 +990,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, ...@@ -1017,7 +990,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
rc = CIFSSMBWrite2(xid, pTcon, rc = CIFSSMBWrite2(xid, pTcon,
open_file->netfid, len, open_file->netfid, len,
*poffset, &bytes_written, *poffset, &bytes_written,
iov, 1, long_op); iov, 1, 0);
} else } else
rc = CIFSSMBWrite(xid, pTcon, rc = CIFSSMBWrite(xid, pTcon,
open_file->netfid, open_file->netfid,
...@@ -1025,7 +998,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, ...@@ -1025,7 +998,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
write_size - total_written), write_size - total_written),
*poffset, &bytes_written, *poffset, &bytes_written,
write_data + total_written, write_data + total_written,
NULL, long_op); NULL, 0);
} }
if (rc || (bytes_written == 0)) { if (rc || (bytes_written == 0)) {
if (total_written) if (total_written)
...@@ -1038,8 +1011,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, ...@@ -1038,8 +1011,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file,
cifs_update_eof(cifsi, *poffset, bytes_written); cifs_update_eof(cifsi, *poffset, bytes_written);
*poffset += bytes_written; *poffset += bytes_written;
} }
long_op = CIFS_STD_OP; /* subsequent writes fast -
15 seconds is plenty */
} }
cifs_stats_bytes_written(pTcon, total_written); cifs_stats_bytes_written(pTcon, total_written);
...@@ -1239,7 +1210,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1239,7 +1210,7 @@ static int cifs_writepages(struct address_space *mapping,
struct pagevec pvec; struct pagevec pvec;
int rc = 0; int rc = 0;
int scanned = 0; int scanned = 0;
int xid, long_op; int xid;
cifs_sb = CIFS_SB(mapping->host->i_sb); cifs_sb = CIFS_SB(mapping->host->i_sb);
...@@ -1377,43 +1348,67 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -1377,43 +1348,67 @@ static int cifs_writepages(struct address_space *mapping,
break; break;
} }
if (n_iov) { if (n_iov) {
retry_write:
open_file = find_writable_file(CIFS_I(mapping->host), open_file = find_writable_file(CIFS_I(mapping->host),
false); false);
if (!open_file) { if (!open_file) {
cERROR(1, "No writable handles for inode"); cERROR(1, "No writable handles for inode");
rc = -EBADF; rc = -EBADF;
} else { } else {
long_op = cifs_write_timeout(cifsi, offset);
rc = CIFSSMBWrite2(xid, tcon, open_file->netfid, rc = CIFSSMBWrite2(xid, tcon, open_file->netfid,
bytes_to_write, offset, bytes_to_write, offset,
&bytes_written, iov, n_iov, &bytes_written, iov, n_iov,
long_op); 0);
cifsFileInfo_put(open_file); cifsFileInfo_put(open_file);
cifs_update_eof(cifsi, offset, bytes_written);
} }
if (rc || bytes_written < bytes_to_write) { cFYI(1, "Write2 rc=%d, wrote=%u", rc, bytes_written);
cERROR(1, "Write2 ret %d, wrote %d",
rc, bytes_written); /*
mapping_set_error(mapping, rc); * For now, treat a short write as if nothing got
} else { * written. A zero length write however indicates
* ENOSPC or EFBIG. We have no way to know which
* though, so call it ENOSPC for now. EFBIG would
* get translated to AS_EIO anyway.
*
* FIXME: make it take into account the data that did
* get written
*/
if (rc == 0) {
if (bytes_written == 0)
rc = -ENOSPC;
else if (bytes_written < bytes_to_write)
rc = -EAGAIN;
}
/* retry on data-integrity flush */
if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN)
goto retry_write;
/* fix the stats and EOF */
if (bytes_written > 0) {
cifs_stats_bytes_written(tcon, bytes_written); cifs_stats_bytes_written(tcon, bytes_written);
cifs_update_eof(cifsi, offset, bytes_written);
} }
for (i = 0; i < n_iov; i++) { for (i = 0; i < n_iov; i++) {
page = pvec.pages[first + i]; page = pvec.pages[first + i];
/* Should we also set page error on /* on retryable write error, redirty page */
success rc but too little data written? */ if (rc == -EAGAIN)
/* BB investigate retry logic on temporary redirty_page_for_writepage(wbc, page);
server crash cases and how recovery works else if (rc != 0)
when page marked as error */
if (rc)
SetPageError(page); SetPageError(page);
kunmap(page); kunmap(page);
unlock_page(page); unlock_page(page);
end_page_writeback(page); end_page_writeback(page);
page_cache_release(page); page_cache_release(page);
} }
if (rc != -EAGAIN)
mapping_set_error(mapping, rc);
else
rc = 0;
if ((wbc->nr_to_write -= n_iov) <= 0) if ((wbc->nr_to_write -= n_iov) <= 0)
done = 1; done = 1;
index = next; index = next;
...@@ -2192,7 +2187,8 @@ void cifs_oplock_break(struct work_struct *work) ...@@ -2192,7 +2187,8 @@ void cifs_oplock_break(struct work_struct *work)
*/ */
if (!cfile->oplock_break_cancelled) { if (!cfile->oplock_break_cancelled) {
rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0,
0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false); 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false,
cinode->clientCanCacheRead ? 1 : 0);
cFYI(1, "Oplock release rc = %d", rc); cFYI(1, "Oplock release rc = %d", rc);
} }
......
...@@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -571,7 +571,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
pCifsInode = CIFS_I(netfile->dentry->d_inode); pCifsInode = CIFS_I(netfile->dentry->d_inode);
cifs_set_oplock_level(pCifsInode, cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel); pSMB->OplockLevel ? OPLOCK_READ : 0);
/* /*
* cifs_oplock_break_put() can't be called * cifs_oplock_break_put() can't be called
* from here. Get reference after queueing * from here. Get reference after queueing
......
...@@ -879,7 +879,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, ...@@ -879,7 +879,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
BCC_LE(smb_buf) = cpu_to_le16(count); BCC_LE(smb_buf) = cpu_to_le16(count);
rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); CIFS_LOG_ERROR);
/* SMB request buf freed in SendReceive2 */ /* SMB request buf freed in SendReceive2 */
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment