diff options
author | Suresh Jayaraman <sjayaraman@suse.de> | 2010-03-31 02:30:03 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-04-03 13:24:20 -0400 |
commit | 6513a81e9325d712f1bfb9a1d7b750134e49ff18 (patch) | |
tree | f0f00a27d29ad6b6dc7cb05f6b10101aa01b0c64 /fs/cifs | |
parent | a24e2d7d8f512340991ef0a59cb5d08d491b8e98 (diff) |
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 <stable@kernel.org>
Reviewed-by: Jeff Layton <jlayton@samba.org>
Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/cifssmb.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index e1f90a3a0162..f213b8ae43c1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1518,6 +1518,14 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1518 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1518 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1519 | *nbytes = (*nbytes) << 16; | 1519 | *nbytes = (*nbytes) << 16; |
1520 | *nbytes += le16_to_cpu(pSMBr->Count); | 1520 | *nbytes += le16_to_cpu(pSMBr->Count); |
1521 | |||
1522 | /* | ||
1523 | * Mask off high 16 bits when bytes written as returned by the | ||
1524 | * server is greater than bytes requested by the client. Some | ||
1525 | * OS/2 servers are known to set incorrect CountHigh values. | ||
1526 | */ | ||
1527 | if (*nbytes > count) | ||
1528 | *nbytes &= 0xFFFF; | ||
1521 | } | 1529 | } |
1522 | 1530 | ||
1523 | cifs_buf_release(pSMB); | 1531 | cifs_buf_release(pSMB); |
@@ -1606,6 +1614,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1606 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1614 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1607 | *nbytes = (*nbytes) << 16; | 1615 | *nbytes = (*nbytes) << 16; |
1608 | *nbytes += le16_to_cpu(pSMBr->Count); | 1616 | *nbytes += le16_to_cpu(pSMBr->Count); |
1617 | |||
1618 | /* | ||
1619 | * Mask off high 16 bits when bytes written as returned by the | ||
1620 | * server is greater than bytes requested by the client. OS/2 | ||
1621 | * servers are known to set incorrect CountHigh values. | ||
1622 | */ | ||
1623 | if (*nbytes > count) | ||
1624 | *nbytes &= 0xFFFF; | ||
1609 | } | 1625 | } |
1610 | 1626 | ||
1611 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ | 1627 | /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ |