From: Dan Kegel <dank@kegel.com>
To: Vitaly Luban <vitaly@luban.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: spin_lock_bh() usage check, please (was: [PATCH][RFC] Signal-per-fd for RT signals)
Date: Sat, 15 Sep 2001 05:59:19 -0700 [thread overview]
Message-ID: <3BA350A7.7D39FC23@kegel.com> (raw)
In-Reply-To: <3BA2AFFF.C7B8C4DF@kegel.com> <3BA2E144.FB0E5D55@luban.org> <3BA2E99A.1134E382@kegel.com>
I'm playing with a patch that collapses duplicate sigio signals.
It refers to task->files during signal generation,
so it crashes on a uniprocessor system when an interrupt that
causes a sigio comes in while the process was busy expanding its
file table, to wit:
> <send_signal+69/160> <==== crash on wild pointer here
> <deliver_signal+17/80>
> <send_sig_info+86/b0>
> <send_sigio_to_task+c5/e0>
> <ip_queue_xmit+334/470>
> <tcp_rcv_established+79e/7e0>
> <tcp_v4_send_check+6e/b0>
> <send_sigio+58/b0>
> <__kill_fasync+59/70>
> <sock_wake_async+72/80>
> <sock_def_readable+5d/70>
> <tcp_rcv_established+399/7e0>
> <tcp_v4_do_rcv+3b/120>
> <tcp_v4_rcv+3e4/660>
> <ip_local_deliver+fa/170>
> <ip_rcv+304/380>
> <tulip_interrupt+618/7d0>
> <net_rx_action+17b/290>
> <net_tx_action+62/140>
> <do_softirq+7b/e0>
> <do_IRQ+dd/f0>
> <ret_from_intr+0/7>
> <vfs_rename_other+28/2b0>
> <expand_fd_array+d6/160>
> <get_unused_fd+f2/160>
> <sock_map_fd+c/1c0>
> <sock_create+f3/120>
> <sys_socket+2d/50>
> <sys_socketcall+62/200>
> <system_call+33/38>
Documentation/DocBook/kernel-locking seems to say spin_lock_bh()
is the way to address conflicts like this between a softirq and
the process.
The code referring to task->files is sprinkled into kernel/signal.c
by the patch, in routines where task->sigmask_lock is already
acquired with spin_lock_irqsave() or spin_lock_irq() before entry.
Question: is it safe to acquire task->files->file_lock with spin_lock_bh()
inside these routines, or am I risking deadlock? Is it an issue that
I might be holding the lock while traversing a list thousands of
entries long? For example, is adding file_lock locks to rm_sig_from_queue() as
follows safe, efficient, and proper?
/*
* Remove signal sig from t->pending.
* Returns 1 if sig was found.
*
* All callers must be holding t->sigmask_lock.
*/
static int rm_sig_from_queue(int sig, struct task_struct *t)
{
struct sigqueue *q, **pp;
struct sigpending *s = &t->pending;
struct files_struct *files = t->files;
if (!sigismember(&s->signal, sig))
return 0;
sigdelset(&s->signal, sig);
pp = &s->head;
if (files)
spin_lock_bh(files->file_lock); /* ??? */
while ((q = *pp) != NULL) {
if (q->info.si_signo == sig) {
/* Must clear f_revents for FASYNC sigs. dank 9/2001 */
struct file *filp;
if (files
&& (q->info.si_fd < files->max_fds)
&& ((filp = files->fd[ q->info.si_fd ]) != 0)
&& (filp->f_flags & FASYNC)
&& (filp->f_owner.signum == sig))
filp->f_revents = 0;
if ((*pp = q->next) == NULL)
s->tail = pp;
kmem_cache_free(sigqueue_cachep,q);
atomic_dec(&nr_queued_signals);
continue;
}
pp = &q->next;
}
if (files)
spin_unlock_bh(files->file_lock); /* ??? */
return 1;
}
Thanks,
Dan
p.s. The bug was introduced by Luban's one-signal-per-fd patch; I ran into
it while running my variant of his patch, http://www.kegel.com/linux/onefd-dank.patch
My variant makes the following changes:
* it fixes an oops related to 'task->files' being null during SIGINT
* it fixes two oopses related to signal queue overflow
* it keeps poll data, not pointers, in struct file. This saves space
and makes the consequence of screwing up less severe.
* it overloads an existing struct file field to avoid the space penalty;
it doesn't bloat struct file.
* it assumes that it's better to keep the kernel uncluttered, so it
changes the meaning of siginfo.si_code rather than introduces new ioctl's.
(I hear the Austin draft of the Posix single unix spec is deleting all mention
of SIGIO, so it looks like we're free to 'improve' that interface freely
once Austin becomes the law of the land :-)
I'm perfectly willing to write patches for phhttpd and x15 to use the
new interface in the unlikely event that everyone agrees my interface change
is good.
next prev parent reply other threads:[~2001-09-15 12:59 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-09-15 1:33 [PATCH][RFC] Signal-per-fd for RT signals Dan Kegel
2001-09-15 5:04 ` Vitaly Luban
2001-09-15 5:39 ` Dan Kegel
2001-09-15 12:59 ` Dan Kegel [this message]
2001-09-15 21:20 ` spin_lock_bh() usage check, please (was: [PATCH][RFC] Signal-per-fd for RT signals) Vitaly Luban
2001-09-15 22:07 ` Dan Kegel
2001-09-16 2:35 ` [PATCH][RFC] Signal-per-fd for RT signals Vitaly Luban
2001-09-16 3:51 ` Dan Kegel
2001-09-22 23:30 ` [PATCH][RFC] Signal-per-fd for RT signals; write_lock_bh(file_lock)? Dan Kegel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3BA350A7.7D39FC23@kegel.com \
--to=dank@kegel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=vitaly@luban.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox