aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/CHANGES4
-rw-r--r--fs/cifs/cifspdu.h5
-rw-r--r--fs/cifs/cifsproto.h5
-rw-r--r--fs/cifs/cifssmb.c78
-rw-r--r--fs/cifs/file.c67
5 files changed, 137 insertions, 22 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index cf846c73bc69..25d7df4a00c3 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -6,7 +6,9 @@ be followed (not just recognized). Fix wraparound of bcc on
6read responses when buffer size over 64K and also fix wrap of 6read responses when buffer size over 64K and also fix wrap of
7max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in 7max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in
8cifs_user_read and cifs_readpages (when EAGAIN on send of smb 8cifs_user_read and cifs_readpages (when EAGAIN on send of smb
9on socket is returned over and over) 9on socket is returned over and over). Add POSIX (advisory) byte range
10locking support (requires server with newest CIFS UNIX Extensions
11to the protocol implemented).
10 12
11Version 1.40 13Version 1.40
12------------ 14------------
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index cc2471094ca5..b75866115c21 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -859,7 +859,10 @@ typedef struct smb_com_lock_req {
859 LOCKING_ANDX_RANGE Locks[1]; 859 LOCKING_ANDX_RANGE Locks[1];
860} __attribute__((packed)) LOCK_REQ; 860} __attribute__((packed)) LOCK_REQ;
861 861
862 862/* lock type */
863#define CIFS_RDLCK 0
864#define CIFS_WRLCK 1
865#define CIFS_UNLCK 2
863typedef struct cifs_posix_lock { 866typedef struct cifs_posix_lock {
864 __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */ 867 __le16 lock_type; /* 0 = Read, 1 = Write, 2 = Unlock */
865 __le16 lock_flags; /* 1 = Wait (only valid for setlock) */ 868 __le16 lock_flags; /* 1 = Wait (only valid for setlock) */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 79e7f5a54323..b866e3a7ba67 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -265,7 +265,10 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
265 const __u64 offset, const __u32 numUnlock, 265 const __u64 offset, const __u32 numUnlock,
266 const __u32 numLock, const __u8 lockType, 266 const __u32 numLock, const __u8 lockType,
267 const int waitFlag); 267 const int waitFlag);
268 268extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
269 const __u16 smb_file_id, const int get_flag,
270 const __u64 len, const __u64 offset,
271 const __u16 lock_type, const int waitFlag);
269extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); 272extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
270extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); 273extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
271 274
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 0ddd97b1d87d..fea32e395cc6 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1353,6 +1353,84 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1353} 1353}
1354 1354
1355int 1355int
1356CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1357 const __u16 smb_file_id, const int get_flag, const __u64 len,
1358 const __u64 lkoffset, const __u16 lock_type, const int waitFlag)
1359{
1360 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1361 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1362 char *data_offset;
1363 struct cifs_posix_lock *parm_data;
1364 int rc = 0;
1365 int bytes_returned = 0;
1366 __u16 params, param_offset, offset, byte_count, count;
1367
1368 cFYI(1, ("Posix Lock"));
1369 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1370
1371 if (rc)
1372 return rc;
1373
1374 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1375
1376 params = 6;
1377 pSMB->MaxSetupCount = 0;
1378 pSMB->Reserved = 0;
1379 pSMB->Flags = 0;
1380 pSMB->Timeout = 0;
1381 pSMB->Reserved2 = 0;
1382 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1383 offset = param_offset + params;
1384
1385 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1386
1387 count = sizeof(struct cifs_posix_lock);
1388 pSMB->MaxParameterCount = cpu_to_le16(2);
1389 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1390 pSMB->SetupCount = 1;
1391 pSMB->Reserved3 = 0;
1392 if(get_flag)
1393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1394 else
1395 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1396 byte_count = 3 /* pad */ + params + count;
1397 pSMB->DataCount = cpu_to_le16(count);
1398 pSMB->ParameterCount = cpu_to_le16(params);
1399 pSMB->TotalDataCount = pSMB->DataCount;
1400 pSMB->TotalParameterCount = pSMB->ParameterCount;
1401 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1402 parm_data = (struct cifs_posix_lock *)
1403 (((char *) &pSMB->hdr.Protocol) + offset);
1404
1405 parm_data->lock_type = cpu_to_le16(lock_type);
1406 if(waitFlag)
1407 parm_data->lock_flags = 1;
1408 parm_data->pid = cpu_to_le32(current->tgid);
1409 parm_data->start = lkoffset;
1410 parm_data->length = len; /* normalize negative numbers */
1411
1412 pSMB->DataOffset = cpu_to_le16(offset);
1413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1414 pSMB->Reserved4 = 0;
1415 pSMB->hdr.smb_buf_length += byte_count;
1416 pSMB->ByteCount = cpu_to_le16(byte_count);
1417 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1418 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1419 if (rc) {
1420 cFYI(1, ("Send error in Posix Lock = %d", rc));
1421 }
1422
1423 if (pSMB)
1424 cifs_small_buf_release(pSMB);
1425
1426 /* Note: On -EAGAIN error only caller can retry on handle based calls
1427 since file handle passed in no longer valid */
1428
1429 return rc;
1430}
1431
1432
1433int
1356CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) 1434CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1357{ 1435{
1358 int rc = 0; 1436 int rc = 0;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e5bf1ad540d9..bd135c4e4958 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -577,13 +577,14 @@ int cifs_closedir(struct inode *inode, struct file *file)
577int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) 577int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
578{ 578{
579 int rc, xid; 579 int rc, xid;
580 __u32 lockType = LOCKING_ANDX_LARGE_FILES;
581 __u32 numLock = 0; 580 __u32 numLock = 0;
582 __u32 numUnlock = 0; 581 __u32 numUnlock = 0;
583 __u64 length; 582 __u64 length;
584 int wait_flag = FALSE; 583 int wait_flag = FALSE;
585 struct cifs_sb_info *cifs_sb; 584 struct cifs_sb_info *cifs_sb;
586 struct cifsTconInfo *pTcon; 585 struct cifsTconInfo *pTcon;
586 __u16 netfid;
587 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
587 588
588 length = 1 + pfLock->fl_end - pfLock->fl_start; 589 length = 1 + pfLock->fl_end - pfLock->fl_start;
589 rc = -EACCES; 590 rc = -EACCES;
@@ -640,27 +641,39 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
640 FreeXid(xid); 641 FreeXid(xid);
641 return -EBADF; 642 return -EBADF;
642 } 643 }
644 netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
645
643 646
647 /* BB add code here to normalize offset and length to
648 account for negative length which we can not accept over the
649 wire */
644 if (IS_GETLK(cmd)) { 650 if (IS_GETLK(cmd)) {
645 rc = CIFSSMBLock(xid, pTcon, 651 if(experimEnabled &&
646 ((struct cifsFileInfo *)file-> 652 (cifs_sb->tcon->ses->capabilities & CAP_UNIX)) {
647 private_data)->netfid, 653 int posix_lock_type;
648 length, 654 if(lockType & LOCKING_ANDX_SHARED_LOCK)
649 pfLock->fl_start, 0, 1, lockType, 655 posix_lock_type = CIFS_RDLCK;
650 0 /* wait flag */ ); 656 else
657 posix_lock_type = CIFS_WRLCK;
658 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
659 length, pfLock->fl_start,
660 posix_lock_type, wait_flag);
661 FreeXid(xid);
662 return rc;
663 }
664
665 /* BB we could chain these into one lock request BB */
666 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
667 0, 1, lockType, 0 /* wait flag */ );
651 if (rc == 0) { 668 if (rc == 0) {
652 rc = CIFSSMBLock(xid, pTcon, 669 rc = CIFSSMBLock(xid, pTcon, netfid, length,
653 ((struct cifsFileInfo *) file->
654 private_data)->netfid,
655 length,
656 pfLock->fl_start, 1 /* numUnlock */ , 670 pfLock->fl_start, 1 /* numUnlock */ ,
657 0 /* numLock */ , lockType, 671 0 /* numLock */ , lockType,
658 0 /* wait flag */ ); 672 0 /* wait flag */ );
659 pfLock->fl_type = F_UNLCK; 673 pfLock->fl_type = F_UNLCK;
660 if (rc != 0) 674 if (rc != 0)
661 cERROR(1, ("Error unlocking previously locked " 675 cERROR(1, ("Error unlocking previously locked "
662 "range %d during test of lock ", 676 "range %d during test of lock", rc));
663 rc));
664 rc = 0; 677 rc = 0;
665 678
666 } else { 679 } else {
@@ -672,12 +685,28 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
672 FreeXid(xid); 685 FreeXid(xid);
673 return rc; 686 return rc;
674 } 687 }
675 688 if (experimEnabled &&
676 rc = CIFSSMBLock(xid, pTcon, 689 (cifs_sb->tcon->ses->capabilities & CAP_UNIX)) {
677 ((struct cifsFileInfo *) file->private_data)-> 690 int posix_lock_type;
678 netfid, length, 691 if(lockType & LOCKING_ANDX_SHARED_LOCK)
679 pfLock->fl_start, numUnlock, numLock, lockType, 692 posix_lock_type = CIFS_RDLCK;
680 wait_flag); 693 else
694 posix_lock_type = CIFS_WRLCK;
695
696 if(numUnlock == 1)
697 posix_lock_type |= CIFS_UNLCK;
698 else if(numLock == 0) {
699 /* if no lock or unlock then nothing
700 to do since we do not know what it is */
701 FreeXid(xid);
702 return -EOPNOTSUPP;
703 }
704 rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
705 length, pfLock->fl_start,
706 posix_lock_type, wait_flag);
707 } else
708 rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
709 numUnlock, numLock, lockType, wait_flag);
681 if (pfLock->fl_flags & FL_POSIX) 710 if (pfLock->fl_flags & FL_POSIX)
682 posix_lock_file_wait(file, pfLock); 711 posix_lock_file_wait(file, pfLock);
683 FreeXid(xid); 712 FreeXid(xid);