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
This commit is contained in:
parent
d360b49b1d
commit
aca4bb9112
@ -304,8 +304,7 @@ nfssvc_program(struct svc_req *rqst, SVCXPRT *xprt)
|
||||
svc_freereq(rqst);
|
||||
|
||||
out:
|
||||
if (softdep_ast_cleanup != NULL)
|
||||
softdep_ast_cleanup();
|
||||
td_softdep_cleanup(curthread);
|
||||
NFSEXITCODE(0);
|
||||
}
|
||||
|
||||
|
@ -207,8 +207,7 @@ exit1(struct thread *td, int rval, int signo)
|
||||
/*
|
||||
* 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.
|
||||
|
@ -192,6 +192,8 @@ thread_dtor(void *mem, int size, void *arg)
|
||||
#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);
|
||||
|
@ -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 trapframe *frame)
|
||||
#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
|
||||
|
@ -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_ */
|
||||
|
@ -452,8 +452,6 @@ void free_unr(struct unrhdr *uh, u_int item);
|
||||
|
||||
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
|
||||
|
@ -902,7 +902,7 @@ static int pagedep_find(struct pagedep_hashhead *, ino_t, ufs_lbn_t,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user