@@ -459,6 +459,7 @@ cifs_down_write(struct rw_semaphore *sem)
459459}
460460
461461static void cifsFileInfo_put_work (struct work_struct * work );
462+ void serverclose_work (struct work_struct * work );
462463
463464struct cifsFileInfo * cifs_new_fileinfo (struct cifs_fid * fid , struct file * file ,
464465 struct tcon_link * tlink , __u32 oplock ,
@@ -505,6 +506,7 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
505506 cfile -> tlink = cifs_get_tlink (tlink );
506507 INIT_WORK (& cfile -> oplock_break , cifs_oplock_break );
507508 INIT_WORK (& cfile -> put , cifsFileInfo_put_work );
509+ INIT_WORK (& cfile -> serverclose , serverclose_work );
508510 INIT_DELAYED_WORK (& cfile -> deferred , smb2_deferred_work_close );
509511 mutex_init (& cfile -> fh_mutex );
510512 spin_lock_init (& cfile -> file_info_lock );
@@ -596,6 +598,40 @@ static void cifsFileInfo_put_work(struct work_struct *work)
596598 cifsFileInfo_put_final (cifs_file );
597599}
598600
601+ void serverclose_work (struct work_struct * work )
602+ {
603+ struct cifsFileInfo * cifs_file = container_of (work ,
604+ struct cifsFileInfo , serverclose );
605+
606+ struct cifs_tcon * tcon = tlink_tcon (cifs_file -> tlink );
607+
608+ struct TCP_Server_Info * server = tcon -> ses -> server ;
609+ int rc = 0 ;
610+ int retries = 0 ;
611+ int MAX_RETRIES = 4 ;
612+
613+ do {
614+ if (server -> ops -> close_getattr )
615+ rc = server -> ops -> close_getattr (0 , tcon , cifs_file );
616+ else if (server -> ops -> close )
617+ rc = server -> ops -> close (0 , tcon , & cifs_file -> fid );
618+
619+ if (rc == - EBUSY || rc == - EAGAIN ) {
620+ retries ++ ;
621+ msleep (250 );
622+ }
623+ } while ((rc == - EBUSY || rc == - EAGAIN ) && (retries < MAX_RETRIES )
624+ );
625+
626+ if (retries == MAX_RETRIES )
627+ pr_warn ("Serverclose failed %d times, giving up\n" , MAX_RETRIES );
628+
629+ if (cifs_file -> offload )
630+ queue_work (fileinfo_put_wq , & cifs_file -> put );
631+ else
632+ cifsFileInfo_put_final (cifs_file );
633+ }
634+
599635/**
600636 * cifsFileInfo_put - release a reference of file priv data
601637 *
@@ -636,10 +672,13 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
636672 struct cifs_fid fid = {};
637673 struct cifs_pending_open open ;
638674 bool oplock_break_cancelled ;
675+ bool serverclose_offloaded = false;
639676
640677 spin_lock (& tcon -> open_file_lock );
641678 spin_lock (& cifsi -> open_file_lock );
642679 spin_lock (& cifs_file -> file_info_lock );
680+
681+ cifs_file -> offload = offload ;
643682 if (-- cifs_file -> count > 0 ) {
644683 spin_unlock (& cifs_file -> file_info_lock );
645684 spin_unlock (& cifsi -> open_file_lock );
@@ -681,24 +720,36 @@ void _cifsFileInfo_put(struct cifsFileInfo *cifs_file,
681720 if (!tcon -> need_reconnect && !cifs_file -> invalidHandle ) {
682721 struct TCP_Server_Info * server = tcon -> ses -> server ;
683722 unsigned int xid ;
723+ int rc = 0 ;
684724
685725 xid = get_xid ();
686726 if (server -> ops -> close_getattr )
687- server -> ops -> close_getattr (xid , tcon , cifs_file );
727+ rc = server -> ops -> close_getattr (xid , tcon , cifs_file );
688728 else if (server -> ops -> close )
689- server -> ops -> close (xid , tcon , & cifs_file -> fid );
729+ rc = server -> ops -> close (xid , tcon , & cifs_file -> fid );
690730 _free_xid (xid );
731+
732+ if (rc == - EBUSY || rc == - EAGAIN ) {
733+ // Server close failed, hence offloading it as an async op
734+ queue_work (serverclose_wq , & cifs_file -> serverclose );
735+ serverclose_offloaded = true;
736+ }
691737 }
692738
693739 if (oplock_break_cancelled )
694740 cifs_done_oplock_break (cifsi );
695741
696742 cifs_del_pending_open (& open );
697743
698- if (offload )
699- queue_work (fileinfo_put_wq , & cifs_file -> put );
700- else
701- cifsFileInfo_put_final (cifs_file );
744+ // if serverclose has been offloaded to wq (on failure), it will
745+ // handle offloading put as well. If serverclose not offloaded,
746+ // we need to handle offloading put here.
747+ if (!serverclose_offloaded ) {
748+ if (offload )
749+ queue_work (fileinfo_put_wq , & cifs_file -> put );
750+ else
751+ cifsFileInfo_put_final (cifs_file );
752+ }
702753}
703754
704755int cifs_open (struct inode * inode , struct file * file )
0 commit comments