Author: kib
Date: Sat Feb 25 10:38:18 2017
New Revision: 314253
URL: https://svnweb.freebsd.org/changeset/base/314253

Log:
  Do not leak mount references for dying threads.
  
  Thread might create a condition for delayed SU cleanup, which creates
  a reference to the mount point in td_su, but exit without returning
  through userret(), e.g. when terminating due to single-threading or
  process exit.  In this case, td_su reference is not dropped and mount
  point cannot be freed.
  
  Handle the situation by clearing td_su also in the thread destructor
  and in exit1().  softdep_ast_cleanup() has to receive the thread as
  argument, since e.g. thread destructor is executed in different
  context.
  
  Reported and tested by:       pho
  Sponsored by: The FreeBSD Foundation
  MFC after:    2 weeks

Modified:
  head/sys/fs/nfsserver/nfs_nfsdkrpc.c
  head/sys/kern/kern_exit.c
  head/sys/kern/kern_thread.c
  head/sys/kern/subr_trap.c
  head/sys/sys/proc.h
  head/sys/sys/systm.h
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/fs/nfsserver/nfs_nfsdkrpc.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdkrpc.c        Sat Feb 25 10:32:49 2017        
(r314252)
+++ head/sys/fs/nfsserver/nfs_nfsdkrpc.c        Sat Feb 25 10:38:18 2017        
(r314253)
@@ -304,8 +304,7 @@ nfssvc_program(struct svc_req *rqst, SVC
        svc_freereq(rqst);
 
 out:
-       if (softdep_ast_cleanup != NULL)
-               softdep_ast_cleanup();
+       td_softdep_cleanup(curthread);
        NFSEXITCODE(0);
 }
 

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c   Sat Feb 25 10:32:49 2017        (r314252)
+++ head/sys/kern/kern_exit.c   Sat Feb 25 10:38:18 2017        (r314253)
@@ -207,8 +207,7 @@ exit1(struct thread *td, int rval, int s
        /*
         * Deref SU mp, since the thread does not return to userspace.
         */
-       if (softdep_ast_cleanup != NULL)
-               softdep_ast_cleanup();
+       td_softdep_cleanup(td);
 
        /*
         * MUST abort all other threads before proceeding past here.

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c Sat Feb 25 10:32:49 2017        (r314252)
+++ head/sys/kern/kern_thread.c Sat Feb 25 10:38:18 2017        (r314253)
@@ -192,6 +192,8 @@ thread_dtor(void *mem, int size, void *a
 #endif
        /* Free all OSD associated to this thread. */
        osd_thread_exit(td);
+       td_softdep_cleanup(td);
+       MPASS(td->td_su == NULL);
 
        EVENTHANDLER_INVOKE(thread_dtor, td);
        tid_free(td->td_tid);

Modified: head/sys/kern/subr_trap.c
==============================================================================
--- head/sys/kern/subr_trap.c   Sat Feb 25 10:32:49 2017        (r314252)
+++ head/sys/kern/subr_trap.c   Sat Feb 25 10:38:18 2017        (r314253)
@@ -86,7 +86,7 @@ __FBSDID("$FreeBSD$");
 
 #include <security/mac/mac_framework.h>
 
-void (*softdep_ast_cleanup)(void);
+void (*softdep_ast_cleanup)(struct thread *);
 
 /*
  * Define the code needed before returning to user mode, for trap and
@@ -128,8 +128,8 @@ userret(struct thread *td, struct trapfr
 #ifdef KTRACE
        KTRUSERRET(td);
 #endif
-       if (softdep_ast_cleanup != NULL)
-               softdep_ast_cleanup();
+       td_softdep_cleanup(td);
+       MPASS(td->td_su == NULL);
 
        /*
         * If this thread tickled GEOM, we need to wait for the giggling to

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h Sat Feb 25 10:32:49 2017        (r314252)
+++ head/sys/sys/proc.h Sat Feb 25 10:38:18 2017        (r314253)
@@ -1114,6 +1114,15 @@ td_get_sched(struct thread *td)
        return ((struct td_sched *)&td[1]);
 }
 
+extern void (*softdep_ast_cleanup)(struct thread *);
+static __inline void
+td_softdep_cleanup(struct thread *td)
+{
+
+       if (td->td_su != NULL && softdep_ast_cleanup != NULL)
+               softdep_ast_cleanup(td);
+}
+
 #endif /* _KERNEL */
 
 #endif /* !_SYS_PROC_H_ */

Modified: head/sys/sys/systm.h
==============================================================================
--- head/sys/sys/systm.h        Sat Feb 25 10:32:49 2017        (r314252)
+++ head/sys/sys/systm.h        Sat Feb 25 10:38:18 2017        (r314253)
@@ -452,8 +452,6 @@ void free_unr(struct unrhdr *uh, u_int i
 
 void   intr_prof_stack_use(struct thread *td, struct trapframe *frame);
 
-extern void (*softdep_ast_cleanup)(void);
-
 void counted_warning(unsigned *counter, const char *msg);
 
 __NULLABILITY_PRAGMA_POP

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c      Sat Feb 25 10:32:49 2017        
(r314252)
+++ head/sys/ufs/ffs/ffs_softdep.c      Sat Feb 25 10:38:18 2017        
(r314253)
@@ -902,7 +902,7 @@ static      int pagedep_find(struct pagedep_h
 static void pause_timer(void *);
 static int request_cleanup(struct mount *, int);
 static void schedule_cleanup(struct mount *);
-static void softdep_ast_cleanup_proc(void);
+static void softdep_ast_cleanup_proc(struct thread *);
 static int process_worklist_item(struct mount *, int, int);
 static void process_removes(struct vnode *);
 static void process_truncates(struct vnode *);
@@ -13445,15 +13445,13 @@ schedule_cleanup(struct mount *mp)
 }
 
 static void
-softdep_ast_cleanup_proc(void)
+softdep_ast_cleanup_proc(struct thread *td)
 {
-       struct thread *td;
        struct mount *mp;
        struct ufsmount *ump;
        int error;
        bool req;
 
-       td = curthread;
        while ((mp = td->td_su) != NULL) {
                td->td_su = NULL;
                error = vfs_busy(mp, MBF_NOWAIT);
@@ -13491,6 +13489,10 @@ softdep_ast_cleanup_proc(void)
                }
                vfs_unbusy(mp);
        }
+       if ((mp = td->td_su) != NULL) {
+               td->td_su = NULL;
+               vfs_rel(mp);
+       }
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to