aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2011-10-22 07:33:30 -0400
committerSteve French <smfrench@gmail.com>2011-10-24 13:29:27 -0400
commit4f6bcec910d45e4f46b1514977caa529bc69e645 (patch)
tree37469bfcd1216ea98f0a947b997ce65e1b5aa3b0 /fs/cifs
parent85160e03a79e0d7f9082e61f6a784abc6f402701 (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.h4
-rw-r--r--fs/cifs/cifssmb.c8
-rw-r--r--fs/cifs/file.c150
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);
376extern int CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, 376extern 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);
380extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon); 380extern int CIFSSMBTDis(const int xid, struct cifs_tcon *tcon);
381extern int CIFSSMBEcho(struct TCP_Server_Info *server); 381extern 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
2394int 2394int
2395CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon, 2395CIFSSMBPosixLock(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
790static int 790static int
791cifs_push_locks(struct cifsFileInfo *cfile) 791cifs_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
809static int
810cifs_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
825static int
826cifs_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
863static int
864cifs_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
905send_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
929static int
930cifs_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
823static void 943static void
824cifs_read_flock(struct file_lock *flock, __u8 *type, int *lock, int *unlock, 944cifs_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
867static int 987static int
868cifs_getlk(struct cifsFileInfo *cfile, struct file_lock *flock, __u8 type, 988cifs_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 }