Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
not overwriting file_lock structure after GET_LK
cifs: Fix a kernel BUG with remote OS/2 server (try #3)
[CIFS] initialize nbytes at the beginning of CIFSSMBWrite()
[CIFS] Add mmap for direct, nobrl cifs mount types
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 5183bc2..ded66be 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -808,6 +808,7 @@
.release = cifs_close,
.fsync = cifs_fsync,
.flush = cifs_flush,
+ .mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3f4fbd6..5d3f29f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1431,6 +1431,8 @@
__u32 bytes_sent;
__u16 byte_count;
+ *nbytes = 0;
+
/* cFYI(1, ("write at %lld %d bytes", offset, count));*/
if (tcon->ses == NULL)
return -ECONNABORTED;
@@ -1513,11 +1515,18 @@
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;
*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 +1615,14 @@
*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 */
@@ -1794,8 +1811,21 @@
}
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:
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 058b390..9b11a8f 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -839,8 +839,32 @@
} else {
/* if rc == ERR_SHARING_VIOLATION ? */
- rc = 0; /* do not change lock type to unlock
- since range in use */
+ rc = 0;
+
+ if (lockType & LOCKING_ANDX_SHARED_LOCK) {
+ pfLock->fl_type = F_WRLCK;
+ } else {
+ rc = CIFSSMBLock(xid, tcon, netfid, length,
+ pfLock->fl_start, 0, 1,
+ lockType | LOCKING_ANDX_SHARED_LOCK,
+ 0 /* wait flag */);
+ if (rc == 0) {
+ rc = CIFSSMBLock(xid, tcon, netfid,
+ length, pfLock->fl_start, 1, 0,
+ lockType |
+ LOCKING_ANDX_SHARED_LOCK,
+ 0 /* wait flag */);
+ pfLock->fl_type = F_RDLCK;
+ if (rc != 0)
+ cERROR(1, ("Error unlocking "
+ "previously locked range %d "
+ "during test of lock", rc));
+ rc = 0;
+ } else {
+ pfLock->fl_type = F_WRLCK;
+ rc = 0;
+ }
+ }
}
FreeXid(xid);