diff --git a/src/afs/LINUX/osi_misc.c b/src/afs/LINUX/osi_misc.c index be69846614..773ca19e43 100644 --- a/src/afs/LINUX/osi_misc.c +++ b/src/afs/LINUX/osi_misc.c @@ -186,3 +186,20 @@ afs_start_thread(void (*proc)(void), char *name, int needs_glock) kthread_run(afs_thread_wrapper, proc, "%s", name); } } + +/* + * Check for a pending fatal signal + * Return 1 if a fatal signal is pending, otherwise return 0; + */ +int +osi_kill_pending(void) +{ +#if defined(HAVE_LINUX_FATAL_SIGNAL_PENDING) + if (fatal_signal_pending(current)) { + return 1; + } +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) +# error fatal_signal_pending not available, but it should be +#endif + return 0; +} \ No newline at end of file diff --git a/src/afs/LINUX/osi_prototypes.h b/src/afs/LINUX/osi_prototypes.h index 2ed0543397..a628f87137 100644 --- a/src/afs/LINUX/osi_prototypes.h +++ b/src/afs/LINUX/osi_prototypes.h @@ -51,6 +51,7 @@ extern int osi_lookupname(char *aname, uio_seg_t seg, int followlink, extern int osi_abspath(char *aname, char *buf, int buflen, int followlink, char **pathp); extern void afs_start_thread(void (*proc)(void), char *name, int needs_glock); +extern int osi_kill_pending(void); /* osi_probe.c */ extern void *osi_find_syscall_table(int which); diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index c6c3bfe39b..1da52c4879 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1305,17 +1305,19 @@ parent_vcache_dv(struct inode *inode, cred_t *credp) } return hgetlo(pvcp->f.m.DataVersion); } - +/* + * Make sure we don't accidentally yield an ENOENT that's caused by internal + * errors instead of the requested filename actually not existing. This has been + * possible in the past because Linux returns errors for some low-level routines + * when the process is dying. Incorrect ENOENT errors can cause bogus negative + * dentries to exist, which is very bad, so make sure that doesn't happen. + */ static inline int filter_enoent(int code) { -#ifdef HAVE_LINUX_FATAL_SIGNAL_PENDING - if (code == ENOENT && fatal_signal_pending(current)) { - return EINTR; + if (code == ENOENT && afs_kill_pending()) { + return EINTR; } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) -# error fatal_signal_pending not available, but it should be -#endif return code; } diff --git a/src/afs/afs_analyze.c b/src/afs/afs_analyze.c index 88c6a178a5..b83a55d199 100644 --- a/src/afs/afs_analyze.c +++ b/src/afs/afs_analyze.c @@ -383,6 +383,38 @@ afs_PrintServerErrors(struct vrequest *areq, struct VenusFid *afid) afs_warnuser("%s\n", term); } +/*! + * \brief + * Determine if the current process is pending termination and will be + * killed when returning to userspace. + * + * \retval 1 if the process is dying + * \retval 0 if the process is not dying + * + * \note + * If the process is pending termination, there is no need to retry requests + * or wait for a server to return data, etc. as the process is going to die + * before it can process any data. However we will still need to ensure that + * we don't corrupt any locks, cache, etc., or any data that persists in other + * processes. + * + * \note + * On some platforms (Linux), a process will not sleep if it is pending + * termination. If we can detect that the process will be killed, it is better + * to not retry the requests, etc. to avoid spinning the CPU. + */ +int +afs_kill_pending(void) +{ +#if defined(UKERNEL) + return 0; +#elif defined(AFS_LINUX_ENV) + return osi_kill_pending(); +#else + return 0; +#endif /* UKERNEL */ +} + /*! * \brief * Analyze the outcome of an RPC operation, taking whatever support diff --git a/src/afs/afs_prototypes.h b/src/afs/afs_prototypes.h index 3657c669df..1d89337169 100644 --- a/src/afs/afs_prototypes.h +++ b/src/afs/afs_prototypes.h @@ -11,9 +11,10 @@ #define _AFS_PROTOTYPES_H_ /* afs_analyze.c */ +extern int afs_kill_pending(void); extern int afs_Analyze(struct afs_conn *aconn, struct rx_connection *rxconn, - afs_int32 acode, struct VenusFid *afid, - struct vrequest *areq, + afs_int32 acode, struct VenusFid *afid, + struct vrequest *areq, int op, afs_int32 locktype, struct cell *cellp); /* afs_axscache.c */