diff options
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 131 |
1 files changed, 76 insertions, 55 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c1f063cd1b0c..4dd9283885e7 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -645,20 +645,20 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
645 | } | 645 | } |
646 | 646 | ||
647 | static struct cifsLockInfo * | 647 | static struct cifsLockInfo * |
648 | cifs_lock_init(__u64 len, __u64 offset, __u8 type, __u16 netfid) | 648 | cifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 netfid) |
649 | { | 649 | { |
650 | struct cifsLockInfo *li = | 650 | struct cifsLockInfo *lock = |
651 | kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); | 651 | kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); |
652 | if (!li) | 652 | if (!lock) |
653 | return li; | 653 | return lock; |
654 | li->netfid = netfid; | 654 | lock->offset = offset; |
655 | li->offset = offset; | 655 | lock->length = length; |
656 | li->length = len; | 656 | lock->type = type; |
657 | li->type = type; | 657 | lock->netfid = netfid; |
658 | li->pid = current->tgid; | 658 | lock->pid = current->tgid; |
659 | INIT_LIST_HEAD(&li->blist); | 659 | INIT_LIST_HEAD(&lock->blist); |
660 | init_waitqueue_head(&li->block_q); | 660 | init_waitqueue_head(&lock->block_q); |
661 | return li; | 661 | return lock; |
662 | } | 662 | } |
663 | 663 | ||
664 | static void | 664 | static void |
@@ -672,7 +672,7 @@ cifs_del_lock_waiters(struct cifsLockInfo *lock) | |||
672 | } | 672 | } |
673 | 673 | ||
674 | static bool | 674 | static bool |
675 | cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, | 675 | __cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, |
676 | __u64 length, __u8 type, __u16 netfid, | 676 | __u64 length, __u8 type, __u16 netfid, |
677 | struct cifsLockInfo **conf_lock) | 677 | struct cifsLockInfo **conf_lock) |
678 | { | 678 | { |
@@ -694,6 +694,21 @@ cifs_find_lock_conflict(struct cifsInodeInfo *cinode, __u64 offset, | |||
694 | return false; | 694 | return false; |
695 | } | 695 | } |
696 | 696 | ||
697 | static bool | ||
698 | cifs_find_lock_conflict(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, | ||
699 | struct cifsLockInfo **conf_lock) | ||
700 | { | ||
701 | return __cifs_find_lock_conflict(cinode, lock->offset, lock->length, | ||
702 | lock->type, lock->netfid, conf_lock); | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Check if there is another lock that prevents us to set the lock (mandatory | ||
707 | * style). If such a lock exists, update the flock structure with its | ||
708 | * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks | ||
709 | * or leave it the same if we can't. Returns 0 if we don't need to request to | ||
710 | * the server or 1 otherwise. | ||
711 | */ | ||
697 | static int | 712 | static int |
698 | cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | 713 | cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, |
699 | __u8 type, __u16 netfid, struct file_lock *flock) | 714 | __u8 type, __u16 netfid, struct file_lock *flock) |
@@ -704,8 +719,8 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | |||
704 | 719 | ||
705 | mutex_lock(&cinode->lock_mutex); | 720 | mutex_lock(&cinode->lock_mutex); |
706 | 721 | ||
707 | exist = cifs_find_lock_conflict(cinode, offset, length, type, netfid, | 722 | exist = __cifs_find_lock_conflict(cinode, offset, length, type, netfid, |
708 | &conf_lock); | 723 | &conf_lock); |
709 | if (exist) { | 724 | if (exist) { |
710 | flock->fl_start = conf_lock->offset; | 725 | flock->fl_start = conf_lock->offset; |
711 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; | 726 | flock->fl_end = conf_lock->offset + conf_lock->length - 1; |
@@ -723,40 +738,33 @@ cifs_lock_test(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | |||
723 | return rc; | 738 | return rc; |
724 | } | 739 | } |
725 | 740 | ||
726 | static int | 741 | static void |
727 | cifs_lock_add(struct cifsInodeInfo *cinode, __u64 len, __u64 offset, | 742 | cifs_lock_add(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock) |
728 | __u8 type, __u16 netfid) | ||
729 | { | 743 | { |
730 | struct cifsLockInfo *li; | ||
731 | |||
732 | li = cifs_lock_init(len, offset, type, netfid); | ||
733 | if (!li) | ||
734 | return -ENOMEM; | ||
735 | |||
736 | mutex_lock(&cinode->lock_mutex); | 744 | mutex_lock(&cinode->lock_mutex); |
737 | list_add_tail(&li->llist, &cinode->llist); | 745 | list_add_tail(&lock->llist, &cinode->llist); |
738 | mutex_unlock(&cinode->lock_mutex); | 746 | mutex_unlock(&cinode->lock_mutex); |
739 | return 0; | ||
740 | } | 747 | } |
741 | 748 | ||
749 | /* | ||
750 | * Set the byte-range lock (mandatory style). Returns: | ||
751 | * 1) 0, if we set the lock and don't need to request to the server; | ||
752 | * 2) 1, if no locks prevent us but we need to request to the server; | ||
753 | * 3) -EACCESS, if there is a lock that prevents us and wait is false. | ||
754 | */ | ||
742 | static int | 755 | static int |
743 | cifs_lock_add_if(struct cifsInodeInfo *cinode, __u64 offset, __u64 length, | 756 | cifs_lock_add_if(struct cifsInodeInfo *cinode, struct cifsLockInfo *lock, |
744 | __u8 type, __u16 netfid, bool wait) | 757 | bool wait) |
745 | { | 758 | { |
746 | struct cifsLockInfo *lock, *conf_lock; | 759 | struct cifsLockInfo *conf_lock; |
747 | bool exist; | 760 | bool exist; |
748 | int rc = 0; | 761 | int rc = 0; |
749 | 762 | ||
750 | lock = cifs_lock_init(length, offset, type, netfid); | ||
751 | if (!lock) | ||
752 | return -ENOMEM; | ||
753 | |||
754 | try_again: | 763 | try_again: |
755 | exist = false; | 764 | exist = false; |
756 | mutex_lock(&cinode->lock_mutex); | 765 | mutex_lock(&cinode->lock_mutex); |
757 | 766 | ||
758 | exist = cifs_find_lock_conflict(cinode, offset, length, type, netfid, | 767 | exist = cifs_find_lock_conflict(cinode, lock, &conf_lock); |
759 | &conf_lock); | ||
760 | if (!exist && cinode->can_cache_brlcks) { | 768 | if (!exist && cinode->can_cache_brlcks) { |
761 | list_add_tail(&lock->llist, &cinode->llist); | 769 | list_add_tail(&lock->llist, &cinode->llist); |
762 | mutex_unlock(&cinode->lock_mutex); | 770 | mutex_unlock(&cinode->lock_mutex); |
@@ -775,17 +783,21 @@ try_again: | |||
775 | (lock->blist.next == &lock->blist)); | 783 | (lock->blist.next == &lock->blist)); |
776 | if (!rc) | 784 | if (!rc) |
777 | goto try_again; | 785 | goto try_again; |
778 | else { | 786 | mutex_lock(&cinode->lock_mutex); |
779 | mutex_lock(&cinode->lock_mutex); | 787 | list_del_init(&lock->blist); |
780 | list_del_init(&lock->blist); | ||
781 | } | ||
782 | } | 788 | } |
783 | 789 | ||
784 | kfree(lock); | ||
785 | mutex_unlock(&cinode->lock_mutex); | 790 | mutex_unlock(&cinode->lock_mutex); |
786 | return rc; | 791 | return rc; |
787 | } | 792 | } |
788 | 793 | ||
794 | /* | ||
795 | * Check if there is another lock that prevents us to set the lock (posix | ||
796 | * style). If such a lock exists, update the flock structure with its | ||
797 | * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks | ||
798 | * or leave it the same if we can't. Returns 0 if we don't need to request to | ||
799 | * the server or 1 otherwise. | ||
800 | */ | ||
789 | static int | 801 | static int |
790 | cifs_posix_lock_test(struct file *file, struct file_lock *flock) | 802 | cifs_posix_lock_test(struct file *file, struct file_lock *flock) |
791 | { | 803 | { |
@@ -808,6 +820,12 @@ cifs_posix_lock_test(struct file *file, struct file_lock *flock) | |||
808 | return rc; | 820 | return rc; |
809 | } | 821 | } |
810 | 822 | ||
823 | /* | ||
824 | * Set the byte-range lock (posix style). Returns: | ||
825 | * 1) 0, if we set the lock and don't need to request to the server; | ||
826 | * 2) 1, if we need to request to the server; | ||
827 | * 3) <0, if the error occurs while setting the lock. | ||
828 | */ | ||
811 | static int | 829 | static int |
812 | cifs_posix_lock_set(struct file *file, struct file_lock *flock) | 830 | cifs_posix_lock_set(struct file *file, struct file_lock *flock) |
813 | { | 831 | { |
@@ -933,7 +951,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
933 | else | 951 | else |
934 | type = CIFS_WRLCK; | 952 | type = CIFS_WRLCK; |
935 | 953 | ||
936 | lck = cifs_lock_init(length, flock->fl_start, type, | 954 | lck = cifs_lock_init(flock->fl_start, length, type, |
937 | cfile->netfid); | 955 | cfile->netfid); |
938 | if (!lck) { | 956 | if (!lck) { |
939 | rc = -ENOMEM; | 957 | rc = -ENOMEM; |
@@ -1070,14 +1088,12 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1070 | if (rc != 0) | 1088 | if (rc != 0) |
1071 | cERROR(1, "Error unlocking previously locked " | 1089 | cERROR(1, "Error unlocking previously locked " |
1072 | "range %d during test of lock", rc); | 1090 | "range %d during test of lock", rc); |
1073 | rc = 0; | 1091 | return 0; |
1074 | return rc; | ||
1075 | } | 1092 | } |
1076 | 1093 | ||
1077 | if (type & LOCKING_ANDX_SHARED_LOCK) { | 1094 | if (type & LOCKING_ANDX_SHARED_LOCK) { |
1078 | flock->fl_type = F_WRLCK; | 1095 | flock->fl_type = F_WRLCK; |
1079 | rc = 0; | 1096 | return 0; |
1080 | return rc; | ||
1081 | } | 1097 | } |
1082 | 1098 | ||
1083 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1099 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, |
@@ -1095,8 +1111,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1095 | } else | 1111 | } else |
1096 | flock->fl_type = F_WRLCK; | 1112 | flock->fl_type = F_WRLCK; |
1097 | 1113 | ||
1098 | rc = 0; | 1114 | return 0; |
1099 | return rc; | ||
1100 | } | 1115 | } |
1101 | 1116 | ||
1102 | static void | 1117 | static void |
@@ -1254,20 +1269,26 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
1254 | } | 1269 | } |
1255 | 1270 | ||
1256 | if (lock) { | 1271 | if (lock) { |
1257 | rc = cifs_lock_add_if(cinode, flock->fl_start, length, | 1272 | struct cifsLockInfo *lock; |
1258 | type, netfid, wait_flag); | 1273 | |
1274 | lock = cifs_lock_init(flock->fl_start, length, type, netfid); | ||
1275 | if (!lock) | ||
1276 | return -ENOMEM; | ||
1277 | |||
1278 | rc = cifs_lock_add_if(cinode, lock, wait_flag); | ||
1259 | if (rc < 0) | 1279 | if (rc < 0) |
1260 | return rc; | 1280 | kfree(lock); |
1261 | else if (!rc) | 1281 | if (rc <= 0) |
1262 | goto out; | 1282 | goto out; |
1263 | 1283 | ||
1264 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, | 1284 | rc = CIFSSMBLock(xid, tcon, netfid, current->tgid, length, |
1265 | flock->fl_start, 0, 1, type, wait_flag, 0); | 1285 | flock->fl_start, 0, 1, type, wait_flag, 0); |
1266 | if (rc == 0) { | 1286 | if (rc) { |
1267 | /* For Windows locks we must store them. */ | 1287 | kfree(lock); |
1268 | rc = cifs_lock_add(cinode, length, flock->fl_start, | 1288 | goto out; |
1269 | type, netfid); | ||
1270 | } | 1289 | } |
1290 | |||
1291 | cifs_lock_add(cinode, lock); | ||
1271 | } else if (unlock) | 1292 | } else if (unlock) |
1272 | rc = cifs_unlock_range(cfile, flock, xid); | 1293 | rc = cifs_unlock_range(cfile, flock, xid); |
1273 | 1294 | ||