Commit 32735425 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linux-input.bkbits.net/linux-input

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 26c69294 3197f480
...@@ -673,31 +673,22 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio) ...@@ -673,31 +673,22 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio)
seg_size = nr_phys_segs = nr_hw_segs = 0; seg_size = nr_phys_segs = nr_hw_segs = 0;
bio_for_each_segment(bv, bio, i) { bio_for_each_segment(bv, bio, i) {
if (bvprv && cluster) { if (bvprv && cluster) {
int phys, seg; if (seg_size + bv->bv_len > q->max_segment_size)
if (seg_size + bv->bv_len > q->max_segment_size) {
nr_phys_segs++;
goto new_segment; goto new_segment;
} if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
phys = BIOVEC_PHYS_MERGEABLE(bvprv, bv);
seg = BIOVEC_SEG_BOUNDARY(q, bvprv, bv);
if (!phys || !seg)
nr_phys_segs++;
if (!seg)
goto new_segment; goto new_segment;
if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
if (!BIOVEC_VIRT_MERGEABLE(bvprv, bv))
goto new_segment; goto new_segment;
seg_size += bv->bv_len; seg_size += bv->bv_len;
bvprv = bv; bvprv = bv;
continue; continue;
} else {
nr_phys_segs++;
} }
new_segment: new_segment:
nr_hw_segs++; if (!bvprv || !BIOVEC_VIRT_MERGEABLE(bvprv, bv))
nr_hw_segs++;
nr_phys_segs++;
bvprv = bv; bvprv = bv;
seg_size = bv->bv_len; seg_size = bv->bv_len;
} }
......
...@@ -42,47 +42,47 @@ ...@@ -42,47 +42,47 @@
#define MAX_PROTOS 32 #define MAX_PROTOS 32
static struct pi_protocol *protocols[MAX_PROTOS]; static struct pi_protocol *protocols[MAX_PROTOS];
static spinlock_t pi_spinlock = SPIN_LOCK_UNLOCKED; static spinlock_t pi_spinlock = SPIN_LOCK_UNLOCKED;
void pi_write_regr( PIA *pi, int cont, int regr, int val) void pi_write_regr(PIA * pi, int cont, int regr, int val)
{
{ pi->proto->write_regr(pi,cont,regr,val); pi->proto->write_regr(pi, cont, regr, val);
} }
EXPORT_SYMBOL(pi_write_regr); EXPORT_SYMBOL(pi_write_regr);
int pi_read_regr( PIA *pi, int cont, int regr) int pi_read_regr(PIA * pi, int cont, int regr)
{
{ return pi->proto->read_regr(pi,cont,regr); return pi->proto->read_regr(pi, cont, regr);
} }
EXPORT_SYMBOL(pi_read_regr); EXPORT_SYMBOL(pi_read_regr);
void pi_write_block( PIA *pi, char * buf, int count) void pi_write_block(PIA * pi, char *buf, int count)
{
{ pi->proto->write_block(pi,buf,count); pi->proto->write_block(pi, buf, count);
} }
EXPORT_SYMBOL(pi_write_block); EXPORT_SYMBOL(pi_write_block);
void pi_read_block( PIA *pi, char * buf, int count) void pi_read_block(PIA * pi, char *buf, int count)
{
{ pi->proto->read_block(pi,buf,count); pi->proto->read_block(pi, buf, count);
} }
EXPORT_SYMBOL(pi_read_block); EXPORT_SYMBOL(pi_read_block);
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
static void pi_wake_up( void *p) static void pi_wake_up(void *p)
{
{ PIA *pi = (PIA *) p; PIA *pi = (PIA *) p;
unsigned long flags; unsigned long flags;
void (*cont)(void) = NULL; void (*cont) (void) = NULL;
spin_lock_irqsave(&pi_spinlock,flags); spin_lock_irqsave(&pi_spinlock, flags);
if (pi->claim_cont && !parport_claim(pi->pardev)) { if (pi->claim_cont && !parport_claim(pi->pardev)) {
cont = pi->claim_cont; cont = pi->claim_cont;
...@@ -90,95 +90,91 @@ static void pi_wake_up( void *p) ...@@ -90,95 +90,91 @@ static void pi_wake_up( void *p)
pi->claimed = 1; pi->claimed = 1;
} }
spin_unlock_irqrestore(&pi_spinlock,flags); spin_unlock_irqrestore(&pi_spinlock, flags);
wake_up(&(pi->parq)); wake_up(&(pi->parq));
if (cont) cont(); if (cont)
cont();
} }
#endif #endif
void pi_do_claimed( PIA *pi, void(*cont)(void)) void pi_do_claimed(PIA * pi, void (*cont) (void))
{
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
unsigned long flags;
{ unsigned long flags; spin_lock_irqsave(&pi_spinlock, flags);
spin_lock_irqsave(&pi_spinlock,flags);
if (!pi->pardev || !parport_claim(pi->pardev)) { if (pi->pardev && parport_claim(pi->pardev)) {
pi->claimed = 1;
spin_unlock_irqrestore(&pi_spinlock,flags);
cont();
} else {
pi->claim_cont = cont; pi->claim_cont = cont;
spin_unlock_irqrestore(&pi_spinlock,flags); spin_unlock_irqrestore(&pi_spinlock, flags);
return;
} }
pi->claimed = 1;
spin_unlock_irqrestore(&pi_spinlock, flags);
#endif
cont();
} }
#else
{ cont();
}
#endif
EXPORT_SYMBOL(pi_do_claimed); EXPORT_SYMBOL(pi_do_claimed);
static void pi_claim( PIA *pi) static void pi_claim(PIA * pi)
{
{ if (pi->claimed) return; if (pi->claimed)
return;
pi->claimed = 1; pi->claimed = 1;
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
if (pi->pardev) if (pi->pardev)
wait_event (pi->parq, wait_event(pi->parq,
!parport_claim ((struct pardevice *)pi->pardev)); !parport_claim((struct pardevice *) pi->pardev));
#endif #endif
} }
static void pi_unclaim( PIA *pi) static void pi_unclaim(PIA * pi)
{
{ pi->claimed = 0; pi->claimed = 0;
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
if (pi->pardev) parport_release((struct pardevice *)(pi->pardev)); if (pi->pardev)
#endif parport_release((struct pardevice *) (pi->pardev));
#endif
} }
void pi_connect( PIA *pi) void pi_connect(PIA * pi)
{
{ pi_claim(pi); pi_claim(pi);
pi->proto->connect(pi); pi->proto->connect(pi);
} }
EXPORT_SYMBOL(pi_connect); EXPORT_SYMBOL(pi_connect);
void pi_disconnect( PIA *pi) void pi_disconnect(PIA * pi)
{
{ pi->proto->disconnect(pi); pi->proto->disconnect(pi);
pi_unclaim(pi); pi_unclaim(pi);
} }
EXPORT_SYMBOL(pi_disconnect); EXPORT_SYMBOL(pi_disconnect);
static void pi_unregister_parport( PIA *pi) static void pi_unregister_parport(PIA * pi)
{ {
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
if (pi->pardev) { if (pi->pardev) {
parport_unregister_device((struct pardevice *)(pi->pardev)); parport_unregister_device((struct pardevice *) (pi->pardev));
pi->pardev = NULL; pi->pardev = NULL;
} }
#endif #endif
} }
void pi_release( PIA *pi) void pi_release(PIA * pi)
{
{ pi_unregister_parport(pi); pi_unregister_parport(pi);
#ifndef CONFIG_PARPORT #ifndef CONFIG_PARPORT
if (pi->reserved) if (pi->reserved)
release_region(pi->port,pi->reserved); release_region(pi->port, pi->reserved);
#endif /* !CONFIG_PARPORT */ #endif /* !CONFIG_PARPORT */
pi->proto->release_proto(pi); pi->proto->release_proto(pi);
} }
...@@ -187,50 +183,53 @@ EXPORT_SYMBOL(pi_release); ...@@ -187,50 +183,53 @@ EXPORT_SYMBOL(pi_release);
#define WR(r,v) pi_write_regr(pi,0,r,v) #define WR(r,v) pi_write_regr(pi,0,r,v)
#define RR(r) (pi_read_regr(pi,0,r)) #define RR(r) (pi_read_regr(pi,0,r))
static int pi_test_proto( PIA *pi, char * scratch, int verbose ) static int pi_test_proto(PIA * pi, char *scratch, int verbose)
{
{ int j, k; int j, k;
int e[2] = {0,0}; int e[2] = { 0, 0 };
if (pi->proto->test_proto) { if (pi->proto->test_proto) {
pi_claim(pi); pi_claim(pi);
j = pi->proto->test_proto(pi,scratch,verbose); j = pi->proto->test_proto(pi, scratch, verbose);
pi_unclaim(pi); pi_unclaim(pi);
return j; return j;
} }
pi_connect(pi); pi_connect(pi);
for (j=0;j<2;j++) { for (j = 0; j < 2; j++) {
WR(6,0xa0+j*0x10); WR(6, 0xa0 + j * 0x10);
for (k=0;k<256;k++) { for (k = 0; k < 256; k++) {
WR(2,k^0xaa); WR(2, k ^ 0xaa);
WR(3,k^0x55); WR(3, k ^ 0x55);
if (RR(2) != (k^0xaa)) e[j]++; if (RR(2) != (k ^ 0xaa))
} e[j]++;
} }
}
pi_disconnect(pi); pi_disconnect(pi);
if (verbose) if (verbose)
printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n", printk("%s: %s: port 0x%x, mode %d, test=(%d,%d)\n",
pi->device,pi->proto->name,pi->port, pi->device, pi->proto->name, pi->port,
pi->mode,e[0],e[1]); pi->mode, e[0], e[1]);
return (e[0] && e[1]); /* not here if both > 0 */ return (e[0] && e[1]); /* not here if both > 0 */
} }
int pi_register( PIP *pr) int pi_register(PIP * pr)
{
{ int k; int k;
for (k=0;k<MAX_PROTOS;k++) for (k = 0; k < MAX_PROTOS; k++)
if (protocols[k] && !strcmp(pr->name,protocols[k]->name)) { if (protocols[k] && !strcmp(pr->name, protocols[k]->name)) {
printk("paride: %s protocol already registered\n",pr->name); printk("paride: %s protocol already registered\n",
return 0; pr->name);
} return 0;
}
k = 0; k = 0;
while((k<MAX_PROTOS) && (protocols[k])) k++; while ((k < MAX_PROTOS) && (protocols[k]))
k++;
if (k == MAX_PROTOS) { if (k == MAX_PROTOS) {
printk("paride: protocol table full\n"); printk("paride: protocol table full\n");
return 0; return 0;
...@@ -238,194 +237,209 @@ int pi_register( PIP *pr) ...@@ -238,194 +237,209 @@ int pi_register( PIP *pr)
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
protocols[k] = pr; protocols[k] = pr;
pr->index = k; pr->index = k;
printk("paride: %s registered as protocol %d\n",pr->name,k); printk("paride: %s registered as protocol %d\n", pr->name, k);
return 1; return 1;
} }
EXPORT_SYMBOL(pi_register); EXPORT_SYMBOL(pi_register);
void pi_unregister( PIP *pr) void pi_unregister(PIP * pr)
{
{ if (!pr) return; if (!pr)
return;
if (protocols[pr->index] != pr) { if (protocols[pr->index] != pr) {
printk("paride: %s not registered\n",pr->name); printk("paride: %s not registered\n", pr->name);
return; return;
} }
protocols[pr->index] = 0; protocols[pr->index] = 0;
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
EXPORT_SYMBOL(pi_unregister); EXPORT_SYMBOL(pi_unregister);
static int pi_register_parport( PIA *pi, int verbose) static int pi_register_parport(PIA * pi, int verbose)
{ {
#ifdef CONFIG_PARPORT #ifdef CONFIG_PARPORT
struct parport *port; struct parport *port;
port = parport_find_base (pi->port); port = parport_find_base(pi->port);
if (!port) if (!port)
return 0; return 0;
pi->pardev = parport_register_device(port, pi->pardev = parport_register_device(port,
pi->device,NULL, pi->device, NULL,
pi_wake_up,NULL, pi_wake_up, NULL, 0, (void *) pi);
0,(void *)pi); parport_put_port(port);
parport_put_port (port);
if (!pi->pardev) if (!pi->pardev)
return 0; return 0;
init_waitqueue_head(&pi->parq); init_waitqueue_head(&pi->parq);
if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port, if (verbose)
port->name); printk("%s: 0x%x is %s\n", pi->device, pi->port, port->name);
pi->parname = (char *)port->name; pi->parname = (char *) port->name;
#endif #endif
return 1; return 1;
} }
static int pi_probe_mode( PIA *pi, int max, char * scratch, int verbose) static int pi_probe_mode(PIA * pi, int max, char *scratch, int verbose)
{
{ int best, range; int best, range;
if (pi->mode != -1) { if (pi->mode != -1) {
if (pi->mode >= max) return 0; if (pi->mode >= max)
return 0;
range = 3; range = 3;
if (pi->mode >= pi->proto->epp_first) range = 8; if (pi->mode >= pi->proto->epp_first)
if ((range == 8) && (pi->port % 8)) return 0; range = 8;
if ((range == 8) && (pi->port % 8))
return 0;
pi->reserved = range; pi->reserved = range;
return (!pi_test_proto(pi,scratch,verbose)); return (!pi_test_proto(pi, scratch, verbose));
} }
best = -1; best = -1;
for(pi->mode=0;pi->mode<max;pi->mode++) { for (pi->mode = 0; pi->mode < max; pi->mode++) {
range = 3; range = 3;
if (pi->mode >= pi->proto->epp_first) range = 8; if (pi->mode >= pi->proto->epp_first)
if ((range == 8) && (pi->port % 8)) break; range = 8;
if ((range == 8) && (pi->port % 8))
break;
pi->reserved = range; pi->reserved = range;
if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode; if (!pi_test_proto(pi, scratch, verbose))
best = pi->mode;
} }
pi->mode = best; pi->mode = best;
return (best > -1); return (best > -1);
} }
static int pi_probe_unit( PIA *pi, int unit, char * scratch, int verbose) static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
{
{ int max,s,e; int max, s, e;
s = unit; e = s+1; s = unit;
e = s + 1;
if (s == -1) { if (s == -1) {
s = 0; s = 0;
e = pi->proto->max_units; e = pi->proto->max_units;
} }
if (!pi_register_parport(pi,verbose)) if (!pi_register_parport(pi, verbose))
return 0; return 0;
if (pi->proto->test_port) { if (pi->proto->test_port) {
pi_claim(pi); pi_claim(pi);
max = pi->proto->test_port(pi); max = pi->proto->test_port(pi);
pi_unclaim(pi); pi_unclaim(pi);
} } else
else max = pi->proto->max_mode; max = pi->proto->max_mode;
if (pi->proto->probe_unit) { if (pi->proto->probe_unit) {
pi_claim(pi); pi_claim(pi);
for (pi->unit=s;pi->unit<e;pi->unit++) for (pi->unit = s; pi->unit < e; pi->unit++)
if (pi->proto->probe_unit(pi)) { if (pi->proto->probe_unit(pi)) {
pi_unclaim(pi); pi_unclaim(pi);
if (pi_probe_mode(pi,max,scratch,verbose)) return 1; if (pi_probe_mode(pi, max, scratch, verbose))
pi_unregister_parport(pi); return 1;
return 0; pi_unregister_parport(pi);
} return 0;
pi_unclaim(pi); }
pi_unregister_parport(pi); pi_unclaim(pi);
return 0; pi_unregister_parport(pi);
} return 0;
}
if (!pi_probe_mode(pi,max,scratch,verbose)) {
pi_unregister_parport(pi); if (!pi_probe_mode(pi, max, scratch, verbose)) {
return 0; pi_unregister_parport(pi);
return 0;
} }
return 1; return 1;
}
int pi_init(PIA *pi, int autoprobe, int port, int mode, }
int unit, int protocol, int delay, char * scratch,
int devtype, int verbose, char *device )
{ int p,k,s,e; int pi_init(PIA * pi, int autoprobe, int port, int mode,
int lpts[7] = {0x3bc,0x378,0x278,0x268,0x27c,0x26c,0}; int unit, int protocol, int delay, char *scratch,
int devtype, int verbose, char *device)
{
int p, k, s, e;
int lpts[7] = { 0x3bc, 0x378, 0x278, 0x268, 0x27c, 0x26c, 0 };
s = protocol; e = s+1; s = protocol;
e = s + 1;
if (!protocols[0]) if (!protocols[0])
request_module ("paride_protocol"); request_module("paride_protocol");
if (autoprobe) { if (autoprobe) {
s = 0; s = 0;
e = MAX_PROTOS; e = MAX_PROTOS;
} else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) || } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
(!protocols[s]) || (unit < 0) || (!protocols[s]) || (unit < 0) ||
(unit >= protocols[s]->max_units)) { (unit >= protocols[s]->max_units)) {
printk("%s: Invalid parameters\n",device); printk("%s: Invalid parameters\n", device);
return 0; return 0;
} }
for (p=s;p<e;p++) { for (p = s; p < e; p++) {
if (protocols[p]) { if (protocols[p]) {
pi->proto = protocols[p]; pi->proto = protocols[p];
pi->private = 0; pi->private = 0;
pi->proto->init_proto(pi); pi->proto->init_proto(pi);
if (delay == -1) pi->delay = pi->proto->default_delay; if (delay == -1)
else pi->delay = delay; pi->delay = pi->proto->default_delay;
pi->devtype = devtype; else
pi->device = device; pi->delay = delay;
pi->devtype = devtype;
pi->parname = NULL; pi->device = device;
pi->pardev = NULL;
init_waitqueue_head(&pi->parq); pi->parname = NULL;
pi->claimed = 0; pi->pardev = NULL;
pi->claim_cont = NULL; init_waitqueue_head(&pi->parq);
pi->claimed = 0;
pi->mode = mode; pi->claim_cont = NULL;
if (port != -1) {
pi->port = port; pi->mode = mode;
if (pi_probe_unit(pi,unit,scratch,verbose)) break; if (port != -1) {
pi->port = 0; pi->port = port;
} else { if (pi_probe_unit(pi, unit, scratch, verbose))
k = 0; break;
while ((pi->port = lpts[k++])) pi->port = 0;
if (pi_probe_unit(pi,unit,scratch,verbose)) break; } else {
if (pi->port) break; k = 0;
while ((pi->port = lpts[k++]))
if (pi_probe_unit
(pi, unit, scratch, verbose))
break;
if (pi->port)
break;
}
pi->proto->release_proto(pi);
} }
pi->proto->release_proto(pi);
}
} }
if (!pi->port) { if (!pi->port) {
if (autoprobe) printk("%s: Autoprobe failed\n",device); if (autoprobe)
else printk("%s: Adapter not found\n",device); printk("%s: Autoprobe failed\n", device);
else
printk("%s: Adapter not found\n", device);
return 0; return 0;
} }
#ifndef CONFIG_PARPORT #ifndef CONFIG_PARPORT
if (!request_region(pi->port,pi->reserved,pi->device)) if (!request_region(pi->port, pi->reserved, pi->device)) {
{ printk(KERN_WARNING "paride: Unable to request region 0x%x\n",
printk(KERN_WARNING"paride: Unable to request region 0x%x\n", pi->port); pi->port);
return 0; return 0;
} }
#endif /* !CONFIG_PARPORT */ #endif /* !CONFIG_PARPORT */
if (pi->parname) if (pi->parname)
printk("%s: Sharing %s at 0x%x\n",pi->device, printk("%s: Sharing %s at 0x%x\n", pi->device,
pi->parname,pi->port); pi->parname, pi->port);
pi->proto->log_adapter(pi,scratch,verbose); pi->proto->log_adapter(pi, scratch, verbose);
return 1; return 1;
} }
......
...@@ -5871,8 +5871,8 @@ int __init sbpcd_init(void) ...@@ -5871,8 +5871,8 @@ int __init sbpcd_init(void)
disk->fops = &sbpcd_bdops; disk->fops = &sbpcd_bdops;
strcpy(disk->disk_name, sbpcd_infop->name); strcpy(disk->disk_name, sbpcd_infop->name);
disk->flags = GENHD_FL_CD; disk->flags = GENHD_FL_CD;
sprintf(nbuff, "c0t%d", p->drv_id); sprintf(nbuff, "sbp/c0t%d", p->drv_id);
disk->de = devfs_mk_dir(devfs_handle, nbuff, NULL); disk->de = devfs_mk_dir(NULL, nbuff, NULL);
p->disk = disk; p->disk = disk;
if (register_cdrom(sbpcd_infop)) if (register_cdrom(sbpcd_infop))
{ {
......
...@@ -1047,7 +1047,6 @@ static int alloc_disks(ide_hwif_t *hwif) ...@@ -1047,7 +1047,6 @@ static int alloc_disks(ide_hwif_t *hwif)
static void init_gendisk (ide_hwif_t *hwif) static void init_gendisk (ide_hwif_t *hwif)
{ {
unsigned int unit; unsigned int unit;
extern devfs_handle_t ide_devfs_handle;
for (unit = 0; unit < MAX_DRIVES; ++unit) { for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t * drive = &hwif->drives[unit]; ide_drive_t * drive = &hwif->drives[unit];
...@@ -1059,13 +1058,13 @@ static void init_gendisk (ide_hwif_t *hwif) ...@@ -1059,13 +1058,13 @@ static void init_gendisk (ide_hwif_t *hwif)
"%s","IDE Drive"); "%s","IDE Drive");
drive->gendev.parent = &hwif->gendev; drive->gendev.parent = &hwif->gendev;
drive->gendev.bus = &ide_bus_type; drive->gendev.bus = &ide_bus_type;
sprintf (name, "host%d/bus%d/target%d/lun%d", sprintf (name, "ide/host%d/bus%d/target%d/lun%d",
(hwif->channel && hwif->mate) ? (hwif->channel && hwif->mate) ?
hwif->mate->index : hwif->index, hwif->mate->index : hwif->index,
hwif->channel, unit, drive->lun); hwif->channel, unit, drive->lun);
if (drive->present) { if (drive->present) {
device_register(&drive->gendev); device_register(&drive->gendev);
drive->de = devfs_mk_dir(ide_devfs_handle, name, NULL); drive->de = devfs_mk_dir(NULL, name, NULL);
} }
} }
blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS, blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
......
...@@ -6122,6 +6122,7 @@ static int idetape_cleanup (ide_drive_t *drive) ...@@ -6122,6 +6122,7 @@ static int idetape_cleanup (ide_drive_t *drive)
drive->driver_data = NULL; drive->driver_data = NULL;
devfs_unregister(tape->de_r); devfs_unregister(tape->de_r);
devfs_unregister(tape->de_n); devfs_unregister(tape->de_n);
devfs_unregister_tape(drive->disk->number);
kfree (tape); kfree (tape);
drive->disk->fops = ide_fops; drive->disk->fops = ide_fops;
return 0; return 0;
...@@ -6269,7 +6270,7 @@ static int idetape_attach (ide_drive_t *drive) ...@@ -6269,7 +6270,7 @@ static int idetape_attach (ide_drive_t *drive)
HWIF(drive)->major, minor + 128, HWIF(drive)->major, minor + 128,
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
&idetape_fops, NULL); &idetape_fops, NULL);
devfs_register_tape(tape->de_r); drive->disk->number = devfs_register_tape(drive->de);
drive->disk->fops = &idetape_block_ops; drive->disk->fops = &idetape_block_ops;
return 0; return 0;
failed: failed:
......
...@@ -169,15 +169,6 @@ static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED; ...@@ -169,15 +169,6 @@ static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED;
static struct hpsb_highlevel *hl_handle; /* = NULL; */ static struct hpsb_highlevel *hl_handle; /* = NULL; */
static LIST_HEAD(dv1394_devfs);
struct dv1394_devfs_entry {
struct list_head list;
devfs_handle_t devfs;
char name[32];
struct dv1394_devfs_entry *parent;
};
static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED;
/* translate from a struct file* to the corresponding struct video_card* */ /* translate from a struct file* to the corresponding struct video_card* */
static inline struct video_card* file_to_video_card(struct file *file) static inline struct video_card* file_to_video_card(struct file *file)
...@@ -2564,135 +2555,42 @@ static struct file_operations dv1394_fops= ...@@ -2564,135 +2555,42 @@ static struct file_operations dv1394_fops=
/*** DEVFS HELPERS *********************************************************/ /*** DEVFS HELPERS *********************************************************/
struct dv1394_devfs_entry *
dv1394_devfs_find( char *name)
{
struct list_head *lh;
struct dv1394_devfs_entry *p;
spin_lock( &dv1394_devfs_lock);
if(!list_empty(&dv1394_devfs)) {
list_for_each(lh, &dv1394_devfs) {
p = list_entry(lh, struct dv1394_devfs_entry, list);
if(!strncmp(p->name, name, sizeof(p->name))) {
goto found;
}
}
}
p = NULL;
found:
spin_unlock( &dv1394_devfs_lock);
return p;
}
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
static int dv1394_devfs_add_entry(struct video_card *video) static int dv1394_devfs_add_entry(struct video_card *video)
{ {
char buf[32]; char buf[64];
struct dv1394_devfs_entry *p; snprintf(buf, sizeof(buf), "ieee1394/dv/host%d/%s/%s",
struct dv1394_devfs_entry *parent; (video->id>>2),
(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
(video->mode == MODE_RECEIVE ? "in" : "out"));
p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); video->devfs_handle = devfs_register(NULL, buf, DEVFS_FL_NONE,
if(!p) {
printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
goto err;
}
memset(p, 0, sizeof(struct dv1394_devfs_entry));
snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2),
(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"));
parent = dv1394_devfs_find(buf);
if (parent == NULL) {
printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf);
goto err_free;
}
video->devfs_handle = devfs_register(
parent->devfs,
(video->mode == MODE_RECEIVE ? "in" : "out"),
DEVFS_FL_NONE,
IEEE1394_MAJOR, IEEE1394_MAJOR,
IEEE1394_MINOR_BLOCK_DV1394*16 + video->id, IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
&dv1394_fops, &dv1394_fops,
(void*) video); (void*) video);
p->devfs = video->devfs_handle; if (video->devfs_handle == NULL) {
printk(KERN_ERR "dv1394: unable to create /dev/%s\n", buf);
if (p->devfs == NULL) { return -ENOMEM;
printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n",
parent->name,
(video->mode == MODE_RECEIVE ? "in" : "out"));
goto err_free;
} }
spin_lock( &dv1394_devfs_lock);
INIT_LIST_HEAD(&p->list);
list_add_tail(&p->list, &dv1394_devfs);
spin_unlock( &dv1394_devfs_lock);
return 0; return 0;
err_free:
kfree(p);
err:
return -ENOMEM;
} }
static int static int dv1394_devfs_add_dir(char *name)
dv1394_devfs_add_dir( char *name,
struct dv1394_devfs_entry *parent,
struct dv1394_devfs_entry **out)
{ {
struct dv1394_devfs_entry *p; if (!devfs_mk_dir(NULL, name, NULL))
printk(KERN_ERR "dv1394: unable to create /dev/%s\n", name);
p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); return -ENOMEM;
if(!p) {
printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n");
goto err;
}
memset(p, 0, sizeof(struct dv1394_devfs_entry));
if (parent == NULL) {
snprintf(p->name, sizeof(p->name), "%s", name);
p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL);
} else {
snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name);
p->devfs = devfs_mk_dir(parent->devfs, name, NULL);
}
if (p->devfs == NULL) {
printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name);
goto err_free;
} }
p->parent = parent;
if (out != NULL) *out = p;
spin_lock( &dv1394_devfs_lock);
INIT_LIST_HEAD(&p->list);
list_add_tail(&p->list, &dv1394_devfs);
spin_unlock( &dv1394_devfs_lock);
return 0; return 0;
err_free:
kfree(p);
err:
return -ENOMEM;
} }
void dv1394_devfs_del( char *name) void dv1394_devfs_del(char *name)
{ {
struct dv1394_devfs_entry *p = dv1394_devfs_find(name); char s[64];
if (p != NULL) { sprintf(s, "ieee1394/%s", name);
devfs_unregister(p->devfs); devfs_find_and_unregister(NULL, s, 0, 0, 0, 0);
spin_lock( &dv1394_devfs_lock);
list_del(&p->list);
spin_unlock( &dv1394_devfs_lock);
kfree(p);
}
} }
#endif /* CONFIG_DEVFS_FS */ #endif /* CONFIG_DEVFS_FS */
...@@ -2874,15 +2772,12 @@ static void dv1394_add_host (struct hpsb_host *host) ...@@ -2874,15 +2772,12 @@ static void dv1394_add_host (struct hpsb_host *host)
#endif #endif
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
{ snprintf(buf, sizeof(buf), "ieee1394/dv/host%d", ohci->id);
struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv"); dv1394_devfs_add_dir(buf);
if (devfs_entry != NULL) { snprintf(buf, sizeof(buf), "ieee1394/dv/host%d/NTSC", ohci->id);
snprintf(buf, sizeof(buf), "host%d", ohci->id); dv1394_devfs_add_dir(buf);
dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry); snprintf(buf, sizeof(buf), "ieee1394/dv/host%d/PAL", ohci->id);
dv1394_devfs_add_dir("NTSC", devfs_entry, NULL); dv1394_devfs_add_dir(buf);
dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
}
}
#endif #endif
dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
...@@ -3042,7 +2937,7 @@ static int __init dv1394_init_module(void) ...@@ -3042,7 +2937,7 @@ static int __init dv1394_init_module(void)
} }
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) { if (dv1394_devfs_add_dir("ieee1394/dv") < 0) {
printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n"); printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
return -ENOMEM; return -ENOMEM;
......
...@@ -1078,7 +1078,6 @@ static struct miscdevice _dm_misc = { ...@@ -1078,7 +1078,6 @@ static struct miscdevice _dm_misc = {
int __init dm_interface_init(void) int __init dm_interface_init(void)
{ {
int r; int r;
char rname[64];
r = dm_hash_init(); r = dm_hash_init();
if (r) if (r)
...@@ -1091,25 +1090,12 @@ int __init dm_interface_init(void) ...@@ -1091,25 +1090,12 @@ int __init dm_interface_init(void)
return r; return r;
} }
r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3, r = devfs_mk_symlink(NULL, DM_DIR "/control", DEVFS_FL_DEFAULT,
sizeof rname - 3); "../misc/" DM_NAME, &_ctl_handle, NULL);
if (r == -ENOSYS)
return 0; /* devfs not present */
if (r < 0) {
DMERR("devfs_generate_path failed for control device");
goto failed;
}
strncpy(rname + r, "../", 3);
r = devfs_mk_symlink(NULL, DM_DIR "/control",
DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL);
if (r) { if (r) {
DMERR("devfs_mk_symlink failed for control device"); DMERR("devfs_mk_symlink failed for control device");
goto failed; goto failed;
} }
devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle);
DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
DM_DRIVER_EMAIL); DM_DRIVER_EMAIL);
...@@ -1125,6 +1111,8 @@ void dm_interface_exit(void) ...@@ -1125,6 +1111,8 @@ void dm_interface_exit(void)
{ {
dm_hash_exit(); dm_hash_exit();
devfs_find_and_unregister(NULL, DM_DIR "/control", 0, 0, 0, 0);
if (misc_deregister(&_dm_misc) < 0) if (misc_deregister(&_dm_misc) < 0)
DMERR("misc_deregister failed for control device"); DMERR("misc_deregister failed for control device");
} }
...@@ -350,7 +350,7 @@ int dvbdev_get_free_adapter_num (void) ...@@ -350,7 +350,7 @@ int dvbdev_get_free_adapter_num (void)
int dvb_register_adapter(dvb_adapter_t **padap, char *name) int dvb_register_adapter(dvb_adapter_t **padap, char *name)
{ {
char dirname[10]; char dirname[16];
dvb_adapter_t *adap; dvb_adapter_t *adap;
int num; int num;
...@@ -374,8 +374,8 @@ int dvb_register_adapter(dvb_adapter_t **padap, char *name) ...@@ -374,8 +374,8 @@ int dvb_register_adapter(dvb_adapter_t **padap, char *name)
printk ("%s: registering new adapter (%s).\n", __FUNCTION__, name); printk ("%s: registering new adapter (%s).\n", __FUNCTION__, name);
sprintf(dirname, "adapter%d", num); sprintf(dirname, "dvb/adapter%d", num);
adap->devfs_handle = devfs_mk_dir(dvb_devfs_handle, dirname, NULL); adap->devfs_handle = devfs_mk_dir(NULL, dirname, NULL);
adap->num = num; adap->num = num;
list_add_tail (&adap->list_head, &dvb_adapter_list); list_add_tail (&adap->list_head, &dvb_adapter_list);
......
...@@ -283,7 +283,7 @@ dasd_free_device(dasd_device_t *device) ...@@ -283,7 +283,7 @@ dasd_free_device(dasd_device_t *device)
static inline int static inline int
dasd_state_new_to_known(dasd_device_t *device) dasd_state_new_to_known(dasd_device_t *device)
{ {
char buffer[5]; char buffer[10];
dasd_devmap_t *devmap; dasd_devmap_t *devmap;
umode_t devfs_perm; umode_t devfs_perm;
devfs_handle_t dir; devfs_handle_t dir;
...@@ -303,8 +303,8 @@ dasd_state_new_to_known(dasd_device_t *device) ...@@ -303,8 +303,8 @@ dasd_state_new_to_known(dasd_device_t *device)
return rc; return rc;
/* Add a proc directory and the dasd device entry to devfs. */ /* Add a proc directory and the dasd device entry to devfs. */
sprintf(buffer, "%04x", device->devinfo.devno); sprintf(buffer, "dasd/%04x", device->devinfo.devno);
dir = devfs_mk_dir(dasd_devfs_handle, buffer, device); dir = devfs_mk_dir(NULL, buffer, NULL);
device->gdp->de = dir; device->gdp->de = dir;
if (devmap->features & DASD_FEATURE_READONLY) if (devmap->features & DASD_FEATURE_READONLY)
devfs_perm = S_IFBLK | S_IRUSR; devfs_perm = S_IFBLK | S_IRUSR;
......
...@@ -5486,7 +5486,7 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5486,7 +5486,7 @@ static int osst_attach(Scsi_Device * SDp)
0, 0, &osst_fops, NULL); 0, 0, &osst_fops, NULL);
# endif # endif
} }
devfs_register_tape (tpnt->de_r[0]); disk->number = devfs_register_tape(SDp->de);
#endif #endif
tpnt->device = SDp; tpnt->device = SDp;
...@@ -5647,6 +5647,7 @@ static void osst_detach(Scsi_Device * SDp) ...@@ -5647,6 +5647,7 @@ static void osst_detach(Scsi_Device * SDp)
devfs_unregister (tpnt->de_n[mode]); devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL; tpnt->de_n[mode] = NULL;
} }
devfs_unregister_tape(tpnt->disk->number);
#endif #endif
put_disk(tpnt->disk); put_disk(tpnt->disk);
kfree(tpnt); kfree(tpnt);
......
...@@ -1323,7 +1323,6 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1323,7 +1323,6 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
{ {
Scsi_Device *sdev; Scsi_Device *sdev;
char devname[64]; char devname[64];
extern devfs_handle_t scsi_devfs_handle;
sdev = scsi_alloc_sdev(sdevscan->host, sdevscan->channel, sdev = scsi_alloc_sdev(sdevscan->host, sdevscan->channel,
sdevscan->id, sdevscan->lun); sdevscan->id, sdevscan->lun);
...@@ -1445,13 +1444,13 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew, ...@@ -1445,13 +1444,13 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
*/ */
device_create_file(&sdev->sdev_driverfs_dev, &dev_attr_type); device_create_file(&sdev->sdev_driverfs_dev, &dev_attr_type);
sprintf(devname, "host%d/bus%d/target%d/lun%d", sprintf(devname, "scsi/host%d/bus%d/target%d/lun%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
if (sdev->de) if (sdev->de)
printk(KERN_WARNING "scsi devfs dir: \"%s\" already exists\n", printk(KERN_WARNING "scsi devfs dir: \"%s\" already exists\n",
devname); devname);
else else
sdev->de = devfs_mk_dir(scsi_devfs_handle, devname, NULL); sdev->de = devfs_mk_dir(NULL, devname, NULL);
/* /*
* End driverfs/devfs code. * End driverfs/devfs code.
*/ */
......
...@@ -3874,7 +3874,7 @@ static int st_attach(Scsi_Device * SDp) ...@@ -3874,7 +3874,7 @@ static int st_attach(Scsi_Device * SDp)
S_IFCHR | S_IRUGO | S_IWUGO, S_IFCHR | S_IRUGO | S_IWUGO,
&st_fops, NULL); &st_fops, NULL);
} }
devfs_register_tape (tpnt->de_r[0]); disk->number = devfs_register_tape(SDp->de);
printk(KERN_WARNING printk(KERN_WARNING
"Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n", "Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n",
...@@ -3908,6 +3908,7 @@ static void st_detach(Scsi_Device * SDp) ...@@ -3908,6 +3908,7 @@ static void st_detach(Scsi_Device * SDp)
devfs_unregister (tpnt->de_n[mode]); devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL; tpnt->de_n[mode] = NULL;
} }
devfs_unregister_tape(tpnt->disk->number);
scsi_tapes[i] = 0; scsi_tapes[i] = 0;
scsi_slave_detach(SDp); scsi_slave_detach(SDp);
st_nr_dev--; st_nr_dev--;
......
...@@ -80,26 +80,33 @@ ...@@ -80,26 +80,33 @@
* @de: Any tape device entry in the device directory. * @de: Any tape device entry in the device directory.
*/ */
void devfs_register_tape (devfs_handle_t de) int devfs_register_tape (devfs_handle_t de)
{ {
int pos; int pos;
devfs_handle_t parent, slave; devfs_handle_t slave;
char name[16], dest[64]; char name[32], dest[64];
static unsigned int tape_counter; static unsigned int tape_counter;
static devfs_handle_t tape_dir; int n = tape_counter++;
if (tape_dir == NULL) tape_dir = devfs_mk_dir (NULL, "tapes", NULL); pos = devfs_generate_path (de, dest + 3, sizeof dest - 3);
parent = devfs_get_parent (de); if (pos < 0) return -1;
pos = devfs_generate_path (parent, dest + 3, sizeof dest - 3);
if (pos < 0) return;
strncpy (dest + pos, "../", 3); strncpy (dest + pos, "../", 3);
sprintf (name, "tape%u", tape_counter++); sprintf (name, "tapes/tape%u", n);
devfs_mk_symlink (tape_dir, name, DEVFS_FL_DEFAULT, dest + pos, devfs_mk_symlink (NULL, name, DEVFS_FL_DEFAULT, dest + pos, &slave, NULL);
&slave, NULL); return n;
devfs_auto_unregister (de, slave);
} /* End Function devfs_register_tape */ } /* End Function devfs_register_tape */
EXPORT_SYMBOL(devfs_register_tape); EXPORT_SYMBOL(devfs_register_tape);
void devfs_unregister_tape(int num)
{
if (num >= 0) {
char name[32];
sprintf(name, "tapes/tape%u", num);
devfs_find_and_unregister(NULL, name, 0, 0, 0, 0);
}
}
EXPORT_SYMBOL(devfs_unregister_tape);
/** /**
* devfs_register_series - Register a sequence of device entries. * devfs_register_series - Register a sequence of device entries.
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/hash.h> #include <linux/hash.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/rwsem.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -65,13 +66,6 @@ ...@@ -65,13 +66,6 @@
/* Minimum size of the hash in bits ( 2^N ) */ /* Minimum size of the hash in bits ( 2^N ) */
#define EP_MIN_HASH_BITS 9 #define EP_MIN_HASH_BITS 9
/*
* Event buffer dimension used to cache events before sending them in
* userspace with a __copy_to_user(). The event buffer is in stack,
* so keep this size fairly small.
*/
#define EP_EVENT_BUFF_SIZE 32
/* Maximum number of wait queue we can attach to */ /* Maximum number of wait queue we can attach to */
#define EP_MAX_POLL_QUEUE 2 #define EP_MAX_POLL_QUEUE 2
...@@ -110,6 +104,17 @@ ...@@ -110,6 +104,17 @@
/* Get the "struct epitem" from an epoll queue wrapper */ /* Get the "struct epitem" from an epoll queue wrapper */
#define EP_ITEM_FROM_EPQUEUE(p) (container_of(p, struct ep_pqueue, pt)->dpi) #define EP_ITEM_FROM_EPQUEUE(p) (container_of(p, struct ep_pqueue, pt)->dpi)
/*
* This is used to optimize the event transfer to userspace. Since this
* is kept on stack, it should be pretty small.
*/
#define EP_MAX_BUF_EVENTS 32
/*
* Used to optimize ready items collection by reducing the irqlock/irqunlock
* switching rate. This is kept in stack too, so do not go wild with this number.
*/
#define EP_MAX_COLLECT_ITEMS 64
...@@ -119,9 +124,6 @@ ...@@ -119,9 +124,6 @@
* interface. * interface.
*/ */
struct eventpoll { struct eventpoll {
/* Used to link to the "struct eventpoll" list ( eplist ) */
struct list_head llink;
/* Protect the this structure access */ /* Protect the this structure access */
rwlock_t lock; rwlock_t lock;
...@@ -187,6 +189,9 @@ struct epitem { ...@@ -187,6 +189,9 @@ struct epitem {
* that the structure will desappear from underneath our processing. * that the structure will desappear from underneath our processing.
*/ */
atomic_t usecnt; atomic_t usecnt;
/* List header used to link this item to the "struct file" items list */
struct list_head fllink;
}; };
/* Wrapper struct used by poll queueing */ /* Wrapper struct used by poll queueing */
...@@ -212,11 +217,15 @@ static void ep_release_epitem(struct epitem *dpi); ...@@ -212,11 +217,15 @@ static void ep_release_epitem(struct epitem *dpi);
static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, poll_table *pt); static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, poll_table *pt);
static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfile); static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfile);
static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events); static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events);
static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *dpi);
static int ep_unlink(struct eventpoll *ep, struct epitem *dpi); static int ep_unlink(struct eventpoll *ep, struct epitem *dpi);
static int ep_remove(struct eventpoll *ep, struct epitem *dpi); static int ep_remove(struct eventpoll *ep, struct epitem *dpi);
static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync); static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync);
static int ep_eventpoll_close(struct inode *inode, struct file *file); static int ep_eventpoll_close(struct inode *inode, struct file *file);
static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait); static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
static int ep_collect_ready_items(struct eventpoll *ep, struct epitem **adpi, int maxdpi);
static int ep_send_events(struct eventpoll *ep, struct epitem **adpi, int ndpi,
struct pollfd *events);
static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents); static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents);
static int ep_poll(struct eventpoll *ep, struct pollfd *events, int maxevents, static int ep_poll(struct eventpoll *ep, struct pollfd *events, int maxevents,
int timeout); int timeout);
...@@ -226,12 +235,15 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type, ...@@ -226,12 +235,15 @@ static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
int flags, char *dev_name, void *data); int flags, char *dev_name, void *data);
/*
/* Use to link togheter all the "struct eventpoll" */ * This semaphore is used to ensure that files are not removed
static struct list_head eplist; * while epoll is using them. Namely the f_op->poll(), since
* it has to be called from outside the lock, must be protected.
/* Serialize the access to "eplist" */ * This is read-held during the event transfer loop to userspace
static rwlock_t eplock; * and it is write-held during the file cleanup path and the epoll
* exit code.
*/
struct rw_semaphore epsem;
/* Slab cache used to allocate "struct epitem" */ /* Slab cache used to allocate "struct epitem" */
static kmem_cache_t *dpi_cache; static kmem_cache_t *dpi_cache;
...@@ -275,6 +287,15 @@ static unsigned int ep_get_hash_bits(unsigned int hintsize) ...@@ -275,6 +287,15 @@ static unsigned int ep_get_hash_bits(unsigned int hintsize)
} }
/* Used to initialize the epoll bits inside the "struct file" */
void ep_init_file_struct(struct file *file)
{
INIT_LIST_HEAD(&file->f_ep_links);
spin_lock_init(&file->f_ep_lock);
}
/* /*
* This is called from inside fs/file_table.c:__fput() to unlink files * This is called from inside fs/file_table.c:__fput() to unlink files
* from the eventpoll interface. We need to have this facility to cleanup * from the eventpoll interface. We need to have this facility to cleanup
...@@ -283,21 +304,18 @@ static unsigned int ep_get_hash_bits(unsigned int hintsize) ...@@ -283,21 +304,18 @@ static unsigned int ep_get_hash_bits(unsigned int hintsize)
*/ */
void ep_notify_file_close(struct file *file) void ep_notify_file_close(struct file *file)
{ {
unsigned long flags; struct list_head *lsthead = &file->f_ep_links;
struct list_head *lnk;
struct eventpoll *ep;
struct epitem *dpi; struct epitem *dpi;
read_lock_irqsave(&eplock, flags); down_write(&epsem);
list_for_each(lnk, &eplist) { while (!list_empty(lsthead)) {
ep = list_entry(lnk, struct eventpoll, llink); dpi = list_entry(lsthead->next, struct epitem, fllink);
while ((dpi = ep_find(ep, file))) { EP_LIST_DEL(&dpi->fllink);
ep_remove(ep, dpi);
ep_release_epitem(dpi); ep_remove(dpi->ep, dpi);
}
} }
read_unlock_irqrestore(&eplock, flags); up_write(&epsem);
} }
...@@ -438,14 +456,14 @@ asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events) ...@@ -438,14 +456,14 @@ asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events)
if (dpi) if (dpi)
ep_release_epitem(dpi); ep_release_epitem(dpi);
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n",
current, epfd, op, fd, events, error));
eexit_3: eexit_3:
fput(tfile); fput(tfile);
eexit_2: eexit_2:
fput(file); fput(file);
eexit_1: eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %u) = %d\n",
current, epfd, op, fd, events, error));
return error; return error;
} }
...@@ -495,12 +513,12 @@ asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents, ...@@ -495,12 +513,12 @@ asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents,
/* Time to fish for events ... */ /* Time to fish for events ... */
error = ep_poll(ep, events, maxevents, timeout); error = ep_poll(ep, events, maxevents, timeout);
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
current, epfd, events, maxevents, timeout, error));
eexit_2: eexit_2:
fput(file); fput(file);
eexit_1: eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
current, epfd, events, maxevents, timeout, error));
return error; return error;
} }
...@@ -616,7 +634,6 @@ static int ep_free_pages(char **pages, int numpages) ...@@ -616,7 +634,6 @@ static int ep_free_pages(char **pages, int numpages)
static int ep_file_init(struct file *file, unsigned int hashbits) static int ep_file_init(struct file *file, unsigned int hashbits)
{ {
int error; int error;
unsigned long flags;
struct eventpoll *ep; struct eventpoll *ep;
if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL)))
...@@ -632,11 +649,6 @@ static int ep_file_init(struct file *file, unsigned int hashbits) ...@@ -632,11 +649,6 @@ static int ep_file_init(struct file *file, unsigned int hashbits)
file->private_data = ep; file->private_data = ep;
/* Add the structure to the linked list that links "struct eventpoll" */
write_lock_irqsave(&eplock, flags);
list_add(&ep->llink, &eplist);
write_unlock_irqrestore(&eplock, flags);
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n", DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n",
current, ep)); current, ep));
return 0; return 0;
...@@ -669,7 +681,6 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits) ...@@ -669,7 +681,6 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits)
int error; int error;
unsigned int i, hsize; unsigned int i, hsize;
INIT_LIST_HEAD(&ep->llink);
rwlock_init(&ep->lock); rwlock_init(&ep->lock);
init_waitqueue_head(&ep->wq); init_waitqueue_head(&ep->wq);
init_waitqueue_head(&ep->poll_wait); init_waitqueue_head(&ep->poll_wait);
...@@ -694,44 +705,45 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits) ...@@ -694,44 +705,45 @@ static int ep_init(struct eventpoll *ep, unsigned int hashbits)
static void ep_free(struct eventpoll *ep) static void ep_free(struct eventpoll *ep)
{ {
unsigned int i, hsize; unsigned int i, hsize;
unsigned long flags; struct list_head *lsthead, *lnk;
struct list_head *lsthead;
/*
* We need to lock this because we could be hit by
* ep_notify_file_close() while we're freeing the
* "struct eventpoll".
*/
down_write(&epsem);
/* /*
* Walks through the whole hash by unregistering file callbacks and * Walks through the whole hash by unregistering poll callbacks.
* freeing each "struct epitem".
*/ */
for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) { for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
lsthead = ep_hash_entry(ep, i); lsthead = ep_hash_entry(ep, i);
/* list_for_each(lnk, lsthead) {
* We need to lock this because we could be hit by struct epitem *dpi = list_entry(lnk, struct epitem, llink);
* ep_notify_file_close() while we're freeing this.
*/
write_lock_irqsave(&ep->lock, flags);
while (!list_empty(lsthead)) { ep_unregister_pollwait(ep, dpi);
struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink); }
}
/* The function ep_unlink() must be called with held lock */
ep_unlink(ep, dpi);
/* We release the lock before releasing the "struct epitem" */ /*
write_unlock_irqrestore(&ep->lock, flags); * Walks through the whole hash by freeing each "struct epitem". At this
* point we are sure no poll callbacks will be lingering around, and also by
* write-holding "epsem" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
*/
for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
lsthead = ep_hash_entry(ep, i);
ep_release_epitem(dpi); while (!list_empty(lsthead)) {
struct epitem *dpi = list_entry(lsthead->next, struct epitem, llink);
/* And then we reaquire the lock ... */ ep_remove(ep, dpi);
write_lock_irqsave(&ep->lock, flags);
} }
write_unlock_irqrestore(&ep->lock, flags);
} }
/* Remove the structure to the linked list that links "struct eventpoll" */ up_write(&epsem);
write_lock_irqsave(&eplock, flags);
EP_LIST_DEL(&ep->llink);
write_unlock_irqrestore(&eplock, flags);
/* Free hash pages */ /* Free hash pages */
ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits)); ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
...@@ -826,6 +838,7 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil ...@@ -826,6 +838,7 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil
/* Item initialization follow here ... */ /* Item initialization follow here ... */
INIT_LIST_HEAD(&dpi->llink); INIT_LIST_HEAD(&dpi->llink);
INIT_LIST_HEAD(&dpi->rdllink); INIT_LIST_HEAD(&dpi->rdllink);
INIT_LIST_HEAD(&dpi->fllink);
dpi->ep = ep; dpi->ep = ep;
dpi->file = tfile; dpi->file = tfile;
dpi->pfd = *pfd; dpi->pfd = *pfd;
...@@ -839,7 +852,16 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil ...@@ -839,7 +852,16 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil
/* Initialize the poll table using the queue callback */ /* Initialize the poll table using the queue callback */
epq.dpi = dpi; epq.dpi = dpi;
poll_initwait_ex(&epq.pt, ep_ptable_queue_proc); poll_initwait_ex(&epq.pt, ep_ptable_queue_proc, NULL);
/*
* Attach the item to the poll hooks and get current event bits.
* We can safely use the file* here because its usage count has
* been increased by the caller of this function.
*/
revents = tfile->f_op->poll(tfile, &epq.pt);
poll_freewait(&epq.pt);
/* We have to drop the new item inside our item list to keep track of it */ /* We have to drop the new item inside our item list to keep track of it */
write_lock_irqsave(&ep->lock, flags); write_lock_irqsave(&ep->lock, flags);
...@@ -847,9 +869,6 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil ...@@ -847,9 +869,6 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil
/* Add the current item to the hash table */ /* Add the current item to the hash table */
list_add(&dpi->llink, ep_hash_entry(ep, ep_hash_index(ep, tfile))); list_add(&dpi->llink, ep_hash_entry(ep, ep_hash_index(ep, tfile)));
/* Attach the item to the poll hooks and get current event bits */
revents = tfile->f_op->poll(tfile, &epq.pt);
/* If the file is already "ready" we drop it inside the ready list */ /* If the file is already "ready" we drop it inside the ready list */
if ((revents & pfd->events) && !EP_IS_LINKED(&dpi->rdllink)) { if ((revents & pfd->events) && !EP_IS_LINKED(&dpi->rdllink)) {
list_add_tail(&dpi->rdllink, &ep->rdllist); list_add_tail(&dpi->rdllink, &ep->rdllist);
...@@ -863,7 +882,10 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil ...@@ -863,7 +882,10 @@ static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfil
write_unlock_irqrestore(&ep->lock, flags); write_unlock_irqrestore(&ep->lock, flags);
poll_freewait(&epq.pt); /* Add the current item to the list of active epoll hook for this file */
spin_lock(&tfile->f_ep_lock);
list_add_tail(&dpi->fllink, &tfile->f_ep_links);
spin_unlock(&tfile->f_ep_lock);
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n", DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n",
current, ep, pfd->fd)); current, ep, pfd->fd));
...@@ -884,13 +906,21 @@ static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int even ...@@ -884,13 +906,21 @@ static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int even
unsigned int revents; unsigned int revents;
unsigned long flags; unsigned long flags;
write_lock_irqsave(&ep->lock, flags); /*
* Set the new event interest mask before calling f_op->poll(), otherwise
* a potential race might occur. In fact if we do this operation inside
* the lock, an event might happen between the f_op->poll() call and the
* new event set registering.
*/
dpi->pfd.events = events;
/* Get current event bits */ /*
* Get current event bits. We can safely use the file* here because
* its usage count has been increased by the caller of this function.
*/
revents = dpi->file->f_op->poll(dpi->file, NULL); revents = dpi->file->f_op->poll(dpi->file, NULL);
/* Set the new event interest mask */ write_lock_irqsave(&ep->lock, flags);
dpi->pfd.events = events;
/* If the file is already "ready" we drop it inside the ready list */ /* If the file is already "ready" we drop it inside the ready list */
if ((revents & events) && EP_IS_LINKED(&dpi->llink) && if ((revents & events) && EP_IS_LINKED(&dpi->llink) &&
...@@ -910,20 +940,39 @@ static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int even ...@@ -910,20 +940,39 @@ static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int even
} }
/*
* This function unregister poll callbacks from the associated file descriptor.
* Since this must be called without holding "ep->lock" the atomic exchange trick
* will protect us from multiple unregister.
*/
static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *dpi)
{
int i, nwait;
/* This is called without locks, so we need the atomic exchange */
nwait = xchg(&dpi->nwait, 0);
/* Removes poll wait queue hooks */
for (i = 0; i < nwait; i++)
remove_wait_queue(dpi->wait[i].whead, &dpi->wait[i].wait);
}
/* /*
* Unlink the "struct epitem" from all places it might have been hooked up. * Unlink the "struct epitem" from all places it might have been hooked up.
* This function must be called with write IRQ lock on "ep->lock". * This function must be called with write IRQ lock on "ep->lock".
*/ */
static int ep_unlink(struct eventpoll *ep, struct epitem *dpi) static int ep_unlink(struct eventpoll *ep, struct epitem *dpi)
{ {
int i; int error;
/* /*
* It can happen that this one is called for an item already unlinked. * It can happen that this one is called for an item already unlinked.
* The check protect us from doing a double unlink ( crash ). * The check protect us from doing a double unlink ( crash ).
*/ */
error = -ENOENT;
if (!EP_IS_LINKED(&dpi->llink)) if (!EP_IS_LINKED(&dpi->llink))
goto not_linked; goto eexit_1;
/* /*
* At this point is safe to do the job, unlink the item from our list. * At this point is safe to do the job, unlink the item from our list.
...@@ -932,10 +981,6 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *dpi) ...@@ -932,10 +981,6 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *dpi)
*/ */
EP_LIST_DEL(&dpi->llink); EP_LIST_DEL(&dpi->llink);
/* Removes poll wait queue hooks */
for (i = 0; i < dpi->nwait; i++)
remove_wait_queue(dpi->wait[i].whead, &dpi->wait[i].wait);
/* /*
* If the item we are going to remove is inside the ready file descriptors * If the item we are going to remove is inside the ready file descriptors
* we want to remove it from this list to avoid stale events. * we want to remove it from this list to avoid stale events.
...@@ -943,12 +988,13 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *dpi) ...@@ -943,12 +988,13 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *dpi)
if (EP_IS_LINKED(&dpi->rdllink)) if (EP_IS_LINKED(&dpi->rdllink))
EP_LIST_DEL(&dpi->rdllink); EP_LIST_DEL(&dpi->rdllink);
not_linked: error = 0;
eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %d)\n", DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %d) = %d\n",
current, ep, dpi->pfd.fd)); current, ep, dpi->pfd.fd, error));
return 0; return error;
} }
...@@ -961,6 +1007,22 @@ static int ep_remove(struct eventpoll *ep, struct epitem *dpi) ...@@ -961,6 +1007,22 @@ static int ep_remove(struct eventpoll *ep, struct epitem *dpi)
int error; int error;
unsigned long flags; unsigned long flags;
/*
* Removes poll wait queue hooks. We _have_ to do this without holding
* the "ep->lock" otherwise a deadlock might occur. This because of the
* sequence of the lock acquisition. Here we do "ep->lock" then the wait
* queue head lock when unregistering the wait queue. The wakeup callback
* will run by holding the wait queue head lock and will call our callback
* that will try to get "ep->lock".
*/
ep_unregister_pollwait(ep, dpi);
/* Remove the current item from the list of epoll hooks */
spin_lock(&dpi->file->f_ep_lock);
if (EP_IS_LINKED(&dpi->fllink))
EP_LIST_DEL(&dpi->fllink);
spin_unlock(&dpi->file->f_ep_lock);
/* We need to acquire the write IRQ lock before calling ep_unlink() */ /* We need to acquire the write IRQ lock before calling ep_unlink() */
write_lock_irqsave(&ep->lock, flags); write_lock_irqsave(&ep->lock, flags);
...@@ -972,14 +1034,14 @@ static int ep_remove(struct eventpoll *ep, struct epitem *dpi) ...@@ -972,14 +1034,14 @@ static int ep_remove(struct eventpoll *ep, struct epitem *dpi)
if (error) if (error)
goto eexit_1; goto eexit_1;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %d)\n",
current, ep, dpi->pfd.fd));
/* At this point it is safe to free the eventpoll item */ /* At this point it is safe to free the eventpoll item */
ep_release_epitem(dpi); ep_release_epitem(dpi);
error = 0; error = 0;
eexit_1: eexit_1:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %d) = %d\n",
current, ep, dpi->pfd.fd, error));
return error; return error;
} }
...@@ -1055,19 +1117,19 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) ...@@ -1055,19 +1117,19 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
/* /*
* Perform the transfer of events to user space. Optimize the copy by * Since we have to release the lock during the __copy_to_user() operation and
* caching EP_EVENT_BUFF_SIZE events at a time and then copying it to user space. * during the f_op->poll() call, we try to collect the maximum number of items
* by reducing the irqlock/irqunlock switching rate.
*/ */
static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents) static int ep_collect_ready_items(struct eventpoll *ep, struct epitem **adpi, int maxdpi)
{ {
int eventcnt, ebufcnt, revents; int ndpi;
unsigned long flags; unsigned long flags;
struct list_head *lsthead = &ep->rdllist; struct list_head *lsthead = &ep->rdllist;
struct pollfd eventbuf[EP_EVENT_BUFF_SIZE];
write_lock_irqsave(&ep->lock, flags); write_lock_irqsave(&ep->lock, flags);
for (eventcnt = 0, ebufcnt = 0; (eventcnt + ebufcnt) < maxevents && !list_empty(lsthead);) { for (ndpi = 0; ndpi < maxdpi && !list_empty(lsthead);) {
struct epitem *dpi = list_entry(lsthead->next, struct epitem, rdllink); struct epitem *dpi = list_entry(lsthead->next, struct epitem, rdllink);
/* Remove the item from the ready list */ /* Remove the item from the ready list */
...@@ -1081,41 +1143,112 @@ static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int m ...@@ -1081,41 +1143,112 @@ static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int m
if (!EP_IS_LINKED(&dpi->llink)) if (!EP_IS_LINKED(&dpi->llink))
continue; continue;
/* Fetch event bits from the signaled file */ /*
* We need to increase the usage count of the "struct epitem" because
* another thread might call EP_CTL_DEL on this target and make the
* object to vanish underneath our nose.
*/
ep_use_epitem(dpi);
adpi[ndpi++] = dpi;
}
write_unlock_irqrestore(&ep->lock, flags);
return ndpi;
}
/*
* This function is called without holding the "ep->lock" since the call to
* __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
* because of the way poll() is traditionally implemented in Linux.
*/
static int ep_send_events(struct eventpoll *ep, struct epitem **adpi, int ndpi,
struct pollfd *events)
{
int i, eventcnt, eventbuf, revents;
struct epitem *dpi;
struct pollfd pfd[EP_MAX_BUF_EVENTS];
for (i = 0, eventcnt = 0, eventbuf = 0; i < ndpi; i++, adpi++) {
dpi = *adpi;
/* Get the ready file event set */
revents = dpi->file->f_op->poll(dpi->file, NULL); revents = dpi->file->f_op->poll(dpi->file, NULL);
if (revents & dpi->pfd.events) { if (revents & dpi->pfd.events) {
eventbuf[ebufcnt] = dpi->pfd; pfd[eventbuf] = dpi->pfd;
eventbuf[ebufcnt].revents = revents & eventbuf[ebufcnt].events; pfd[eventbuf].revents = revents & pfd[eventbuf].events;
ebufcnt++; eventbuf++;
if (eventbuf == EP_MAX_BUF_EVENTS) {
/* If our buffer page is full we need to flush it to user space */ if (__copy_to_user(&events[eventcnt], pfd,
if (ebufcnt == EP_EVENT_BUFF_SIZE) { eventbuf * sizeof(struct pollfd))) {
/* for (; i < ndpi; i++, adpi++)
* We need to drop the irqlock before using the function ep_release_epitem(*adpi);
* __copy_to_user() because it might fault.
*/
write_unlock_irqrestore(&ep->lock, flags);
if (__copy_to_user(&events[eventcnt], eventbuf,
ebufcnt * sizeof(struct pollfd)))
return -EFAULT; return -EFAULT;
eventcnt += ebufcnt; }
ebufcnt = 0; eventcnt += eventbuf;
write_lock_irqsave(&ep->lock, flags); eventbuf = 0;
} }
} }
ep_release_epitem(dpi);
} }
write_unlock_irqrestore(&ep->lock, flags);
/* There might be still something inside our event buffer */ if (eventbuf) {
if (ebufcnt) { if (__copy_to_user(&events[eventcnt], pfd,
if (__copy_to_user(&events[eventcnt], eventbuf, eventbuf * sizeof(struct pollfd)))
ebufcnt * sizeof(struct pollfd))) return -EFAULT;
eventcnt = -EFAULT; eventcnt += eventbuf;
else }
eventcnt += ebufcnt;
return eventcnt;
}
/*
* Perform the transfer of events to user space.
*/
static int ep_events_transfer(struct eventpoll *ep, struct pollfd *events, int maxevents)
{
int eventcnt, ndpi, sdpi, maxdpi;
struct epitem *adpi[EP_MAX_COLLECT_ITEMS];
/*
* We need to lock this because we could be hit by
* ep_notify_file_close() while we're transfering
* events to userspace. Read-holding "epsem" will lock
* out ep_notify_file_close() during the whole
* transfer loop and this will garantie us that the
* file will not vanish underneath our nose when
* we will call f_op->poll() from ep_send_events().
*/
down_read(&epsem);
for (eventcnt = 0; eventcnt < maxevents;) {
/* Maximum items we can extract this time */
maxdpi = min(EP_MAX_COLLECT_ITEMS, maxevents - eventcnt);
/* Collect/extract ready items */
ndpi = ep_collect_ready_items(ep, adpi, maxdpi);
if (ndpi) {
/* Send events to userspace */
sdpi = ep_send_events(ep, adpi, ndpi, &events[eventcnt]);
if (sdpi < 0) {
up_read(&epsem);
return sdpi;
}
eventcnt += sdpi;
}
if (ndpi < maxdpi)
break;
} }
up_read(&epsem);
return eventcnt; return eventcnt;
} }
...@@ -1236,11 +1369,7 @@ static int __init eventpoll_init(void) ...@@ -1236,11 +1369,7 @@ static int __init eventpoll_init(void)
{ {
int error; int error;
/* Initialize the list that will link "struct eventpoll" */ init_rwsem(&epsem);
INIT_LIST_HEAD(&eplist);
/* Initialize the rwlock used to access "eplist" */
rwlock_init(&eplock);
/* Allocates slab cache used to allocate "struct epitem" items */ /* Allocates slab cache used to allocate "struct epitem" items */
error = -ENOMEM; error = -ENOMEM;
......
...@@ -50,6 +50,7 @@ struct file * get_empty_filp(void) ...@@ -50,6 +50,7 @@ struct file * get_empty_filp(void)
file_list_unlock(); file_list_unlock();
return NULL; return NULL;
} }
ep_init_file_struct(f);
atomic_set(&f->f_count,1); atomic_set(&f->f_count,1);
f->f_version = 0; f->f_version = 0;
f->f_uid = current->fsuid; f->f_uid = current->fsuid;
...@@ -94,6 +95,7 @@ struct file * get_empty_filp(void) ...@@ -94,6 +95,7 @@ struct file * get_empty_filp(void)
int init_private_file(struct file *filp, struct dentry *dentry, int mode) int init_private_file(struct file *filp, struct dentry *dentry, int mode)
{ {
memset(filp, 0, sizeof(*filp)); memset(filp, 0, sizeof(*filp));
ep_init_file_struct(filp);
filp->f_mode = mode; filp->f_mode = mode;
atomic_set(&filp->f_count, 1); atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry; filp->f_dentry = dentry;
...@@ -121,6 +123,10 @@ void __fput(struct file * file) ...@@ -121,6 +123,10 @@ void __fput(struct file * file)
struct vfsmount * mnt = file->f_vfsmnt; struct vfsmount * mnt = file->f_vfsmnt;
struct inode * inode = dentry->d_inode; struct inode * inode = dentry->d_inode;
/*
* The function ep_notify_file_close() should be the first called
* in the file cleanup chain.
*/
ep_notify_file_close(file); ep_notify_file_close(file);
locks_remove_flock(file); locks_remove_flock(file);
......
...@@ -163,7 +163,7 @@ static void devfs_register_partition(struct gendisk *dev, int part) ...@@ -163,7 +163,7 @@ static void devfs_register_partition(struct gendisk *dev, int part)
if (p[part-1].de) if (p[part-1].de)
return; return;
dir = devfs_get_parent(dev->disk_de); dir = dev->de;
if (!dir) if (!dir)
return; return;
if (dev->flags & GENHD_FL_REMOVABLE) if (dev->flags & GENHD_FL_REMOVABLE)
...@@ -178,7 +178,6 @@ static void devfs_register_partition(struct gendisk *dev, int part) ...@@ -178,7 +178,6 @@ static void devfs_register_partition(struct gendisk *dev, int part)
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER; static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
static devfs_handle_t cdroms;
static struct unique_numspace cdrom_numspace = UNIQUE_NUMBERSPACE_INITIALISER; static struct unique_numspace cdrom_numspace = UNIQUE_NUMBERSPACE_INITIALISER;
#endif #endif
...@@ -189,7 +188,6 @@ static void devfs_create_partitions(struct gendisk *dev) ...@@ -189,7 +188,6 @@ static void devfs_create_partitions(struct gendisk *dev)
devfs_handle_t dir, slave; devfs_handle_t dir, slave;
unsigned int devfs_flags = DEVFS_FL_DEFAULT; unsigned int devfs_flags = DEVFS_FL_DEFAULT;
char dirname[64], symlink[16]; char dirname[64], symlink[16];
static devfs_handle_t devfs_handle;
if (dev->flags & GENHD_FL_REMOVABLE) if (dev->flags & GENHD_FL_REMOVABLE)
devfs_flags |= DEVFS_FL_REMOVABLE; devfs_flags |= DEVFS_FL_REMOVABLE;
...@@ -206,19 +204,15 @@ static void devfs_create_partitions(struct gendisk *dev) ...@@ -206,19 +204,15 @@ static void devfs_create_partitions(struct gendisk *dev)
sprintf(dirname, "../%s/disc%d", dev->disk_name, sprintf(dirname, "../%s/disc%d", dev->disk_name,
dev->first_minor >> dev->minor_shift); dev->first_minor >> dev->minor_shift);
dir = devfs_mk_dir(NULL, dirname + 3, NULL); dir = devfs_mk_dir(NULL, dirname + 3, NULL);
dev->de = dir;
} }
if (!devfs_handle)
devfs_handle = devfs_mk_dir(NULL, "discs", NULL);
dev->number = devfs_alloc_unique_number (&disc_numspace); dev->number = devfs_alloc_unique_number (&disc_numspace);
sprintf(symlink, "disc%d", dev->number); sprintf(symlink, "discs/disc%d", dev->number);
devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT, devfs_mk_symlink(NULL, symlink, DEVFS_FL_DEFAULT,
dirname + pos, &slave, NULL); dirname + pos, &slave, NULL);
dev->disk_de = devfs_register(dir, "disc", devfs_flags, dev->disk_de = devfs_register(dir, "disc", devfs_flags,
dev->major, dev->first_minor, dev->major, dev->first_minor,
S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL); S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL);
devfs_auto_unregister(dev->disk_de, slave);
if (!(dev->flags & GENHD_FL_DEVFS))
devfs_auto_unregister (slave, dir);
#endif #endif
} }
...@@ -227,11 +221,8 @@ static void devfs_create_cdrom(struct gendisk *dev) ...@@ -227,11 +221,8 @@ static void devfs_create_cdrom(struct gendisk *dev)
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
char vname[23]; char vname[23];
if (!cdroms)
cdroms = devfs_mk_dir (NULL, "cdroms", NULL);
dev->number = devfs_alloc_unique_number(&cdrom_numspace); dev->number = devfs_alloc_unique_number(&cdrom_numspace);
sprintf(vname, "cdrom%d", dev->number); sprintf(vname, "cdroms/cdrom%d", dev->number);
if (dev->de) { if (dev->de) {
int pos; int pos;
devfs_handle_t slave; devfs_handle_t slave;
...@@ -245,10 +236,8 @@ static void devfs_create_cdrom(struct gendisk *dev) ...@@ -245,10 +236,8 @@ static void devfs_create_cdrom(struct gendisk *dev)
pos = devfs_generate_path(dev->disk_de, rname+3, sizeof(rname)-3); pos = devfs_generate_path(dev->disk_de, rname+3, sizeof(rname)-3);
if (pos >= 0) { if (pos >= 0) {
strncpy(rname + pos, "../", 3); strncpy(rname + pos, "../", 3);
devfs_mk_symlink(cdroms, vname, devfs_mk_symlink(NULL, vname, DEVFS_FL_DEFAULT,
DEVFS_FL_DEFAULT,
rname + pos, &slave, NULL); rname + pos, &slave, NULL);
devfs_auto_unregister(dev->de, slave);
} }
} else { } else {
dev->disk_de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT, dev->disk_de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT,
...@@ -264,10 +253,22 @@ static void devfs_remove_partitions(struct gendisk *dev) ...@@ -264,10 +253,22 @@ static void devfs_remove_partitions(struct gendisk *dev)
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
devfs_unregister(dev->disk_de); devfs_unregister(dev->disk_de);
dev->disk_de = NULL; dev->disk_de = NULL;
if (dev->flags & GENHD_FL_CD) if (dev->flags & GENHD_FL_CD) {
char name[64];
sprintf(name, "cdroms/cdrom%d", dev->number);
if (dev->de)
devfs_find_and_unregister(NULL, name, 0, 0, 0, 0);
devfs_dealloc_unique_number(&cdrom_numspace, dev->number); devfs_dealloc_unique_number(&cdrom_numspace, dev->number);
else } else {
char name[64];
sprintf(name, "discs/disc%d", dev->number);
devfs_find_and_unregister(NULL, name, 0, 0, 0, 0);
if (!(dev->flags & GENHD_FL_DEVFS)) {
devfs_unregister(dev->de);
dev->de = NULL;
}
devfs_dealloc_unique_number(&disc_numspace, dev->number); devfs_dealloc_unique_number(&disc_numspace, dev->number);
}
#endif #endif
} }
......
...@@ -54,7 +54,7 @@ struct poll_table_page { ...@@ -54,7 +54,7 @@ struct poll_table_page {
* poll table. * poll table.
*/ */
void poll_freewait(poll_table* pt) void __pollfreewait(poll_table* pt)
{ {
struct poll_table_page * p = pt->table; struct poll_table_page * p = pt->table;
while (p) { while (p) {
......
...@@ -88,7 +88,8 @@ extern void devfs_auto_unregister (devfs_handle_t master,devfs_handle_t slave); ...@@ -88,7 +88,8 @@ extern void devfs_auto_unregister (devfs_handle_t master,devfs_handle_t slave);
extern devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master); extern devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master);
extern const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen); extern const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen);
extern int devfs_only (void); extern int devfs_only (void);
extern void devfs_register_tape (devfs_handle_t de); extern int devfs_register_tape (devfs_handle_t de);
extern void devfs_unregister_tape(int num);
extern void devfs_register_series (devfs_handle_t dir, const char *format, extern void devfs_register_series (devfs_handle_t dir, const char *format,
unsigned int num_entries, unsigned int num_entries,
unsigned int flags, unsigned int major, unsigned int flags, unsigned int major,
...@@ -230,11 +231,13 @@ static inline int devfs_only (void) ...@@ -230,11 +231,13 @@ static inline int devfs_only (void)
{ {
return 0; return 0;
} }
static inline void devfs_register_tape (devfs_handle_t de) static inline int devfs_register_tape (devfs_handle_t de)
{
return -1;
}
static inline void devfs_unregister_tape(int num)
{ {
return;
} }
static inline void devfs_register_series (devfs_handle_t dir, static inline void devfs_register_series (devfs_handle_t dir,
const char *format, const char *format,
unsigned int num_entries, unsigned int num_entries,
......
...@@ -34,6 +34,9 @@ asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events); ...@@ -34,6 +34,9 @@ asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events);
asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents, asmlinkage int sys_epoll_wait(int epfd, struct pollfd *events, int maxevents,
int timeout); int timeout);
/* Used to initialize the epoll bits inside the "struct file" */
void ep_init_file_struct(struct file *file);
/* Used in fs/file_table.c:__fput() to unlink files from the eventpoll interface */ /* Used in fs/file_table.c:__fput() to unlink files from the eventpoll interface */
void ep_notify_file_close(struct file *file); void ep_notify_file_close(struct file *file);
......
...@@ -506,6 +506,10 @@ struct file { ...@@ -506,6 +506,10 @@ struct file {
/* needed for tty driver, and maybe others */ /* needed for tty driver, and maybe others */
void *private_data; void *private_data;
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
spinlock_t f_ep_lock;
}; };
extern spinlock_t files_lock; extern spinlock_t files_lock;
#define file_list_lock() spin_lock(&files_lock); #define file_list_lock() spin_lock(&files_lock);
......
...@@ -14,14 +14,17 @@ struct poll_table_page; ...@@ -14,14 +14,17 @@ struct poll_table_page;
struct poll_table_struct; struct poll_table_struct;
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
typedef void (*poll_free_proc)(struct poll_table_struct *);
typedef struct poll_table_struct { typedef struct poll_table_struct {
poll_queue_proc qproc; poll_queue_proc qproc;
poll_free_proc fproc;
int error; int error;
struct poll_table_page * table; struct poll_table_page * table;
} poll_table; } poll_table;
extern void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p); extern void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);
extern void __pollfreewait(poll_table* pt);
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{ {
...@@ -29,9 +32,10 @@ static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_addres ...@@ -29,9 +32,10 @@ static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_addres
p->qproc(filp, wait_address, p); p->qproc(filp, wait_address, p);
} }
static inline void poll_initwait_ex(poll_table* pt, poll_queue_proc qproc) static inline void poll_initwait_ex(poll_table* pt, poll_queue_proc qproc, poll_free_proc fproc)
{ {
pt->qproc = qproc; pt->qproc = qproc;
pt->fproc = fproc;
pt->error = 0; pt->error = 0;
pt->table = NULL; pt->table = NULL;
} }
...@@ -39,10 +43,15 @@ static inline void poll_initwait_ex(poll_table* pt, poll_queue_proc qproc) ...@@ -39,10 +43,15 @@ static inline void poll_initwait_ex(poll_table* pt, poll_queue_proc qproc)
static inline void poll_initwait(poll_table* pt) static inline void poll_initwait(poll_table* pt)
{ {
poll_initwait_ex(pt, __pollwait); poll_initwait_ex(pt, __pollwait, __pollfreewait);
} }
extern void poll_freewait(poll_table* pt); static inline void poll_freewait(poll_table* pt)
{
if (pt && pt->fproc)
pt->fproc(pt);
}
/* /*
......
...@@ -269,7 +269,7 @@ EXPORT_SYMBOL(generic_file_llseek); ...@@ -269,7 +269,7 @@ EXPORT_SYMBOL(generic_file_llseek);
EXPORT_SYMBOL(remote_llseek); EXPORT_SYMBOL(remote_llseek);
EXPORT_SYMBOL(no_llseek); EXPORT_SYMBOL(no_llseek);
EXPORT_SYMBOL(__pollwait); EXPORT_SYMBOL(__pollwait);
EXPORT_SYMBOL(poll_freewait); EXPORT_SYMBOL(__pollfreewait);
EXPORT_SYMBOL(ROOT_DEV); EXPORT_SYMBOL(ROOT_DEV);
EXPORT_SYMBOL(find_get_page); EXPORT_SYMBOL(find_get_page);
EXPORT_SYMBOL(find_lock_page); EXPORT_SYMBOL(find_lock_page);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment