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); |
