55 *
66 * Copyright (C) International Business Machines Corp., 2002,2003
77 * Author(s): Steve French (sfrench@us.ibm.com)
8+ * Jeremy Allison (jra@samba.org)
89 *
910 * This library is free software; you can redistribute it and/or modify
1011 * it under the terms of the GNU Lesser General Public License as published
@@ -47,6 +48,8 @@ static inline struct cifsFileInfo *cifs_init_private(
4748 private_data -> netfid = netfid ;
4849 private_data -> pid = current -> tgid ;
4950 init_MUTEX (& private_data -> fh_sem );
51+ init_MUTEX (& private_data -> lock_sem );
52+ INIT_LIST_HEAD (& private_data -> llist );
5053 private_data -> pfile = file ; /* needed for writepage */
5154 private_data -> pInode = inode ;
5255 private_data -> invalidHandle = FALSE;
@@ -473,6 +476,8 @@ int cifs_close(struct inode *inode, struct file *file)
473476 cifs_sb = CIFS_SB (inode -> i_sb );
474477 pTcon = cifs_sb -> tcon ;
475478 if (pSMBFile ) {
479+ struct cifsLockInfo * li , * tmp ;
480+
476481 pSMBFile -> closePend = TRUE;
477482 if (pTcon ) {
478483 /* no sense reconnecting to close a file that is
@@ -496,6 +501,16 @@ int cifs_close(struct inode *inode, struct file *file)
496501 pSMBFile -> netfid );
497502 }
498503 }
504+
505+ /* Delete any outstanding lock records.
506+ We'll lose them when the file is closed anyway. */
507+ down (& pSMBFile -> lock_sem );
508+ list_for_each_entry_safe (li , tmp , & pSMBFile -> llist , llist ) {
509+ list_del (& li -> llist );
510+ kfree (li );
511+ }
512+ up (& pSMBFile -> lock_sem );
513+
499514 write_lock (& GlobalSMBSeslock );
500515 list_del (& pSMBFile -> flist );
501516 list_del (& pSMBFile -> tlist );
@@ -570,6 +585,21 @@ int cifs_closedir(struct inode *inode, struct file *file)
570585 return rc ;
571586}
572587
588+ static int store_file_lock (struct cifsFileInfo * fid , __u64 len ,
589+ __u64 offset , __u8 lockType )
590+ {
591+ struct cifsLockInfo * li = kmalloc (sizeof (struct cifsLockInfo ), GFP_KERNEL );
592+ if (li == NULL )
593+ return - ENOMEM ;
594+ li -> offset = offset ;
595+ li -> length = len ;
596+ li -> type = lockType ;
597+ down (& fid -> lock_sem );
598+ list_add (& li -> llist , & fid -> llist );
599+ up (& fid -> lock_sem );
600+ return 0 ;
601+ }
602+
573603int cifs_lock (struct file * file , int cmd , struct file_lock * pfLock )
574604{
575605 int rc , xid ;
@@ -581,6 +611,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
581611 struct cifsTconInfo * pTcon ;
582612 __u16 netfid ;
583613 __u8 lockType = LOCKING_ANDX_LARGE_FILES ;
614+ int posix_locking ;
584615
585616 length = 1 + pfLock -> fl_end - pfLock -> fl_start ;
586617 rc = - EACCES ;
@@ -639,14 +670,14 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
639670 }
640671 netfid = ((struct cifsFileInfo * )file -> private_data )-> netfid ;
641672
673+ posix_locking = (cifs_sb -> tcon -> ses -> capabilities & CAP_UNIX ) &&
674+ (CIFS_UNIX_FCNTL_CAP & le64_to_cpu (cifs_sb -> tcon -> fsUnixInfo .Capability ));
642675
643676 /* BB add code here to normalize offset and length to
644677 account for negative length which we can not accept over the
645678 wire */
646679 if (IS_GETLK (cmd )) {
647- if ((cifs_sb -> tcon -> ses -> capabilities & CAP_UNIX ) &&
648- (CIFS_UNIX_FCNTL_CAP &
649- le64_to_cpu (cifs_sb -> tcon -> fsUnixInfo .Capability ))) {
680+ if (posix_locking ) {
650681 int posix_lock_type ;
651682 if (lockType & LOCKING_ANDX_SHARED_LOCK )
652683 posix_lock_type = CIFS_RDLCK ;
@@ -682,9 +713,15 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
682713 FreeXid (xid );
683714 return rc ;
684715 }
685- if ((cifs_sb -> tcon -> ses -> capabilities & CAP_UNIX ) &&
686- (CIFS_UNIX_FCNTL_CAP &
687- le64_to_cpu (cifs_sb -> tcon -> fsUnixInfo .Capability ))) {
716+
717+ if (!numLock && !numUnlock ) {
718+ /* if no lock or unlock then nothing
719+ to do since we do not know what it is */
720+ FreeXid (xid );
721+ return - EOPNOTSUPP ;
722+ }
723+
724+ if (posix_locking ) {
688725 int posix_lock_type ;
689726 if (lockType & LOCKING_ANDX_SHARED_LOCK )
690727 posix_lock_type = CIFS_RDLCK ;
@@ -693,18 +730,46 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
693730
694731 if (numUnlock == 1 )
695732 posix_lock_type = CIFS_UNLCK ;
696- else if (numLock == 0 ) {
697- /* if no lock or unlock then nothing
698- to do since we do not know what it is */
699- FreeXid (xid );
700- return - EOPNOTSUPP ;
701- }
733+
702734 rc = CIFSSMBPosixLock (xid , pTcon , netfid , 0 /* set */ ,
703735 length , pfLock ,
704736 posix_lock_type , wait_flag );
705- } else
706- rc = CIFSSMBLock (xid , pTcon , netfid , length , pfLock -> fl_start ,
707- numUnlock , numLock , lockType , wait_flag );
737+ } else {
738+ struct cifsFileInfo * fid = (struct cifsFileInfo * )file -> private_data ;
739+
740+ if (numLock ) {
741+ rc = CIFSSMBLock (xid , pTcon , netfid , length , pfLock -> fl_start ,
742+ 0 , numLock , lockType , wait_flag );
743+
744+ if (rc == 0 ) {
745+ /* For Windows locks we must store them. */
746+ rc = store_file_lock (fid , length ,
747+ pfLock -> fl_start , lockType );
748+ }
749+ } else if (numUnlock ) {
750+ /* For each stored lock that this unlock overlaps
751+ completely, unlock it. */
752+ int stored_rc = 0 ;
753+ struct cifsLockInfo * li , * tmp ;
754+
755+ down (& fid -> lock_sem );
756+ list_for_each_entry_safe (li , tmp , & fid -> llist , llist ) {
757+ if (pfLock -> fl_start <= li -> offset &&
758+ length >= li -> length ) {
759+ stored_rc = CIFSSMBLock (xid , pTcon , netfid ,
760+ li -> length , li -> offset ,
761+ 1 , 0 , li -> type , FALSE);
762+ if (stored_rc )
763+ rc = stored_rc ;
764+
765+ list_del (& li -> llist );
766+ kfree (li );
767+ }
768+ }
769+ up (& fid -> lock_sem );
770+ }
771+ }
772+
708773 if (pfLock -> fl_flags & FL_POSIX )
709774 posix_lock_file_wait (file , pfLock );
710775 FreeXid (xid );
0 commit comments