diff options
| -rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 8 | ||||
| -rw-r--r-- | fs/cifs/file.c | 150 |
3 files changed, 147 insertions, 15 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c25d0636cc4f..67c26cfe160d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -374,8 +374,8 @@ extern int CIFSSMBLock(const int xid, struct cifs_tcon *tcon, | |||
| 374 | const __u32 numLock, const __u8 lockType, | 374 | const __u32 numLock, const __u8 lockType, |
| 375 | const bool waitFlag, const __u8 oplock_level); | 375 | const bool waitFlag, const __u8 oplock_level); |
| 376 | extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, | 376 | extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, |
| 377 | const __u16 smb_file_id, const int get_flag, | 377 | const __u16 smb_file_id, const __u32 netpid, |
| 378 | const __u64 len, struct file_lock *, | 378 | const int get_flag, const __u64 len, struct file_lock *, |
| 379 | const __u16 lock_type, const bool waitFlag); | 379 | const __u16 lock_type, const bool waitFlag); |
| 380 | extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon); | 380 | extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon); |
| 381 | extern int CIFSSMBEcho(struct TCP_Server_Info *server); | 381 | extern int CIFSSMBEcho(struct TCP_Server_Info *server); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4435b11c41b9..6a45a1769388 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -2393,9 +2393,9 @@ CIFSSMBLock(const int xid, struct cifs_tcon *tcon, | |||
| 2393 | 2393 | ||
| 2394 | int | 2394 | int |
| 2395 | CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, | 2395 | CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, |
| 2396 | const __u16 smb_file_id, const int get_flag, const __u64 len, | 2396 | const __u16 smb_file_id, const __u32 netpid, const int get_flag, |
| 2397 | struct file_lock *pLockData, const __u16 lock_type, | 2397 | const __u64 len, struct file_lock *pLockData, |
| 2398 | const bool waitFlag) | 2398 | const __u16 lock_type, const bool waitFlag) |
| 2399 | { | 2399 | { |
| 2400 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 2400 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
| 2401 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; | 2401 | struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; |
| @@ -2453,7 +2453,7 @@ CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, | |||
| 2453 | } else | 2453 | } else |
| 2454 | pSMB->Timeout = 0; | 2454 | pSMB->Timeout = 0; |
| 2455 | 2455 | ||
| 2456 | parm_data->pid = cpu_to_le32(current->tgid); | 2456 | parm_data->pid = cpu_to_le32(netpid); |
| 2457 | parm_data->start = cpu_to_le64(pLockData->fl_start); | 2457 | parm_data->start = cpu_to_le64(pLockData->fl_start); |
| 2458 | parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ | 2458 | parm_data->length = cpu_to_le64(len); /* normalize negative numbers */ |
| 2459 | 2459 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 34cbbee30b18..805e2bd1dfd5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -788,7 +788,42 @@ try_again: | |||
| 788 | } | 788 | } |
| 789 | 789 | ||
| 790 | static int | 790 | static int |
| 791 | cifs_push_locks(struct cifsFileInfo *cfile) | 791 | cifs_posix_lock_test(struct file *file, struct file_lock *flock) |
| 792 | { | ||
| 793 | int rc = 0; | ||
| 794 | struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); | ||
| 795 | unsigned char saved_type = flock->fl_type; | ||
| 796 | |||
| 797 | mutex_lock(&cinode->lock_mutex); | ||
| 798 | posix_test_lock(file, flock); | ||
| 799 | |||
| 800 | if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) { | ||
| 801 | flock->fl_type = saved_type; | ||
| 802 | rc = 1; | ||
| 803 | } | ||
| 804 | |||
| 805 | mutex_unlock(&cinode->lock_mutex); | ||
| 806 | return rc; | ||
| 807 | } | ||
| 808 | |||
| 809 | static int | ||
| 810 | cifs_posix_lock_set(struct file *file, struct file_lock *flock) | ||
| 811 | { | ||
| 812 | struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); | ||
| 813 | int rc; | ||
| 814 | |||
| 815 | mutex_lock(&cinode->lock_mutex); | ||
| 816 | if (!cinode->can_cache_brlcks) { | ||
| 817 | mutex_unlock(&cinode->lock_mutex); | ||
| 818 | return 1; | ||
| 819 | } | ||
| 820 | rc = posix_lock_file_wait(file, flock); | ||
| 821 | mutex_unlock(&cinode->lock_mutex); | ||
| 822 | return rc; | ||
| 823 | } | ||
| 824 | |||
| 825 | static int | ||
| 826 | cifs_push_mandatory_locks(struct cifsFileInfo *cfile) | ||
| 792 | { | 827 | { |
| 793 | int xid, rc = 0, stored_rc; | 828 | int xid, rc = 0, stored_rc; |
| 794 | struct cifsLockInfo *li, *tmp; | 829 | struct cifsLockInfo *li, *tmp; |
| @@ -820,6 +855,91 @@ cifs_push_locks(struct cifsFileInfo *cfile) | |||
| 820 | return rc; | 855 | return rc; |
| 821 | } | 856 | } |
| 822 | 857 | ||
| 858 | /* copied from fs/locks.c with a name change */ | ||
| 859 | #define cifs_for_each_lock(inode, lockp) \ | ||
| 860 | for (lockp = &inode->i_flock; *lockp != NULL; \ | ||
| 861 | lockp = &(*lockp)->fl_next) | ||
| 862 | |||
| 863 | static int | ||
| 864 | cifs_push_posix_locks(struct cifsFileInfo *cfile) | ||
| 865 | { | ||
| 866 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | ||
| 867 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
| 868 | struct file_lock *flock, **before; | ||
| 869 | struct cifsLockInfo *lck, *tmp; | ||
| 870 | int rc = 0, xid, type; | ||
| 871 | __u64 length; | ||
| 872 | struct list_head locks_to_send; | ||
| 873 | |||
| 874 | xid = GetXid(); | ||
| 875 | |||
| 876 | mutex_lock(&cinode->lock_mutex); | ||
| 877 | if (!cinode->can_cache_brlcks) { | ||
| 878 | mutex_unlock(&cinode->lock_mutex); | ||
| 879 | FreeXid(xid); | ||
| 880 | return rc; | ||
| 881 | } | ||
| 882 | |||
| 883 | INIT_LIST_HEAD(&locks_to_send); | ||
| 884 | |||
| 885 | lock_flocks(); | ||
| 886 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | ||
| 887 | flock = *before; | ||
| 888 | length = 1 + flock->fl_end - flock->fl_start; | ||
| 889 | if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) | ||
| 890 | type = CIFS_RDLCK; | ||
| 891 | else | ||
| 892 | type = CIFS_WRLCK; | ||
| 893 | |||
| 894 | lck = cifs_lock_init(length, flock->fl_start, type, | ||
| 895 | cfile->netfid); | ||
| 896 | if (!lck) { | ||
| 897 | rc = -ENOMEM; | ||
| 898 | goto send_locks; | ||
| 899 | } | ||
| 900 | lck->pid = flock->fl_pid; | ||
| 901 | |||
| 902 | list_add_tail(&lck->llist, &locks_to_send); | ||
| 903 | } | ||
| 904 | |||
| 905 | send_locks: | ||
| 906 | unlock_flocks(); | ||
| 907 | |||
| 908 | list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { | ||
| 909 | struct file_lock tmp_lock; | ||
| 910 | int stored_rc; | ||
| 911 | |||
| 912 | tmp_lock.fl_start = lck->offset; | ||
| 913 | stored_rc = CIFSSMBPosixLock(xid, tcon, lck->netfid, lck->pid, | ||
| 914 | 0, lck->length, &tmp_lock, | ||
| 915 | lck->type, 0); | ||
| 916 | if (stored_rc) | ||
| 917 | rc = stored_rc; | ||
| 918 | list_del(&lck->llist); | ||
| 919 | kfree(lck); | ||
| 920 | } | ||
| 921 | |||
| 922 | cinode->can_cache_brlcks = false; | ||
| 923 | mutex_unlock(&cinode->lock_mutex); | ||
| 924 | |||
| 925 | FreeXid(xid); | ||
| 926 | return rc; | ||
| 927 | } | ||
| 928 | |||
| 929 | static int | ||
| 930 | cifs_push_locks(struct cifsFileInfo *cfile) | ||
| 931 | { | ||
| 932 | struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); | ||
| 933 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
| 934 | |||
| 935 | if ((tcon->ses->capabilities & CAP_UNIX) && | ||
| 936 | (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && | ||
| 937 | ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) | ||
| 938 | return cifs_push_posix_locks(cfile); | ||
| 939 | |||
| 940 | return cifs_push_mandatory_locks(cfile); | ||
| 941 | } | ||
| 942 | |||
| 823 | static void | 943 | static void |
| 824 | cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, | 944 | cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, |
| 825 | bool *wait_flag) | 945 | bool *wait_flag) |
| @@ -865,24 +985,30 @@ cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, | |||
| 865 | } | 985 | } |
| 866 | 986 | ||
| 867 | static int | 987 | static int |
| 868 | cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type, | 988 | cifs_getlk(struct file *file, struct file_lock *flock, __u8 type, |
| 869 | bool wait_flag, bool posix_lck, int xid) | 989 | bool wait_flag, bool posix_lck, int xid) |
| 870 | { | 990 | { |
| 871 | int rc = 0; | 991 | int rc = 0; |
| 872 | __u64 length = 1 + flock->fl_end - flock->fl_start; | 992 | __u64 length = 1 + flock->fl_end - flock->fl_start; |
| 993 | struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; | ||
| 994 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
| 873 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); | 995 | struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); |
| 874 | __u16 netfid = cfile->netfid; | 996 | __u16 netfid = cfile->netfid; |
| 875 | struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); | ||
| 876 | 997 | ||
| 877 | if (posix_lck) { | 998 | if (posix_lck) { |
| 878 | int posix_lock_type; | 999 | int posix_lock_type; |
| 1000 | |||
| 1001 | rc = cifs_posix_lock_test(file, flock); | ||
| 1002 | if (!rc) | ||
| 1003 | return rc; | ||
| 1004 | |||
| 879 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1005 | if (type & LOCKING_ANDX_SHARED_LOCK) |
| 880 | posix_lock_type = CIFS_RDLCK; | 1006 | posix_lock_type = CIFS_RDLCK; |
| 881 | else | 1007 | else |
| 882 | posix_lock_type = CIFS_WRLCK; | 1008 | posix_lock_type = CIFS_WRLCK; |
| 883 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */, | 1009 | rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid, |
| 884 | length, flock, posix_lock_type, | 1010 | 1 /* get */, length, flock, |
| 885 | wait_flag); | 1011 | posix_lock_type, wait_flag); |
| 886 | return rc; | 1012 | return rc; |
| 887 | } | 1013 | } |
| 888 | 1014 | ||
| @@ -944,6 +1070,11 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
| 944 | 1070 | ||
| 945 | if (posix_lck) { | 1071 | if (posix_lck) { |
| 946 | int posix_lock_type; | 1072 | int posix_lock_type; |
| 1073 | |||
| 1074 | rc = cifs_posix_lock_set(file, flock); | ||
| 1075 | if (!rc || rc < 0) | ||
| 1076 | return rc; | ||
| 1077 | |||
| 947 | if (type & LOCKING_ANDX_SHARED_LOCK) | 1078 | if (type & LOCKING_ANDX_SHARED_LOCK) |
| 948 | posix_lock_type = CIFS_RDLCK; | 1079 | posix_lock_type = CIFS_RDLCK; |
| 949 | else | 1080 | else |
| @@ -952,8 +1083,9 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u8 type, | |||
| 952 | if (unlock == 1) | 1083 | if (unlock == 1) |
| 953 | posix_lock_type = CIFS_UNLCK; | 1084 | posix_lock_type = CIFS_UNLCK; |
| 954 | 1085 | ||
| 955 | rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */, length, | 1086 | rc = CIFSSMBPosixLock(xid, tcon, netfid, current->tgid, |
| 956 | flock, posix_lock_type, wait_flag); | 1087 | 0 /* set */, length, flock, |
| 1088 | posix_lock_type, wait_flag); | ||
| 957 | goto out; | 1089 | goto out; |
| 958 | } | 1090 | } |
| 959 | 1091 | ||
| @@ -1052,7 +1184,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) | |||
| 1052 | * negative length which we can not accept over the wire. | 1184 | * negative length which we can not accept over the wire. |
| 1053 | */ | 1185 | */ |
| 1054 | if (IS_GETLK(cmd)) { | 1186 | if (IS_GETLK(cmd)) { |
| 1055 | rc = cifs_getlk(cfile, flock, type, wait_flag, posix_lck, xid); | 1187 | rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid); |
| 1056 | FreeXid(xid); | 1188 | FreeXid(xid); |
| 1057 | return rc; | 1189 | return rc; |
| 1058 | } | 1190 | } |
