From a24e2d7d8f512340991ef0a59cb5d08d491b8e98 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 3 Apr 2010 17:20:21 +0000 Subject: [CIFS] initialize nbytes at the beginning of CIFSSMBWrite() By doing this we always overwrite nbytes value that is being passed on to CIFSSMBWrite() and need not rely on the callers to initialize. CIFSSMBWrite2 is doing this already. CC: Stable Reviewed-by: Shirish Pargaonkar Reviewed-by: Jeff Layton Signed-off-by: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/cifs/cifssmb.c') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 7cc7f83e931..e1f90a3a016 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1430,6 +1430,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, __u32 bytes_sent; __u16 byte_count; + *nbytes = 0; + /* cFYI(1, ("write at %lld %d bytes", offset, count));*/ if (tcon->ses == NULL) return -ECONNABORTED; @@ -1512,7 +1514,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error in write = %d", rc)); - *nbytes = 0; } else { *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; -- cgit v1.2.3 From 6513a81e9325d712f1bfb9a1d7b750134e49ff18 Mon Sep 17 00:00:00 2001 From: Suresh Jayaraman Date: Wed, 31 Mar 2010 12:00:03 +0530 Subject: cifs: Fix a kernel BUG with remote OS/2 server (try #3) While chasing a bug report involving a OS/2 server, I noticed the server sets pSMBr->CountHigh to a incorrect value even in case of normal writes. This results in 'nbytes' being computed wrongly and triggers a kernel BUG at mm/filemap.c. void iov_iter_advance(struct iov_iter *i, size_t bytes) { BUG_ON(i->count < bytes); <--- BUG here Why the server is setting 'CountHigh' is not clear but only does so after writing 64k bytes. Though this looks like the server bug, the client side crash may not be acceptable. The workaround is to mask off high 16 bits if the number of bytes written as returned by the server is greater than the bytes requested by the client as suggested by Jeff Layton. CC: Stable Reviewed-by: Jeff Layton Signed-off-by: Suresh Jayaraman Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'fs/cifs/cifssmb.c') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e1f90a3a016..f213b8ae43c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1518,6 +1518,14 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; *nbytes += le16_to_cpu(pSMBr->Count); + + /* + * Mask off high 16 bits when bytes written as returned by the + * server is greater than bytes requested by the client. Some + * OS/2 servers are known to set incorrect CountHigh values. + */ + if (*nbytes > count) + *nbytes &= 0xFFFF; } cifs_buf_release(pSMB); @@ -1606,6 +1614,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; *nbytes += le16_to_cpu(pSMBr->Count); + + /* + * Mask off high 16 bits when bytes written as returned by the + * server is greater than bytes requested by the client. OS/2 + * servers are known to set incorrect CountHigh values. + */ + if (*nbytes > count) + *nbytes &= 0xFFFF; } /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ -- cgit v1.2.3 From f05337c6ac48d19d354e0640a8eb8fc884f82bcc Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 5 Apr 2010 09:59:14 +0400 Subject: not overwriting file_lock structure after GET_LK If we have preventing lock, cifs should overwrite file_lock structure with info about preventing lock. If we haven't preventing lock, cifs should leave it unchanged except for the lock type (change it to F_UNLCK). Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'fs/cifs/cifssmb.c') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f213b8ae43c..184a399749a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1810,8 +1810,21 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon, } parm_data = (struct cifs_posix_lock *) ((char *)&pSMBr->hdr.Protocol + data_offset); - if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK)) + if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK)) pLockData->fl_type = F_UNLCK; + else { + if (parm_data->lock_type == + __constant_cpu_to_le16(CIFS_RDLCK)) + pLockData->fl_type = F_RDLCK; + else if (parm_data->lock_type == + __constant_cpu_to_le16(CIFS_WRLCK)) + pLockData->fl_type = F_WRLCK; + + pLockData->fl_start = parm_data->start; + pLockData->fl_end = parm_data->start + + parm_data->length - 1; + pLockData->fl_pid = parm_data->pid; + } } plk_err_exit: -- cgit v1.2.3