diff options
Diffstat (limited to 'fs/cifs/file.c')
| -rw-r--r-- | fs/cifs/file.c | 97 |
1 files changed, 80 insertions, 17 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 944d2b9e092d..e9c5ba9084fc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | * | 5 | * |
| 6 | * Copyright (C) International Business Machines Corp., 2002,2003 | 6 | * Copyright (C) International Business Machines Corp., 2002,2003 |
| 7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
| 8 | * Jeremy Allison (jra@samba.org) | ||
| 8 | * | 9 | * |
| 9 | * This library is free software; you can redistribute it and/or modify | 10 | * This library is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU Lesser General Public License as published | 11 | * it under the terms of the GNU Lesser General Public License as published |
| @@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
| 47 | private_data->netfid = netfid; | 48 | private_data->netfid = netfid; |
| 48 | private_data->pid = current->tgid; | 49 | private_data->pid = current->tgid; |
| 49 | init_MUTEX(&private_data->fh_sem); | 50 | init_MUTEX(&private_data->fh_sem); |
| 51 | init_MUTEX(&private_data->lock_sem); | ||
| 52 | INIT_LIST_HEAD(&private_data->llist); | ||
| 50 | private_data->pfile = file; /* needed for writepage */ | 53 | private_data->pfile = file; /* needed for writepage */ |
| 51 | private_data->pInode = inode; | 54 | private_data->pInode = inode; |
| 52 | private_data->invalidHandle = FALSE; | 55 | private_data->invalidHandle = FALSE; |
| @@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 473 | cifs_sb = CIFS_SB(inode->i_sb); | 476 | cifs_sb = CIFS_SB(inode->i_sb); |
| 474 | pTcon = cifs_sb->tcon; | 477 | pTcon = cifs_sb->tcon; |
| 475 | if (pSMBFile) { | 478 | if (pSMBFile) { |
| 479 | struct cifsLockInfo *li, *tmp; | ||
| 480 | |||
| 476 | pSMBFile->closePend = TRUE; | 481 | pSMBFile->closePend = TRUE; |
| 477 | if (pTcon) { | 482 | if (pTcon) { |
| 478 | /* no sense reconnecting to close a file that is | 483 | /* no sense reconnecting to close a file that is |
| @@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 496 | pSMBFile->netfid); | 501 | pSMBFile->netfid); |
| 497 | } | 502 | } |
| 498 | } | 503 | } |
| 504 | |||
| 505 | /* Delete any outstanding lock records. | ||
| 506 | We'll lose them when the file is closed anyway. */ | ||
| 507 | down(&pSMBFile->lock_sem); | ||
| 508 | list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) { | ||
| 509 | list_del(&li->llist); | ||
| 510 | kfree(li); | ||
| 511 | } | ||
| 512 | up(&pSMBFile->lock_sem); | ||
| 513 | |||
| 499 | write_lock(&GlobalSMBSeslock); | 514 | write_lock(&GlobalSMBSeslock); |
| 500 | list_del(&pSMBFile->flist); | 515 | list_del(&pSMBFile->flist); |
| 501 | list_del(&pSMBFile->tlist); | 516 | list_del(&pSMBFile->tlist); |
| @@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
| 570 | return rc; | 585 | return rc; |
| 571 | } | 586 | } |
| 572 | 587 | ||
| 588 | static int store_file_lock(struct cifsFileInfo *fid, __u64 len, | ||
| 589 | __u64 offset, __u8 lockType) | ||
| 590 | { | ||
| 591 | struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); | ||
| 592 | if (li == NULL) | ||
| 593 | return -ENOMEM; | ||
| 594 | li->offset = offset; | ||
| 595 | li->length = len; | ||
| 596 | li->type = lockType; | ||
| 597 | down(&fid->lock_sem); | ||
| 598 | list_add(&li->llist, &fid->llist); | ||
| 599 | up(&fid->lock_sem); | ||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 573 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | 603 | int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) |
| 574 | { | 604 | { |
| 575 | int rc, xid; | 605 | int rc, xid; |
| @@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 581 | struct cifsTconInfo *pTcon; | 611 | struct cifsTconInfo *pTcon; |
| 582 | __u16 netfid; | 612 | __u16 netfid; |
| 583 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; | 613 | __u8 lockType = LOCKING_ANDX_LARGE_FILES; |
| 614 | int posix_locking; | ||
| 584 | 615 | ||
| 585 | length = 1 + pfLock->fl_end - pfLock->fl_start; | 616 | length = 1 + pfLock->fl_end - pfLock->fl_start; |
| 586 | rc = -EACCES; | 617 | rc = -EACCES; |
| @@ -639,15 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 639 | } | 670 | } |
| 640 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 671 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
| 641 | 672 | ||
| 673 | posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
| 674 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability)); | ||
| 642 | 675 | ||
| 643 | /* BB add code here to normalize offset and length to | 676 | /* BB add code here to normalize offset and length to |
| 644 | account for negative length which we can not accept over the | 677 | account for negative length which we can not accept over the |
| 645 | wire */ | 678 | wire */ |
| 646 | if (IS_GETLK(cmd)) { | 679 | if (IS_GETLK(cmd)) { |
| 647 | if(experimEnabled && | 680 | if(posix_locking) { |
| 648 | (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | ||
| 649 | (CIFS_UNIX_FCNTL_CAP & | ||
| 650 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | ||
| 651 | int posix_lock_type; | 681 | int posix_lock_type; |
| 652 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 682 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
| 653 | posix_lock_type = CIFS_RDLCK; | 683 | posix_lock_type = CIFS_RDLCK; |
| @@ -683,10 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 683 | FreeXid(xid); | 713 | FreeXid(xid); |
| 684 | return rc; | 714 | return rc; |
| 685 | } | 715 | } |
| 686 | if (experimEnabled && | 716 | |
| 687 | (cifs_sb->tcon->ses->capabilities & CAP_UNIX) && | 717 | if (!numLock && !numUnlock) { |
| 688 | (CIFS_UNIX_FCNTL_CAP & | 718 | /* if no lock or unlock then nothing |
| 689 | le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability))) { | 719 | to do since we do not know what it is */ |
| 720 | FreeXid(xid); | ||
| 721 | return -EOPNOTSUPP; | ||
| 722 | } | ||
| 723 | |||
| 724 | if (posix_locking) { | ||
| 690 | int posix_lock_type; | 725 | int posix_lock_type; |
| 691 | if(lockType & LOCKING_ANDX_SHARED_LOCK) | 726 | if(lockType & LOCKING_ANDX_SHARED_LOCK) |
| 692 | posix_lock_type = CIFS_RDLCK; | 727 | posix_lock_type = CIFS_RDLCK; |
| @@ -695,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
| 695 | 730 | ||
| 696 | if(numUnlock == 1) | 731 | if(numUnlock == 1) |
| 697 | posix_lock_type = CIFS_UNLCK; | 732 | posix_lock_type = CIFS_UNLCK; |
| 698 | else if(numLock == 0) { | 733 | |
| 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 */, | 734 | rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */, |
| 705 | length, pfLock, | 735 | length, pfLock, |
| 706 | posix_lock_type, wait_flag); | 736 | posix_lock_type, wait_flag); |
| 707 | } else | 737 | } else { |
| 708 | rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, | 738 | struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data; |
| 709 | numUnlock, numLock, lockType, wait_flag); | 739 | |
| 740 | if (numLock) { | ||
| 741 | rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start, | ||
| 742 | 0, numLock, lockType, wait_flag); | ||
| 743 | |||
| 744 | if (rc == 0) { | ||
| 745 | /* For Windows locks we must store them. */ | ||
| 746 | rc = store_file_lock(fid, length, | ||
| 747 | pfLock->fl_start, lockType); | ||
| 748 | } | ||
| 749 | } else if (numUnlock) { | ||
| 750 | /* For each stored lock that this unlock overlaps | ||
| 751 | completely, unlock it. */ | ||
| 752 | int stored_rc = 0; | ||
| 753 | struct cifsLockInfo *li, *tmp; | ||
| 754 | |||
| 755 | down(&fid->lock_sem); | ||
| 756 | list_for_each_entry_safe(li, tmp, &fid->llist, llist) { | ||
| 757 | if (pfLock->fl_start <= li->offset && | ||
| 758 | length >= li->length) { | ||
| 759 | stored_rc = CIFSSMBLock(xid, pTcon, netfid, | ||
| 760 | li->length, li->offset, | ||
| 761 | 1, 0, li->type, FALSE); | ||
| 762 | if (stored_rc) | ||
| 763 | rc = stored_rc; | ||
| 764 | |||
| 765 | list_del(&li->llist); | ||
| 766 | kfree(li); | ||
| 767 | } | ||
| 768 | } | ||
| 769 | up(&fid->lock_sem); | ||
| 770 | } | ||
| 771 | } | ||
| 772 | |||
| 710 | if (pfLock->fl_flags & FL_POSIX) | 773 | if (pfLock->fl_flags & FL_POSIX) |
| 711 | posix_lock_file_wait(file, pfLock); | 774 | posix_lock_file_wait(file, pfLock); |
| 712 | FreeXid(xid); | 775 | FreeXid(xid); |
