diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2011-10-22 07:33:30 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2011-10-24 13:29:27 -0400 |
commit | 4f6bcec910d45e4f46b1514977caa529bc69e645 (patch) | |
tree | 37469bfcd1216ea98f0a947b997ce65e1b5aa3b0 /fs/cifs | |
parent | 85160e03a79e0d7f9082e61f6a784abc6f402701 (diff) |
CIFS: Implement caching mechanism for posix brlocks
to handle all lock requests on the client in an exclusive oplock case.
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-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 | } |