aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/file.c
diff options
context:
space:
mode:
authorPavel Shilovsky <piastryyy@gmail.com>2010-08-17 03:26:00 -0400
committerSteve French <smfrench@gmail.com>2011-10-13 18:16:28 -0400
commit03776f4516bc299b3145595bdd704d40d69adc02 (patch)
treea4c17c0120d5865f322ec5362aa2b3f7f0b826d9 /fs/cifs/file.c
parent94443f43404239c2a6dc4252a7cb9e77f5b1eb6e (diff)
CIFS: Simplify byte range locking code
Split cifs_lock into several functions and let CIFSSMBLock get pid as an argument. Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r--fs/cifs/file.c370
1 files changed, 201 insertions, 169 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 237192ae7587..ab85699c5653 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -639,8 +639,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
639 return rc; 639 return rc;
640} 640}
641 641
642static int store_file_lock(struct cifsFileInfo *fid, __u64 len, 642static int store_file_lock(struct cifsFileInfo *cfile, __u64 len,
643 __u64 offset, __u8 lockType) 643 __u64 offset, __u8 type, __u16 netfid)
644{ 644{
645 struct cifsLockInfo *li = 645 struct cifsLockInfo *li =
646 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); 646 kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
@@ -648,210 +648,241 @@ static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
648 return -ENOMEM; 648 return -ENOMEM;
649 li->offset = offset; 649 li->offset = offset;
650 li->length = len; 650 li->length = len;
651 li->type = lockType; 651 li->type = type;
652 mutex_lock(&fid->lock_mutex); 652 li->pid = current->tgid;
653 list_add(&li->llist, &fid->llist); 653 mutex_lock(&cfile->lock_mutex);
654 mutex_unlock(&fid->lock_mutex); 654 list_add_tail(&li->llist, &cfile->llist);
655 mutex_unlock(&cfile->lock_mutex);
655 return 0; 656 return 0;
656} 657}
657 658
658int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) 659static void
660cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock,
661 bool *wait_flag)
659{ 662{
660 int rc, xid; 663 if (flock->fl_flags & FL_POSIX)
661 __u32 numLock = 0;
662 __u32 numUnlock = 0;
663 __u64 length;
664 bool wait_flag = false;
665 struct cifs_sb_info *cifs_sb;
666 struct cifs_tcon *tcon;
667 __u16 netfid;
668 __u8 lockType = LOCKING_ANDX_LARGE_FILES;
669 bool posix_locking = 0;
670
671 length = 1 + pfLock->fl_end - pfLock->fl_start;
672 rc = -EACCES;
673 xid = GetXid();
674
675 cFYI(1, "Lock parm: 0x%x flockflags: "
676 "0x%x flocktype: 0x%x start: %lld end: %lld",
677 cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
678 pfLock->fl_end);
679
680 if (pfLock->fl_flags & FL_POSIX)
681 cFYI(1, "Posix"); 664 cFYI(1, "Posix");
682 if (pfLock->fl_flags & FL_FLOCK) 665 if (flock->fl_flags & FL_FLOCK)
683 cFYI(1, "Flock"); 666 cFYI(1, "Flock");
684 if (pfLock->fl_flags & FL_SLEEP) { 667 if (flock->fl_flags & FL_SLEEP) {
685 cFYI(1, "Blocking lock"); 668 cFYI(1, "Blocking lock");
686 wait_flag = true; 669 *wait_flag = true;
687 } 670 }
688 if (pfLock->fl_flags & FL_ACCESS) 671 if (flock->fl_flags & FL_ACCESS)
689 cFYI(1, "Process suspended by mandatory locking - " 672 cFYI(1, "Process suspended by mandatory locking - "
690 "not implemented yet"); 673 "not implemented yet");
691 if (pfLock->fl_flags & FL_LEASE) 674 if (flock->fl_flags & FL_LEASE)
692 cFYI(1, "Lease on file - not implemented yet"); 675 cFYI(1, "Lease on file - not implemented yet");
693 if (pfLock->fl_flags & 676 if (flock->fl_flags &
694 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) 677 (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
695 cFYI(1, "Unknown lock flags 0x%x", pfLock->fl_flags); 678 cFYI(1, "Unknown lock flags 0x%x", flock->fl_flags);
696 679
697 if (pfLock->fl_type == F_WRLCK) { 680 *type = LOCKING_ANDX_LARGE_FILES;
681 if (flock->fl_type == F_WRLCK) {
698 cFYI(1, "F_WRLCK "); 682 cFYI(1, "F_WRLCK ");
699 numLock = 1; 683 *lock = 1;
700 } else if (pfLock->fl_type == F_UNLCK) { 684 } else if (flock->fl_type == F_UNLCK) {
701 cFYI(1, "F_UNLCK"); 685 cFYI(1, "F_UNLCK");
702 numUnlock = 1; 686 *unlock = 1;
703 /* Check if unlock includes more than 687 /* Check if unlock includes more than one lock range */
704 one lock range */ 688 } else if (flock->fl_type == F_RDLCK) {
705 } else if (pfLock->fl_type == F_RDLCK) {
706 cFYI(1, "F_RDLCK"); 689 cFYI(1, "F_RDLCK");
707 lockType |= LOCKING_ANDX_SHARED_LOCK; 690 *type |= LOCKING_ANDX_SHARED_LOCK;
708 numLock = 1; 691 *lock = 1;
709 } else if (pfLock->fl_type == F_EXLCK) { 692 } else if (flock->fl_type == F_EXLCK) {
710 cFYI(1, "F_EXLCK"); 693 cFYI(1, "F_EXLCK");
711 numLock = 1; 694 *lock = 1;
712 } else if (pfLock->fl_type == F_SHLCK) { 695 } else if (flock->fl_type == F_SHLCK) {
713 cFYI(1, "F_SHLCK"); 696 cFYI(1, "F_SHLCK");
714 lockType |= LOCKING_ANDX_SHARED_LOCK; 697 *type |= LOCKING_ANDX_SHARED_LOCK;
715 numLock = 1; 698 *lock = 1;
716 } else 699 } else
717 cFYI(1, "Unknown type of lock"); 700 cFYI(1, "Unknown type of lock");
701}
718 702
719 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); 703static int
720 tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink); 704cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type,
721 netfid = ((struct cifsFileInfo *)file->private_data)->netfid; 705 bool wait_flag, bool posix_lck, int xid)
722 706{
723 if ((tcon->ses->capabilities & CAP_UNIX) && 707 int rc = 0;
724 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 708 __u64 length = 1 + flock->fl_end - flock->fl_start;
725 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 709 __u16 netfid = cfile->netfid;
726 posix_locking = 1; 710 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
727 /* BB add code here to normalize offset and length to
728 account for negative length which we can not accept over the
729 wire */
730 if (IS_GETLK(cmd)) {
731 if (posix_locking) {
732 int posix_lock_type;
733 if (lockType & LOCKING_ANDX_SHARED_LOCK)
734 posix_lock_type = CIFS_RDLCK;
735 else
736 posix_lock_type = CIFS_WRLCK;
737 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
738 length, pfLock, posix_lock_type,
739 wait_flag);
740 FreeXid(xid);
741 return rc;
742 }
743
744 /* BB we could chain these into one lock request BB */
745 rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
746 0, 1, lockType, 0 /* wait flag */, 0);
747 if (rc == 0) {
748 rc = CIFSSMBLock(xid, tcon, netfid, length,
749 pfLock->fl_start, 1 /* numUnlock */ ,
750 0 /* numLock */ , lockType,
751 0 /* wait flag */, 0);
752 pfLock->fl_type = F_UNLCK;
753 if (rc != 0)
754 cERROR(1, "Error unlocking previously locked "
755 "range %d during test of lock", rc);
756 rc = 0;
757
758 } else {
759 /* if rc == ERR_SHARING_VIOLATION ? */
760 rc = 0;
761 711
762 if (lockType & LOCKING_ANDX_SHARED_LOCK) { 712 if (posix_lck) {
763 pfLock->fl_type = F_WRLCK; 713 int posix_lock_type;
764 } else { 714 if (type & LOCKING_ANDX_SHARED_LOCK)
765 rc = CIFSSMBLock(xid, tcon, netfid, length, 715 posix_lock_type = CIFS_RDLCK;
766 pfLock->fl_start, 0, 1, 716 else
767 lockType | LOCKING_ANDX_SHARED_LOCK, 717 posix_lock_type = CIFS_WRLCK;
768 0 /* wait flag */, 0); 718 rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
769 if (rc == 0) { 719 length, flock, posix_lock_type,
770 rc = CIFSSMBLock(xid, tcon, netfid, 720 wait_flag);
771 length, pfLock->fl_start, 1, 0, 721 return rc;
772 lockType | 722 }
773 LOCKING_ANDX_SHARED_LOCK,
774 0 /* wait flag */, 0);
775 pfLock->fl_type = F_RDLCK;
776 if (rc != 0)
777 cERROR(1, "Error unlocking "
778 "previously locked range %d "
779 "during test of lock", rc);
780 rc = 0;
781 } else {
782 pfLock->fl_type = F_WRLCK;
783 rc = 0;
784 }
785 }
786 }
787 723
788 FreeXid(xid); 724 /* BB we could chain these into one lock request BB */
725 rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
726 flock->fl_start, 0, 1, type, 0, 0);
727 if (rc == 0) {
728 rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
729 length, flock->fl_start, 1, 0,
730 type, 0, 0);
731 flock->fl_type = F_UNLCK;
732 if (rc != 0)
733 cERROR(1, "Error unlocking previously locked "
734 "range %d during test of lock", rc);
735 rc = 0;
789 return rc; 736 return rc;
790 } 737 }
791 738
792 if (!numLock && !numUnlock) { 739 if (type & LOCKING_ANDX_SHARED_LOCK) {
793 /* if no lock or unlock then nothing 740 flock->fl_type = F_WRLCK;
794 to do since we do not know what it is */ 741 rc = 0;
795 FreeXid(xid); 742 return rc;
796 return -EOPNOTSUPP;
797 } 743 }
798 744
799 if (posix_locking) { 745 rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
746 flock->fl_start, 0, 1,
747 type | LOCKING_ANDX_SHARED_LOCK, 0, 0);
748 if (rc == 0) {
749 rc = CIFSSMBLock(xid, tcon, netfid, current->tgid,
750 length, flock->fl_start, 1, 0,
751 type | LOCKING_ANDX_SHARED_LOCK,
752 0, 0);
753 flock->fl_type = F_RDLCK;
754 if (rc != 0)
755 cERROR(1, "Error unlocking previously locked "
756 "range %d during test of lock", rc);
757 } else
758 flock->fl_type = F_WRLCK;
759
760 rc = 0;
761 return rc;
762}
763
764static int
765cifs_setlk(struct file *file, struct file_lock *flock, __u8 type,
766 bool wait_flag, bool posix_lck, int lock, int unlock, int xid)
767{
768 int rc = 0;
769 __u64 length = 1 + flock->fl_end - flock->fl_start;
770 struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
771 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
772 __u16 netfid = cfile->netfid;
773
774 if (posix_lck) {
800 int posix_lock_type; 775 int posix_lock_type;
801 if (lockType & LOCKING_ANDX_SHARED_LOCK) 776 if (type & LOCKING_ANDX_SHARED_LOCK)
802 posix_lock_type = CIFS_RDLCK; 777 posix_lock_type = CIFS_RDLCK;
803 else 778 else
804 posix_lock_type = CIFS_WRLCK; 779 posix_lock_type = CIFS_WRLCK;
805 780
806 if (numUnlock == 1) 781 if (unlock == 1)
807 posix_lock_type = CIFS_UNLCK; 782 posix_lock_type = CIFS_UNLCK;
808 783
809 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, 784 rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length,
810 length, pfLock, posix_lock_type, 785 flock, posix_lock_type, wait_flag);
811 wait_flag); 786 goto out;
812 } else { 787 }
813 struct cifsFileInfo *fid = file->private_data;
814
815 if (numLock) {
816 rc = CIFSSMBLock(xid, tcon, netfid, length,
817 pfLock->fl_start, 0, numLock, lockType,
818 wait_flag, 0);
819
820 if (rc == 0) {
821 /* For Windows locks we must store them. */
822 rc = store_file_lock(fid, length,
823 pfLock->fl_start, lockType);
824 }
825 } else if (numUnlock) {
826 /* For each stored lock that this unlock overlaps
827 completely, unlock it. */
828 int stored_rc = 0;
829 struct cifsLockInfo *li, *tmp;
830 788
831 rc = 0; 789 if (lock) {
832 mutex_lock(&fid->lock_mutex); 790 rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length,
833 list_for_each_entry_safe(li, tmp, &fid->llist, llist) { 791 flock->fl_start, 0, lock, type, wait_flag, 0);
834 if (pfLock->fl_start <= li->offset && 792 if (rc == 0) {
835 (pfLock->fl_start + length) >= 793 /* For Windows locks we must store them. */
836 (li->offset + li->length)) { 794 rc = store_file_lock(cfile, length, flock->fl_start,
837 stored_rc = CIFSSMBLock(xid, tcon, 795 type, netfid);
838 netfid, li->length, 796 }
839 li->offset, 1, 0, 797 } else if (unlock) {
840 li->type, false, 0); 798 /*
841 if (stored_rc) 799 * For each stored lock that this unlock overlaps completely,
842 rc = stored_rc; 800 * unlock it.
843 else { 801 */
844 list_del(&li->llist); 802 int stored_rc = 0;
845 kfree(li); 803 struct cifsLockInfo *li, *tmp;
846 } 804
847 } 805 mutex_lock(&cfile->lock_mutex);
806 list_for_each_entry_safe(li, tmp, &cfile->llist, llist) {
807 if (flock->fl_start > li->offset ||
808 (flock->fl_start + length) <
809 (li->offset + li->length))
810 continue;
811 if (current->tgid != li->pid)
812 continue;
813
814 stored_rc = CIFSSMBLock(xid, tcon, netfid,
815 current->tgid, li->length,
816 li->offset, 1, 0, li->type,
817 0, 0);
818 if (stored_rc)
819 rc = stored_rc;
820 else {
821 list_del(&li->llist);
822 kfree(li);
848 } 823 }
849 mutex_unlock(&fid->lock_mutex);
850 } 824 }
825 mutex_unlock(&cfile->lock_mutex);
826 }
827out:
828 if (flock->fl_flags & FL_POSIX)
829 posix_lock_file_wait(file, flock);
830 return rc;
831}
832
833int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
834{
835 int rc, xid;
836 int lock = 0, unlock = 0;
837 bool wait_flag = false;
838 bool posix_lck = false;
839 struct cifs_sb_info *cifs_sb;
840 struct cifs_tcon *tcon;
841 struct cifsInodeInfo *cinode;
842 struct cifsFileInfo *cfile;
843 __u16 netfid;
844 __u8 type;
845
846 rc = -EACCES;
847 xid = GetXid();
848
849 cFYI(1, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld "
850 "end: %lld", cmd, flock->fl_flags, flock->fl_type,
851 flock->fl_start, flock->fl_end);
852
853 cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag);
854
855 cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
856 cfile = (struct cifsFileInfo *)file->private_data;
857 tcon = tlink_tcon(cfile->tlink);
858 netfid = cfile->netfid;
859 cinode = CIFS_I(file->f_path.dentry->d_inode);
860
861 if ((tcon->ses->capabilities & CAP_UNIX) &&
862 (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
863 ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
864 posix_lck = true;
865 /*
866 * BB add code here to normalize offset and length to account for
867 * negative length which we can not accept over the wire.
868 */
869 if (IS_GETLK(cmd)) {
870 rc = cifs_getlk(cfile, flock, type, wait_flag, posix_lck, xid);
871 FreeXid(xid);
872 return rc;
873 }
874
875 if (!lock && !unlock) {
876 /*
877 * if no lock or unlock then nothing to do since we do not
878 * know what it is
879 */
880 FreeXid(xid);
881 return -EOPNOTSUPP;
851 } 882 }
852 883
853 if (pfLock->fl_flags & FL_POSIX) 884 rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock,
854 posix_lock_file_wait(file, pfLock); 885 xid);
855 FreeXid(xid); 886 FreeXid(xid);
856 return rc; 887 return rc;
857} 888}
@@ -2423,8 +2454,9 @@ void cifs_oplock_break(struct work_struct *work)
2423 * disconnected since oplock already released by the server 2454 * disconnected since oplock already released by the server
2424 */ 2455 */
2425 if (!cfile->oplock_break_cancelled) { 2456 if (!cfile->oplock_break_cancelled) {
2426 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid, 0, 2457 rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
2427 0, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, false, 2458 current->tgid, 0, 0, 0, 0,
2459 LOCKING_ANDX_OPLOCK_RELEASE, false,
2428 cinode->clientCanCacheRead ? 1 : 0); 2460 cinode->clientCanCacheRead ? 1 : 0);
2429 cFYI(1, "Oplock release rc = %d", rc); 2461 cFYI(1, "Oplock release rc = %d", rc);
2430 } 2462 }