read responses when buffer size over 64K and also fix wrap of
max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in
cifs_user_read and cifs_readpages (when EAGAIN on send of smb
-on socket is returned over and over)
+on socket is returned over and over). Add POSIX (advisory) byte range
+locking support (requires server with newest CIFS UNIX Extensions
+to the protocol implemented).
Version 1.40
------------
LOCKING_ANDX_RANGE Locks[1];
} __attribute__((packed)) LOCK_REQ;
-
+/* lock type */
+#define CIFS_RDLCK 0
+#define CIFS_WRLCK 1
+#define CIFS_UNLCK 2
typedef struct cifs_posix_lock {
__le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */
__le16 lock_flags; /* 1 = Wait (only valid for setlock) */
const __u64 offset, const __u32 numUnlock,
const __u32 numLock, const __u8 lockType,
const int waitFlag);
-
+extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+ const __u16 smb_file_id, const int get_flag,
+ const __u64 len, const __u64 offset,
+ const __u16 lock_type, const int waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
return rc;
}
+int
+CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
+ const __u16 smb_file_id, const int get_flag, const __u64 len,
+ const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
+{
+ struct smb_com_transaction2_sfi_req *pSMB = NULL;
+ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
+ char *data_offset;
+ struct cifs_posix_lock *parm_data;
+ int rc = 0;
+ int bytes_returned = 0;
+ __u16 params, param_offset, offset, byte_count, count;
+
+ cFYI(1, ("Posix Lock"));
+ rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
+
+ if (rc)
+ return rc;
+
+ pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
+
+ params = 6;
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
+ offset = param_offset + params;
+
+ data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+
+ count = sizeof(struct cifs_posix_lock);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ if(get_flag)
+ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+ else
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
+ byte_count = 3 /* pad */ + params + count;
+ pSMB->DataCount = cpu_to_le16(count);
+ pSMB->ParameterCount = cpu_to_le16(params);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->ParameterOffset = cpu_to_le16(param_offset);
+ parm_data = (struct cifs_posix_lock *)
+ (((char *) &pSMB->hdr.Protocol) + offset);
+
+ parm_data->lock_type = cpu_to_le16(lock_type);
+ if(waitFlag)
+ parm_data->lock_flags = 1;
+ parm_data->pid = cpu_to_le32(current->tgid);
+ parm_data->start = lkoffset;
+ parm_data->length = len; /* normalize negative numbers */
+
+ pSMB->DataOffset = cpu_to_le16(offset);
+ pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->ByteCount = cpu_to_le16(byte_count);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Send error in Posix Lock = %d", rc));
+ }
+
+ if (pSMB)
+ cifs_small_buf_release(pSMB);
+
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
+ since file handle passed in no longer valid */
+
+ return rc;
+}
+
+
int
CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
{
int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
{
int rc, xid;
- __u32 lockType = LOCKING_ANDX_LARGE_FILES;
__u32 numLock = 0;
__u32 numUnlock = 0;
__u64 length;
int wait_flag = FALSE;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
+ __u16 netfid;
+ __u8 lockType = LOCKING_ANDX_LARGE_FILES;
length = 1 + pfLock->fl_end - pfLock->fl_start;
rc = -EACCES;
FreeXid(xid);
return -EBADF;
}
+ netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
+
+ /* BB add code here to normalize offset and length to
+ account for negative length which we can not accept over the
+ wire */
if (IS_GETLK(cmd)) {
- rc = CIFSSMBLock(xid, pTcon,
- ((struct cifsFileInfo *)file->
- private_data)->netfid,
- length,
- pfLock->fl_start, 0, 1, lockType,
- 0 /* wait flag */ );
+ if(experimEnabled &&
+ (cifs_sb->tcon->ses->capabilities & CAP_UNIX)) {
+ int posix_lock_type;
+ if(lockType & LOCKING_ANDX_SHARED_LOCK)
+ posix_lock_type = CIFS_RDLCK;
+ else
+ posix_lock_type = CIFS_WRLCK;
+ rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
+ length, pfLock->fl_start,
+ posix_lock_type, wait_flag);
+ FreeXid(xid);
+ return rc;
+ }
+
+ /* BB we could chain these into one lock request BB */
+ rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+ 0, 1, lockType, 0 /* wait flag */ );
if (rc == 0) {
- rc = CIFSSMBLock(xid, pTcon,
- ((struct cifsFileInfo *) file->
- private_data)->netfid,
- length,
+ rc = CIFSSMBLock(xid, pTcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType,
0 /* wait flag */ );
pfLock->fl_type = F_UNLCK;
if (rc != 0)
cERROR(1, ("Error unlocking previously locked "
- "range %d during test of lock ",
- rc));
+ "range %d during test of lock", rc));
rc = 0;
} else {
FreeXid(xid);
return rc;
}
-
- rc = CIFSSMBLock(xid, pTcon,
- ((struct cifsFileInfo *) file->private_data)->
- netfid, length,
- pfLock->fl_start, numUnlock, numLock, lockType,
- wait_flag);
+ if (experimEnabled &&
+ (cifs_sb->tcon->ses->capabilities & CAP_UNIX)) {
+ int posix_lock_type;
+ if(lockType & LOCKING_ANDX_SHARED_LOCK)
+ posix_lock_type = CIFS_RDLCK;
+ else
+ posix_lock_type = CIFS_WRLCK;
+
+ if(numUnlock == 1)
+ posix_lock_type |= CIFS_UNLCK;
+ else if(numLock == 0) {
+ /* if no lock or unlock then nothing
+ to do since we do not know what it is */
+ FreeXid(xid);
+ return -EOPNOTSUPP;
+ }
+ rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
+ length, pfLock->fl_start,
+ posix_lock_type, wait_flag);
+ } else
+ rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+ numUnlock, numLock, lockType, wait_flag);
if (pfLock->fl_flags & FL_POSIX)
posix_lock_file_wait(file, pfLock);
FreeXid(xid);