Commit 08547b03 authored by Steve French's avatar Steve French

[CIFS] Add posix (advisory) byte range locking support to cifs client

Samba (version 3) server support for this is also currently being
done.  This client code is in an experimental path (requires enabling
/proc/fs/cifs/Experimental) while it is being tested.
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent d47d7c1a
......@@ -6,7 +6,9 @@ be followed (not just recognized). Fix wraparound of bcc on
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
------------
......
......@@ -859,7 +859,10 @@ typedef struct smb_com_lock_req {
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) */
......
......@@ -265,7 +265,10 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
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);
......
......@@ -1352,6 +1352,84 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
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)
{
......
......@@ -577,13 +577,14 @@ int cifs_closedir(struct inode *inode, struct file *file)
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;
......@@ -640,27 +641,39 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
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 {
......@@ -672,12 +685,28 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
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);
......
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