Commit 10f3cb41 authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French.

* git://git.samba.org/sfrench/cifs-2.6:
  [CIFS] Update CIFS version number to 1.77
  CIFS: Add missed forcemand mount option
  [CIFS] Fix trivial sparse warning with asyn i/o patch
  cifs: handle "sloppy" option appropriately
  cifs: use standard token parser for mount options
  cifs: remove /proc/fs/cifs/OplockEnabled
  cifs: convert cifs_iovec_write to use async writes
  cifs: call cifs_update_eof with i_lock held
  cifs: abstract out function to marshal up the iovec array for async writes
  cifs: fix up get_numpages
  cifs: make cifsFileInfo_get return the cifsFileInfo pointer
  cifs: fix allocation in cifs_write_allocate_pages
  cifs: allow caller to specify completion op when allocating writedata
  cifs: add pid field to cifs_writedata
  cifs: add new cifsiod_wq workqueue
  CIFS: Change mid_q_entry structure fields
  CIFS: Expand CurrentMid field
  CIFS: Separate protocol-specific code from cifs_readv_receive code
  CIFS: Separate protocol-specific code from demultiplex code
  CIFS: Separate protocol-specific code from transport routines
parents 919c8401 867646f2
...@@ -58,15 +58,16 @@ cifs_dump_mem(char *label, void *data, int length) ...@@ -58,15 +58,16 @@ cifs_dump_mem(char *label, void *data, int length)
} }
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
void cifs_dump_detail(struct smb_hdr *smb) void cifs_dump_detail(void *buf)
{ {
struct smb_hdr *smb = (struct smb_hdr *)buf;
cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
smb->Command, smb->Status.CifsError, smb->Command, smb->Status.CifsError,
smb->Flags, smb->Flags2, smb->Mid, smb->Pid); smb->Flags, smb->Flags2, smb->Mid, smb->Pid);
cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb)); cERROR(1, "smb buf %p len %d", smb, smbCalcSize(smb));
} }
void cifs_dump_mids(struct TCP_Server_Info *server) void cifs_dump_mids(struct TCP_Server_Info *server)
{ {
struct list_head *tmp; struct list_head *tmp;
...@@ -79,15 +80,15 @@ void cifs_dump_mids(struct TCP_Server_Info *server) ...@@ -79,15 +80,15 @@ 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 Cbdata: %p Mid %d", cERROR(1, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu",
mid_entry->midState, mid_entry->mid_state,
(int)mid_entry->command, le16_to_cpu(mid_entry->command),
mid_entry->pid, mid_entry->pid,
mid_entry->callback_data, 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",
mid_entry->largeBuf, mid_entry->large_buf,
mid_entry->resp_buf, mid_entry->resp_buf,
mid_entry->when_received, mid_entry->when_received,
jiffies); jiffies);
...@@ -217,9 +218,9 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -217,9 +218,9 @@ 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 cbdata: %p mid %d\n", " %d cbdata: %p mid %llu\n",
mid_entry->midState, mid_entry->mid_state,
(int)mid_entry->command, le16_to_cpu(mid_entry->command),
mid_entry->pid, mid_entry->pid,
mid_entry->callback_data, mid_entry->callback_data,
mid_entry->mid); mid_entry->mid);
...@@ -417,7 +418,6 @@ static const struct file_operations cifs_stats_proc_fops = { ...@@ -417,7 +418,6 @@ static const struct file_operations cifs_stats_proc_fops = {
static struct proc_dir_entry *proc_fs_cifs; static struct proc_dir_entry *proc_fs_cifs;
static const struct file_operations cifsFYI_proc_fops; static const struct file_operations cifsFYI_proc_fops;
static const struct file_operations cifs_oplock_proc_fops;
static const struct file_operations cifs_lookup_cache_proc_fops; static const struct file_operations cifs_lookup_cache_proc_fops;
static const struct file_operations traceSMB_proc_fops; static const struct file_operations traceSMB_proc_fops;
static const struct file_operations cifs_multiuser_mount_proc_fops; static const struct file_operations cifs_multiuser_mount_proc_fops;
...@@ -438,7 +438,6 @@ cifs_proc_init(void) ...@@ -438,7 +438,6 @@ cifs_proc_init(void)
#endif /* STATS */ #endif /* STATS */
proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops);
proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops);
proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops);
proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs,
&cifs_linux_ext_proc_fops); &cifs_linux_ext_proc_fops);
proc_create("MultiuserMount", 0, proc_fs_cifs, proc_create("MultiuserMount", 0, proc_fs_cifs,
...@@ -462,7 +461,6 @@ cifs_proc_clean(void) ...@@ -462,7 +461,6 @@ cifs_proc_clean(void)
remove_proc_entry("Stats", proc_fs_cifs); remove_proc_entry("Stats", proc_fs_cifs);
#endif #endif
remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs);
remove_proc_entry("OplockEnabled", proc_fs_cifs);
remove_proc_entry("SecurityFlags", proc_fs_cifs); remove_proc_entry("SecurityFlags", proc_fs_cifs);
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
...@@ -508,46 +506,6 @@ static const struct file_operations cifsFYI_proc_fops = { ...@@ -508,46 +506,6 @@ static const struct file_operations cifsFYI_proc_fops = {
.write = cifsFYI_proc_write, .write = cifsFYI_proc_write,
}; };
static int cifs_oplock_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", enable_oplocks);
return 0;
}
static int cifs_oplock_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, cifs_oplock_proc_show, NULL);
}
static ssize_t cifs_oplock_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
int rc;
printk(KERN_WARNING "CIFS: The /proc/fs/cifs/OplockEnabled interface "
"will be removed in kernel version 3.4. Please migrate to "
"using the 'enable_oplocks' module parameter in cifs.ko.\n");
rc = get_user(c, buffer);
if (rc)
return rc;
if (c == '0' || c == 'n' || c == 'N')
enable_oplocks = false;
else if (c == '1' || c == 'y' || c == 'Y')
enable_oplocks = true;
return count;
}
static const struct file_operations cifs_oplock_proc_fops = {
.owner = THIS_MODULE,
.open = cifs_oplock_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = cifs_oplock_proc_write,
};
static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) static int cifs_linux_ext_proc_show(struct seq_file *m, void *v)
{ {
seq_printf(m, "%d\n", linuxExtEnabled); seq_printf(m, "%d\n", linuxExtEnabled);
......
...@@ -26,13 +26,13 @@ ...@@ -26,13 +26,13 @@
void cifs_dump_mem(char *label, void *data, int length); void cifs_dump_mem(char *label, void *data, int length);
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
#define DBG2 2 #define DBG2 2
void cifs_dump_detail(struct smb_hdr *); void cifs_dump_detail(void *);
void cifs_dump_mids(struct TCP_Server_Info *); void cifs_dump_mids(struct TCP_Server_Info *);
#else #else
#define DBG2 0 #define DBG2 0
#endif #endif
extern int traceSMB; /* flag which enables the function below */ extern int traceSMB; /* flag which enables the function below */
void dump_smb(struct smb_hdr *, int); void dump_smb(void *, int);
#define CIFS_INFO 0x01 #define CIFS_INFO 0x01
#define CIFS_RC 0x02 #define CIFS_RC 0x02
#define CIFS_TIMER 0x04 #define CIFS_TIMER 0x04
......
...@@ -85,6 +85,8 @@ extern mempool_t *cifs_sm_req_poolp; ...@@ -85,6 +85,8 @@ 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;
struct workqueue_struct *cifsiod_wq;
static int static int
cifs_read_super(struct super_block *sb) cifs_read_super(struct super_block *sb)
{ {
...@@ -1111,9 +1113,15 @@ init_cifs(void) ...@@ -1111,9 +1113,15 @@ init_cifs(void)
cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ); cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ);
} }
cifsiod_wq = alloc_workqueue("cifsiod", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
if (!cifsiod_wq) {
rc = -ENOMEM;
goto out_clean_proc;
}
rc = cifs_fscache_register(); rc = cifs_fscache_register();
if (rc) if (rc)
goto out_clean_proc; goto out_destroy_wq;
rc = cifs_init_inodecache(); rc = cifs_init_inodecache();
if (rc) if (rc)
...@@ -1161,6 +1169,8 @@ init_cifs(void) ...@@ -1161,6 +1169,8 @@ init_cifs(void)
cifs_destroy_inodecache(); cifs_destroy_inodecache();
out_unreg_fscache: out_unreg_fscache:
cifs_fscache_unregister(); cifs_fscache_unregister();
out_destroy_wq:
destroy_workqueue(cifsiod_wq);
out_clean_proc: out_clean_proc:
cifs_proc_clean(); cifs_proc_clean();
return rc; return rc;
...@@ -1183,6 +1193,7 @@ exit_cifs(void) ...@@ -1183,6 +1193,7 @@ exit_cifs(void)
cifs_destroy_mids(); cifs_destroy_mids();
cifs_destroy_inodecache(); cifs_destroy_inodecache();
cifs_fscache_unregister(); cifs_fscache_unregister();
destroy_workqueue(cifsiod_wq);
cifs_proc_clean(); cifs_proc_clean();
} }
......
...@@ -125,5 +125,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); ...@@ -125,5 +125,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 /* CONFIG_CIFS_NFSD_EXPORT */ #endif /* CONFIG_CIFS_NFSD_EXPORT */
#define CIFS_VERSION "1.76" #define CIFS_VERSION "1.77"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -230,6 +230,12 @@ struct cifs_mnt_data { ...@@ -230,6 +230,12 @@ struct cifs_mnt_data {
int flags; int flags;
}; };
static inline unsigned int
get_rfc1002_length(void *buf)
{
return be32_to_cpu(*((__be32 *)buf));
}
struct TCP_Server_Info { struct TCP_Server_Info {
struct list_head tcp_ses_list; struct list_head tcp_ses_list;
struct list_head smb_ses_list; struct list_head smb_ses_list;
...@@ -276,7 +282,7 @@ struct TCP_Server_Info { ...@@ -276,7 +282,7 @@ struct TCP_Server_Info {
vcnumbers */ vcnumbers */
int capabilities; /* allow selective disabling of caps by smb sess */ int capabilities; /* allow selective disabling of caps by smb sess */
int timeAdj; /* Adjust for difference in server time zone in sec */ int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */ __u64 CurrentMid; /* multiplex id - rotating counter */
char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
/* 16th byte of RFC1001 workstation name is always null */ /* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
...@@ -335,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits) ...@@ -335,6 +341,18 @@ has_credits(struct TCP_Server_Info *server, int *credits)
return num > 0; return num > 0;
} }
static inline size_t
header_size(void)
{
return sizeof(struct smb_hdr);
}
static inline size_t
max_header_size(void)
{
return MAX_CIFS_HDR_SIZE;
}
/* /*
* Macros to allow the TCP_Server_Info->net field and related code to drop out * Macros to allow the TCP_Server_Info->net field and related code to drop out
* when CONFIG_NET_NS isn't set. * when CONFIG_NET_NS isn't set.
...@@ -583,9 +601,11 @@ struct cifs_io_parms { ...@@ -583,9 +601,11 @@ struct cifs_io_parms {
* Take a reference on the file private data. Must be called with * Take a reference on the file private data. Must be called with
* cifs_file_list_lock held. * cifs_file_list_lock held.
*/ */
static inline void cifsFileInfo_get(struct cifsFileInfo *cifs_file) static inline
struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file)
{ {
++cifs_file->count; ++cifs_file->count;
return cifs_file;
} }
void cifsFileInfo_put(struct cifsFileInfo *cifs_file); void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
...@@ -606,7 +626,7 @@ struct cifsInodeInfo { ...@@ -606,7 +626,7 @@ struct cifsInodeInfo {
bool delete_pending; /* DELETE_ON_CLOSE is set */ bool delete_pending; /* DELETE_ON_CLOSE is set */
bool invalid_mapping; /* pagecache is invalid */ bool invalid_mapping; /* pagecache is invalid */
unsigned long time; /* jiffies of last update of inode */ unsigned long time; /* jiffies of last update of inode */
u64 server_eof; /* current file size on server */ u64 server_eof; /* current file size on server -- protected by i_lock */
u64 uniqueid; /* server inode number */ u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */ u64 createtime; /* creation time on server */
#ifdef CONFIG_CIFS_FSCACHE #ifdef CONFIG_CIFS_FSCACHE
...@@ -713,8 +733,8 @@ typedef void (mid_callback_t)(struct mid_q_entry *mid); ...@@ -713,8 +733,8 @@ 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 */
__u16 mid; /* multiplex id */ __u64 mid; /* multiplex id */
__u16 pid; /* process id */ __u32 pid; /* process id */
__u32 sequence_number; /* for CIFS signing */ __u32 sequence_number; /* for CIFS signing */
unsigned long when_alloc; /* when mid was created */ unsigned long when_alloc; /* when mid was created */
#ifdef CONFIG_CIFS_STATS2 #ifdef CONFIG_CIFS_STATS2
...@@ -724,10 +744,10 @@ struct mid_q_entry { ...@@ -724,10 +744,10 @@ struct mid_q_entry {
mid_receive_t *receive; /* call receive callback */ mid_receive_t *receive; /* call receive callback */
mid_callback_t *callback; /* call completion callback */ mid_callback_t *callback; /* call completion callback */
void *callback_data; /* general purpose pointer for callback */ void *callback_data; /* general purpose pointer for callback */
struct smb_hdr *resp_buf; /* pointer to received SMB header */ void *resp_buf; /* pointer to received SMB header */
int midState; /* wish this were enum but can not pass to wait_event */ int mid_state; /* wish this were enum but can not pass to wait_event */
__u8 command; /* smb command code */ __le16 command; /* smb command code */
bool largeBuf:1; /* if valid response, is pointer to large buf */ bool large_buf:1; /* if valid response, is pointer to large buf */
bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiRsp:1; /* multiple trans2 responses for one request */
bool multiEnd:1; /* both received */ bool multiEnd:1; /* both received */
}; };
...@@ -1052,5 +1072,6 @@ GLOBAL_EXTERN spinlock_t gidsidlock; ...@@ -1052,5 +1072,6 @@ GLOBAL_EXTERN spinlock_t gidsidlock;
void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break(struct work_struct *work);
extern const struct slow_work_ops cifs_oplock_break_ops; extern const struct slow_work_ops cifs_oplock_break_ops;
extern struct workqueue_struct *cifsiod_wq;
#endif /* _CIFS_GLOB_H */ #endif /* _CIFS_GLOB_H */
...@@ -77,7 +77,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *, ...@@ -77,7 +77,7 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifs_ses *,
struct smb_hdr * /* out */ , struct smb_hdr * /* out */ ,
int * /* bytes returned */ , const int long_op); int * /* bytes returned */ , const int long_op);
extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, extern int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses,
struct smb_hdr *in_buf, int flags); char *in_buf, int flags);
extern int cifs_check_receive(struct mid_q_entry *mid, extern int cifs_check_receive(struct mid_q_entry *mid,
struct TCP_Server_Info *server, bool log_error); struct TCP_Server_Info *server, bool log_error);
extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
...@@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid, ...@@ -91,9 +91,8 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
extern void cifs_add_credits(struct TCP_Server_Info *server, extern void cifs_add_credits(struct TCP_Server_Info *server,
const unsigned int add); const unsigned int add);
extern void cifs_set_credits(struct TCP_Server_Info *server, const int val); extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int checkSMB(char *buf, unsigned int length);
extern bool is_valid_oplock_break(struct smb_hdr *smb, extern bool is_valid_oplock_break(char *, struct TCP_Server_Info *);
struct TCP_Server_Info *);
extern bool backup_cred(struct cifs_sb_info *); extern bool backup_cred(struct cifs_sb_info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
...@@ -107,7 +106,7 @@ extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len); ...@@ -107,7 +106,7 @@ extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port); extern int cifs_set_port(struct sockaddr *addr, const unsigned short int port);
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len, extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
const unsigned short int port); const unsigned short int port);
extern int map_smb_to_linux_error(struct smb_hdr *smb, bool logErr); extern int map_smb_to_linux_error(char *buf, bool logErr);
extern void header_assemble(struct smb_hdr *, char /* command */ , extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifs_tcon *, int /* length of const struct cifs_tcon *, int /* length of
fixed section (word count) in two byte units */); fixed section (word count) in two byte units */);
...@@ -116,7 +115,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, ...@@ -116,7 +115,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
void **request_buf); void **request_buf);
extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses, extern int CIFS_SessSetup(unsigned int xid, struct cifs_ses *ses,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
extern __u16 GetNextMid(struct TCP_Server_Info *server); extern __u64 GetNextMid(struct TCP_Server_Info *server);
extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601); extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
extern u64 cifs_UnixTimeToNT(struct timespec); extern u64 cifs_UnixTimeToNT(struct timespec);
extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
...@@ -484,18 +483,25 @@ int cifs_async_readv(struct cifs_readdata *rdata); ...@@ -484,18 +483,25 @@ int cifs_async_readv(struct cifs_readdata *rdata);
/* asynchronous write support */ /* asynchronous write support */
struct cifs_writedata { struct cifs_writedata {
struct kref refcount; struct kref refcount;
struct list_head list;
struct completion done;
enum writeback_sync_modes sync_mode; enum writeback_sync_modes sync_mode;
struct work_struct work; struct work_struct work;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
__u64 offset; __u64 offset;
pid_t pid;
unsigned int bytes; unsigned int bytes;
int result; int result;
void (*marshal_iov) (struct kvec *iov,
struct cifs_writedata *wdata);
unsigned int nr_pages; unsigned int nr_pages;
struct page *pages[1]; struct page *pages[1];
}; };
int cifs_async_writev(struct cifs_writedata *wdata); int cifs_async_writev(struct cifs_writedata *wdata);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages); void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
work_func_t complete);
void cifs_writedata_release(struct kref *refcount); void cifs_writedata_release(struct kref *refcount);
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -213,55 +213,62 @@ cifs_small_buf_release(void *buf_to_free) ...@@ -213,55 +213,62 @@ cifs_small_buf_release(void *buf_to_free)
} }
/* /*
Find a free multiplex id (SMB mid). Otherwise there could be * Find a free multiplex id (SMB mid). Otherwise there could be
mid collisions which might cause problems, demultiplexing the * mid collisions which might cause problems, demultiplexing the
wrong response to this request. Multiplex ids could collide if * wrong response to this request. Multiplex ids could collide if
one of a series requests takes much longer than the others, or * one of a series requests takes much longer than the others, or
if a very large number of long lived requests (byte range * if a very large number of long lived requests (byte range
locks or FindNotify requests) are pending. No more than * locks or FindNotify requests) are pending. No more than
64K-1 requests can be outstanding at one time. If no * 64K-1 requests can be outstanding at one time. If no
mids are available, return zero. A future optimization * mids are available, return zero. A future optimization
could make the combination of mids and uid the key we use * could make the combination of mids and uid the key we use
to demultiplex on (rather than mid alone). * to demultiplex on (rather than mid alone).
In addition to the above check, the cifs demultiplex * In addition to the above check, the cifs demultiplex
code already used the command code as a secondary * code already used the command code as a secondary
check of the frame and if signing is negotiated the * check of the frame and if signing is negotiated the
response would be discarded if the mid were the same * response would be discarded if the mid were the same
but the signature was wrong. Since the mid is not put in the * but the signature was wrong. Since the mid is not put in the
pending queue until later (when it is about to be dispatched) * pending queue until later (when it is about to be dispatched)
we do have to limit the number of outstanding requests * we do have to limit the number of outstanding requests
to somewhat less than 64K-1 although it is hard to imagine * to somewhat less than 64K-1 although it is hard to imagine
so many threads being in the vfs at one time. * so many threads being in the vfs at one time.
*/ */
__u16 GetNextMid(struct TCP_Server_Info *server) __u64 GetNextMid(struct TCP_Server_Info *server)
{ {
__u16 mid = 0; __u64 mid = 0;
__u16 last_mid; __u16 last_mid, cur_mid;
bool collision; bool collision;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
last_mid = server->CurrentMid; /* we do not want to loop forever */
server->CurrentMid++; /* mid is 16 bit only for CIFS/SMB */
/* This nested loop looks more expensive than it is. cur_mid = (__u16)((server->CurrentMid) & 0xffff);
In practice the list of pending requests is short, /* we do not want to loop forever */
fewer than 50, and the mids are likely to be unique last_mid = cur_mid;
on the first pass through the loop unless some request cur_mid++;
takes longer than the 64 thousand requests before it
(and it would also have to have been a request that /*
did not time out) */ * This nested loop looks more expensive than it is.
while (server->CurrentMid != last_mid) { * In practice the list of pending requests is short,
* fewer than 50, and the mids are likely to be unique
* on the first pass through the loop unless some request
* takes longer than the 64 thousand requests before it
* (and it would also have to have been a request that
* did not time out).
*/
while (cur_mid != last_mid) {
struct mid_q_entry *mid_entry; struct mid_q_entry *mid_entry;
unsigned int num_mids; unsigned int num_mids;
collision = false; collision = false;
if (server->CurrentMid == 0) if (cur_mid == 0)
server->CurrentMid++; cur_mid++;
num_mids = 0; num_mids = 0;
list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
++num_mids; ++num_mids;
if (mid_entry->mid == server->CurrentMid && if (mid_entry->mid == cur_mid &&
mid_entry->midState == MID_REQUEST_SUBMITTED) { mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
/* This mid is in use, try a different one */ /* This mid is in use, try a different one */
collision = true; collision = true;
break; break;
...@@ -282,10 +289,11 @@ __u16 GetNextMid(struct TCP_Server_Info *server) ...@@ -282,10 +289,11 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
server->tcpStatus = CifsNeedReconnect; server->tcpStatus = CifsNeedReconnect;
if (!collision) { if (!collision) {
mid = server->CurrentMid; mid = (__u64)cur_mid;
server->CurrentMid = mid;
break; break;
} }
server->CurrentMid++; cur_mid++;
} }
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
return mid; return mid;
...@@ -420,8 +428,10 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid) ...@@ -420,8 +428,10 @@ check_smb_hdr(struct smb_hdr *smb, __u16 mid)
} }
int int
checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read) checkSMB(char *buf, unsigned int total_read)
{ {
struct smb_hdr *smb = (struct smb_hdr *)buf;
__u16 mid = smb->Mid;
__u32 rfclen = be32_to_cpu(smb->smb_buf_length); __u32 rfclen = be32_to_cpu(smb->smb_buf_length);
__u32 clc_len; /* calculated length */ __u32 clc_len; /* calculated length */
cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x", cFYI(0, "checkSMB Length: 0x%x, smb_buf_length: 0x%x",
...@@ -502,8 +512,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read) ...@@ -502,8 +512,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int total_read)
} }
bool bool
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
{ {
struct smb_hdr *buf = (struct smb_hdr *)buffer;
struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp, *tmp1, *tmp2; struct list_head *tmp, *tmp1, *tmp2;
struct cifs_ses *ses; struct cifs_ses *ses;
...@@ -584,7 +595,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -584,7 +595,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
cifs_set_oplock_level(pCifsInode, cifs_set_oplock_level(pCifsInode,
pSMB->OplockLevel ? OPLOCK_READ : 0); pSMB->OplockLevel ? OPLOCK_READ : 0);
queue_work(system_nrt_wq, queue_work(cifsiod_wq,
&netfile->oplock_break); &netfile->oplock_break);
netfile->oplock_break_cancelled = false; netfile->oplock_break_cancelled = false;
...@@ -604,16 +615,15 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) ...@@ -604,16 +615,15 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
} }
void void
dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) dump_smb(void *buf, int smb_buf_length)
{ {
int i, j; int i, j;
char debug_line[17]; char debug_line[17];
unsigned char *buffer; unsigned char *buffer = buf;
if (traceSMB == 0) if (traceSMB == 0)
return; return;
buffer = (unsigned char *) smb_buf;
for (i = 0, j = 0; i < smb_buf_length; i++, j++) { for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
if (i % 8 == 0) { if (i % 8 == 0) {
/* have reached the beginning of line */ /* have reached the beginning of line */
......
...@@ -836,8 +836,9 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode) ...@@ -836,8 +836,9 @@ ntstatus_to_dos(__u32 ntstatus, __u8 *eclass, __u16 *ecode)
} }
int int
map_smb_to_linux_error(struct smb_hdr *smb, bool logErr) map_smb_to_linux_error(char *buf, bool logErr)
{ {
struct smb_hdr *smb = (struct smb_hdr *)buf;
unsigned int i; unsigned int i;
int rc = -EIO; /* if transport error smb error may not be set */ int rc = -EIO; /* if transport error smb error may not be set */
__u8 smberrclass; __u8 smberrclass;
......
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