diff options
-rw-r--r-- | fs/cifs/CHANGES | 4 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 78 | ||||
-rw-r--r-- | fs/cifs/file.c | 67 |
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 | |||
6 | read responses when buffer size over 64K and also fix wrap of | 6 | read responses when buffer size over 64K and also fix wrap of |
7 | max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in | 7 | max smb buffer size when CIFSMaxBufSize over 64K. Fix oops in |
8 | cifs_user_read and cifs_readpages (when EAGAIN on send of smb | 8 | cifs_user_read and cifs_readpages (when EAGAIN on send of smb |
9 | on socket is returned over and over) | 9 | on socket is returned over and over). Add POSIX (advisory) byte range |
10 | locking support (requires server with newest CIFS UNIX Extensions | ||
11 | to the protocol implemented). | ||
10 | 12 | ||
11 | Version 1.40 | 13 | Version 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 | ||
863 | typedef struct cifs_posix_lock { | 866 | typedef 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 | 268 | extern 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); | ||
269 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); | 272 | extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); |
270 | extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); | 273 | extern 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 | ||
1355 | int | 1355 | int |
1356 | CIFSSMBPosixLock(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 | |||
1433 | int | ||
1356 | CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | 1434 | CIFSSMBClose(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) | |||
577 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | 577 | int 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); |