Commit 16c82539 authored by Linus Torvalds's avatar Linus Torvalds

pre-patch-2.1.131-3

Ok,
 I've made a new pre-patch-2.1.131-3.

The basic problem (that Alexander Viro correctly diagnosed) is that the
inode locking was horribly and subtly wrong for the case of a "rmdir()"
call. What rmdir() did was essentially something like

 - VFS: lock the directory that contains the directory to remove
   (this is normal and required to make sure that the name updates are
   completely atomic - so removing or adding anything requires you to hold
   the lock on the directory that contains the removee/addee)
 - low-level filesystem: lock the directory you're going to remove, in
   order to atomically check that it's empty.

So far so good, the above makes tons of sense. HOWEVER, the problem is
fairly obvious if anybody before Alexander had actually bothered to think
about it: when we hold two locks, we had better make sure that we get the
locks in the right order, or we may end up deadlocked with two (or more)
processes getting the locks in the wrong order and waiting on each other.

Now, if it was only rmdir(), things would be fine, because the directory
hierarchy itself imposes a lock order for rmdir(). But we have another
case that needs to lock two directories: "rename()". And that one doesn't
have the same kind of obvious order, and uses a different way to order the
two locks it gets. BOOM.

As far as I can tell, this is a problem in 2.0.x too, but while it's a
potential really nasty DoS-opening, it does have the saving grace that the
window to trigger it is really really small. I don't know if you can
actually make an exploit for it that has any real chance of hitting it,
but it's at least conceptually possible.

Now, the only sane fix was to actually make the VFS layer do all the
locking for rmdir(), and thus let the VFS layer make sure the order is
correct, so that low-level filesystems don't need to worry their pretty
heads. I tried to do that in the previous pre-patch, and it worked well
for ext2, but not all that much else. The problem was that too many
filesystems "knew" what the rmdir() downcall used to do. Oh, well.

Anyway, I've fixed the low-level filesystems as far as I can tell, and the
end result is a much cleaner interface (and one less bug). But it's an
interface change at a fairly late date, and while the fixes to smbfs etc
looked for the most part obvious, I haven't been able to test them, so
I've done most of them "blind".

Sadly, this bug couldn't just be glossed over, because a normal user could
(by knowing the exact right incantation) force tons of unkillable
processes that held critical filesystem resources (any lookup on a
directory that was locked would in turn also lock up). So I'd ask people
who have done filesystems for Linux to look over my changes, and if the
filesystems are not part of the standard distribution please look over
your own locally maintained fs code. I think we can ignore 2.0.x by virtue
of it probably being virtually impossible to trigger. I'll leave the
decision up to Alan.

Most specially, I'd like to have people who use/maintain vfat and umsdos
filesystems to test out that I actually made those filesystems happy with
my changes. The other filesystems were more straightforward.

Oh, and thanks to Alexander. Not that I really needed another bug to fix,
but it feels good to plug holes.

                        Linus

The change is basically:
 - the VFS layer locks the directory to be removed for you (as opposed to
   just the directory that contains the directory to be removed as it used
   to). A lot of filesystems didn't actually do this, and it is required,
   because otherwise the test for an empty directory may be subverted by a
   clever hacker.
 - the VFS layer will have done a dcache "prune" operation on the
   directory, and if there were no other uses for that dcache entry, it
   will have done a "d_drop()" on it too.
 - the above essentially means that any filesystem can do a
        if (!list_empty(&dentry->d_hash))
                return -EBUSY;
   to test whether there are other users of this directory. No need to do
   any extra pruning etc - if it's been dropped there won't be any new
   users of the dentry afterwards, so there are no races. So after doing
   the above test you know that you'll have exclusive access to the dentry
   forever.
   Most notably, the low-level filesystem should _not_ look at the
   dentry->d_count member to see how many users there are. The VFS layer
   currently artificially raises the dentry count to make sure
   "d_delete()" doesn't get rid of the inode early.
 - however: traditional local UNIX-type filesystems tend to want to allow
   removing of the directory even if it is in use by something else. This
   requires that the inode be accessible even after the rmdir() - even
   though it doesn't necessarily need to actually _do_ anything.
   For a normal UNIX-like filesystem this tends to be trivial and quite
   automatic behaviour, but you need to think about whether your
   filesystem is of the kind where the inode stays around even after the
   delete until we locally do the final "iput()". For example, on
   networked filesystems this is generally not true, simply because the
   server will have de-allocated the inode even if we still have a
   reference to it locally.
parent b468356b
......@@ -8492,13 +8492,14 @@ CONFIG_JOYSTICK
The module will be called joystick.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
Classic PC analog joysticks
Classic PC analog joysticks and gamepads
CONFIG_JOY_ANALOG
Say Y here if you have an analog joystick or gamepad that connects
to the PC gameport. This supports many different types, including
joysticks with throttle control, and with CHF / FCS / 6-button
extensions. For more information on how to use the driver please
read Documentation/joystick.txt
joysticks with throttle control, with rudders, or with extensions
like additional hats and buttons compatible with CH Flightstick Pro,
ThrustMaster FCS or 6 and 8 button gamepads. For more information on
how to use the driver please read Documentation/joystick.txt
FPGaming and MadCatz A3D controllers
CONFIG_JOY_ASSASIN
......@@ -8506,25 +8507,26 @@ CONFIG_JOY_ASSASIN
MadCatz Panther XL. For more information on how to use the driver
please read Documentation/joystick.txt
Gravis GrIP gamepads
Gravis GrIP joysticks and gamepads
CONFIG_JOY_GRAVIS
Say Y here if you have a Gravis GamePad Pro. For more information
on how to use the driver please read Documentation/joystick.txt
Say Y here if you have a Gravis GamePad Pro, Gravis Xterminator or
Gravis Blackhawk Digital. For more information on how to use the
driver please read Documentation/joystick.txt
PDPI Lightning L4 gamecards
PDPI Lightning 4 gamecards
CONFIG_JOY_LIGHTNING
Say Y here if you have a PDPI Lightning L4 gamecard and an analog
Say Y here if you have a PDPI Lightning 4 gamecard and an analog
joystick or gamepad connected to it. For more information on how to
use the driver please read Documentation/joystick.txt
Logitech Digital joysticks
Logitech Digital joysticks and gamepads
CONFIG_JOY_LOGITECH
Say Y here if you have a Logitech WingMan Extreme Digital,
Logitech ThunderPad Digital or Logitech CyberMan 2. For more
information on how to use the driver please read
Documentation/joystick.txt
Microsoft SideWinder, Genius Digital joysticks
Microsoft SideWinder, Genius Digital joysticks and gamepads
CONFIG_JOY_SIDEWINDER
Say Y here if you have a Microsoft SideWinder 3d Pro, Microsoft
SideWinder Precision Pro, Microsoft SideWinder Force Feedback Pro,
......@@ -8532,34 +8534,35 @@ CONFIG_JOY_SIDEWINDER
more information on how to use the driver please read
Documentation/joystick.txt
ThrustMaster DirectConnect (BSP) joysticks
ThrustMaster DirectConnect joysticks and gamepads
CONFIG_JOY_THRUSTMASTER
Say Y here if you have a ThrustMaster Millenium 3D Inceptor,
ThrustMaster 3D Rage Pad, or ThrustMaster WCS III. For more
information on how to use the driver please read
Documentation/joystick.txt
Say Y here if you have a ThrustMaster Millenium 3D Inceptor or a
ThrustMaster 3D Rage Pad. For more information on how to use the
driver please read Documentation/joystick.txt
NES, SNES, PSX, Multisystem gamepads
NES, SNES, PSX, Multisystem joysticks and gamepads
CONFIG_JOY_CONSOLE
Say Y here if you have a Nintendo Entertainment System gamepad,
Super Nintendo Entertainment System gamepad, Sony PlayStation
gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC
joystick. For more information on how to use the driver please read
Documentation/joystick.txt
Documentation/joystick.txt and Documentation/joystick-parport.txt
Sega, Multisystem gamepads
Sega, Multisystem joysticks and gamepads
CONFIG_JOY_DB9
Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
Commodore, Amstrad CPC joystick. For more information on how to use
the driver please read Documentation/joystick.txt
the driver please read Documentation/joystick.txt and
Documentation/joystick-parport.txt
TurboGraFX Multisystem joystick interface
CONFIG_JOY_TURBOGRAFX
Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
and want to use it with Multiststem -- Atari, Amiga, Commodore,
Amstrad CPC joystick. For more information on how to use the driver
please read Documentation/joystick-parport.txt
please read Documentation/joystick-parport.txt and
Documentation/joystick-parport.txt
Amiga joysticks
CONFIG_JOY_AMIGA
......
......@@ -506,14 +506,14 @@ more joysticks/pads.
~~~~~~~~~~~~~~~~~~~~
The joy-turbografx.c driver uses a very simple kernel/module command line:
js_tg=port,count
js_tg=port,js1,js2,js3,js4,js5,js6,js7
Where 'port' is either the address of the parallel port the interface is
connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
Linux kernels, the number of the parport interface (eg. 0 for parport0).
'Count' is the number of Multisystem, 1-button joysticks connected to the
interface.
'jsX' is the number of buttons the Multisystem joysticks connected to the
interface ports 1-7 have. For a standard multisystem joystick, this is 1.
Should you want to use more than one of these interfaces at once, you can
use js_tg_2 and js_tg_3 as additional command line parameters for two more
......
This diff is collapsed.
......@@ -2,16 +2,16 @@
# Joystick lowlevel driver configuration
#
dep_tristate ' Classic PC analog joysticks' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
dep_tristate ' Gravis GrIP gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
dep_tristate ' Logitech Digital joysticks' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
dep_tristate ' Microsoft SideWinder, Genius Digital joysticks' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
dep_tristate ' ThrustMaster DirectConnect (BSP) joysticks' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
dep_tristate ' PDPI Lightning L4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate ' NES, SNES, PSX, Multisystem gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK
dep_tristate ' Sega, Multisystem gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK
dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK
dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK
dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
......
......@@ -148,8 +148,8 @@ int __init js_am_init(void)
#ifdef MODULE
void cleanup_module(void)
{
while (js_am_port) {
if (js_am_port->devs[0])
while (js_am_port != NULL) {
if (js_am_port->devs[0] != NULL)
js_unregister_device(js_am_port->devs[0]);
js_am_port = js_unregister_port(js_am_port);
}
......
......@@ -195,9 +195,9 @@ void cleanup_module(void)
int i;
struct js_an_info *info;
while (js_an_port) {
while (js_an_port != NULL) {
for (i = 0; i < js_an_port->ndevs; i++)
if (js_an_port->devs[i])
if (js_an_port->devs[i] != NULL)
js_unregister_device(js_an_port->devs[i]);
info = js_an_port->info;
release_region(info->io, 1);
......
......@@ -410,9 +410,9 @@ void cleanup_module(void)
int i;
struct js_as_info *info;
while (js_as_port) {
while (js_as_port != NULL) {
for (i = 0; i < js_as_port->ndevs; i++)
if (js_as_port->devs[i])
if (js_as_port->devs[i] != NULL)
js_unregister_device(js_as_port->devs[i]);
info = js_as_port->info;
release_region(info->io, 1);
......
......@@ -373,9 +373,9 @@ void cleanup_module(void)
struct js_console_info *info;
int i;
while (js_console_port) {
while (js_console_port != NULL) {
for (i = 0; i < js_console_port->ndevs; i++)
if (js_console_port->devs[i])
if (js_console_port->devs[i] != NULL)
js_unregister_device(js_console_port->devs[i]);
info = js_console_port->info;
#ifdef USE_PARPORT
......@@ -428,11 +428,11 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
struct parport *pp;
if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) {
if (pp == NULL) {
printk(KERN_ERR "joy-console: no such parport\n");
return port;
}
......
......@@ -38,8 +38,8 @@
MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
MODULE_PARM(js_db9, "2i");
MODULE_PARM(js_db9_2, "0-2i");
MODULE_PARM(js_db9_3, "0-2i");
MODULE_PARM(js_db9_2, "2i");
MODULE_PARM(js_db9_3, "2i");
#define JS_MULTI_STICK 0x01
#define JS_MULTI2_STICK 0x02
......@@ -227,42 +227,6 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons)
return 0;
}
/*
* js_db9_enable_ps2() enables PS/2 capabilities on a parallel port and
* switches data lines to input mode. We should use parport_change_mode() for
* that if parport present - unfortunately that does nothing and only contains
* a FIXME comment.
*/
static inline void js_db9_enable_ps2(struct js_db9_info *info)
{
#ifdef USE_PARPORT
int io = info->port->port->base;
#else
int io = info->port;
#endif
outb(0x35,io+0x402); /* enable PS/2 mode: */
outb(JS_DB9_NORMAL,io+2); /* reverse direction, enable Select signal: */
}
/*
* js_db9_disable_ps2() disables PS/2 capabilities on a parallel port
* and restores it to standard mode.
*/
static inline void js_db9_disable_ps2(struct js_db9_info *info)
{
#ifdef USE_PARPORT
int io = info->port->port->base;
#else
int io = info->port;
#endif
outb(0,io+2); /* normal direction */
outb(0x15,io+0x402); /* enable normal mode */
}
/*
* open callback: claim parport.
*/
......@@ -275,7 +239,9 @@ int js_db9_open(struct js_dev *dev)
#ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY;
#endif
js_db9_enable_ps2(info);
JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */
JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */
}
MOD_INC_USE_COUNT;
......@@ -293,7 +259,10 @@ int js_db9_close(struct js_dev *dev)
MOD_DEC_USE_COUNT;
if (!MOD_IN_USE) {
js_db9_disable_ps2(info);
JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */
JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */
#ifdef USE_PARPORT
parport_release(info->port);
#endif
......@@ -306,7 +275,7 @@ void cleanup_module(void)
{
struct js_db9_info *info;
while (js_db9_port) {
while (js_db9_port != NULL) {
js_unregister_device(js_db9_port->devs[0]);
info = js_db9_port->info;
#ifdef USE_PARPORT
......@@ -359,11 +328,11 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
struct parport *pp;
if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) {
if (pp == NULL) {
printk(KERN_ERR "joy-db9: no such parport\n");
return port;
}
......
......@@ -43,6 +43,7 @@
#define JS_GR_STROBE_GPP 75
#define JS_GR_MODE_XT 2
#define JS_GR_MODE_BD 3
#define JS_GR_LENGTH_XT 4
#define JS_GR_STROBE_XT 30
#define JS_GR_MAX_CHUNKS_XT 10
......@@ -189,9 +190,10 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons)
axes[i][0] = (data[0] >> 2) & 0x3f;
axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
axes[i][2] = (data[1] >> 2) & 0x3f;
axes[i][3] = (data[1] >> 8) & 0x3f;
axes[i][4] = (data[2] >> 8) & 0x3f;
axes[i][2] = (data[1] >> 2) & 0x3f;
axes[i][3] = (data[1] >> 8) & 0x3f;
axes[i][4] = (data[2] >> 8) & 0x3f;
axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1);
axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1);
......@@ -201,6 +203,22 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons)
break;
case JS_GR_MODE_BD:
if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
axes[i][0] = (data[0] >> 2) & 0x3f;
axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
axes[i][2] = (data[2] >> 8) & 0x3f;
axes[i][3] = ((data[2] >> 1) & 1) - ( data[2] & 1);
axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06)
| ((data[3] >> 4) & 0x18);
break;
default:
break;
......@@ -276,6 +294,28 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr)
break;
case JS_GR_MODE_BD:
for (i = 0; i < 3; i++) {
corr[i].type = JS_CORR_BROKEN;
corr[i].prec = 0;
corr[i].coef[0] = 31 - 4;
corr[i].coef[1] = 32 + 4;
corr[i].coef[2] = (1 << 29) / (32 - 14);
corr[i].coef[3] = (1 << 29) / (32 - 14);
}
for (i = 3; i < 5; i++) {
corr[i].type = JS_CORR_BROKEN;
corr[i].prec = 0;
corr[i].coef[0] = 0;
corr[i].coef[1] = 0;
corr[i].coef[2] = (1 << 29);
corr[i].coef[3] = (1 << 29);
}
break;
}
}
......@@ -286,9 +326,9 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr)
static struct js_port __init *js_gr_probe(int io, struct js_port *port)
{
struct js_gr_info info;
char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator" };
char axes[] = { 0, 2, 9 };
char buttons[] = { 0, 10, 11 };
char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
char axes[] = { 0, 2, 9, 5};
char buttons[] = { 0, 10, 11, 5};
unsigned int data[JS_GR_LENGTH_XT];
int i;
......@@ -298,7 +338,12 @@ static struct js_port __init *js_gr_probe(int io, struct js_port *port)
for (i = 0; i < 2; i++) {
if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP;
if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_XT;
if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) {
if ((data[3] & 7) == 7)
info.mode[i] = JS_GR_MODE_XT;
if ((data[3] & 7) == 0)
info.mode[i] = JS_GR_MODE_BD;
}
}
if (!info.mode[0] && !info.mode[1]) return port;
......@@ -344,9 +389,9 @@ void cleanup_module(void)
int i;
struct js_gr_info *info;
while (js_gr_port) {
while (js_gr_port != NULL) {
for (i = 0; i < js_gr_port->ndevs; i++)
if (js_gr_port->devs[i])
if (js_gr_port->devs[i] != NULL)
js_unregister_device(js_gr_port->devs[i]);
info = js_gr_port->info;
release_region(info->io, 1);
......
......@@ -352,9 +352,9 @@ void cleanup_module(void)
int cal[4] = {59, 59, 59, 59};
struct js_l4_info *info;
while (js_l4_port) {
while (js_l4_port != NULL) {
for (i = 0; i < js_l4_port->ndevs; i++)
if (js_l4_port->devs[i])
if (js_l4_port->devs[i] != NULL)
js_unregister_device(js_l4_port->devs[i]);
info = js_l4_port->info;
js_l4_setcal(info->port, cal);
......
......@@ -361,7 +361,7 @@ void cleanup_module(void)
{
struct js_lt_info *info;
while (js_lt_port) {
while (js_lt_port != NULL) {
js_unregister_device(js_lt_port->devs[0]);
info = js_lt_port->info;
release_region(info->io, 1);
......
......@@ -88,6 +88,11 @@ static void __init js_sw_init_digital(int io)
} while (delays[i++]);
__restore_flags(flags);
for (i = 0; i < 4; i++) {
udelay(300);
outb(0xff, io);
}
return;
}
......@@ -137,19 +142,21 @@ static int js_sw_read_packet(int io, int l1, int l2, int strobe, __u64 *data)
__restore_flags(flags);
*data = 0;
t = i;
if (t == l1) {
if (i == l1) {
t = i > 64 ? 64 : i;
for (i = 0; i < t; i++)
*data |= (__u64) (buf[i] & 1) << i;
return t;
}
if (t == l2) {
if (i == l2) {
t = i > 22 ? 22 : i;
for (i = 0; i < t; i++)
*data |= (__u64) buf[i] << (3 * i);
return t * 3;
}
return t;
return i;
}
/*
......@@ -199,7 +206,7 @@ static int js_sw_read(void *xinfo, int **axes, int **buttons)
i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data);
} else {
i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data);
if (i == 192) info->optimize = 1;
if (i == 198) info->optimize = 1;
}
if (i < 60) {
......@@ -456,9 +463,9 @@ void cleanup_module(void)
int i;
struct js_sw_info *info;
while (js_sw_port) {
while (js_sw_port != NULL) {
for (i = 0; i < js_sw_port->ndevs; i++)
if (js_sw_port->devs[i])
if (js_sw_port->devs[i] != NULL)
js_unregister_device(js_sw_port->devs[i]);
info = js_sw_port->info;
release_region(info->io, 1);
......
......@@ -39,12 +39,12 @@
#include <linux/module.h>
#include <linux/string.h>
#define JS_TM_MAX_START 200
#define JS_TM_MAX_STROBE 15
#define JS_TM_MAX_START 400
#define JS_TM_MAX_STROBE 25
#define JS_TM_MAX_LENGTH 13
#define JS_TM_MODE_M3DI 1
#define JS_TM_MODE_3DRP 2
#define JS_TM_MODE_3DRP 3
#define JS_TM_MODE_WCS3 4
#define JS_TM_MODE_MAX 5 /* Last mode + 1 */
......@@ -73,7 +73,7 @@ struct js_tm_info {
unsigned char mode;
};
static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x22, 0x00, 0x00};
static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x00, 0x22, 0x00};
/*
* js_tm_read_packet() reads a ThrustMaster packet.
......@@ -120,6 +120,7 @@ static int js_tm_read_packet(int io, unsigned char *data)
i++;
}
} else { /* Start bit */
data[i] = 0;
error |= ~v & 1;
j++;
}
......@@ -251,10 +252,10 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js
static struct js_port __init *js_tm_probe(int io, struct js_port *port)
{
struct js_tm_info info;
char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor",
"ThrustMaster Rage 3D Gamepad", NULL, "ThrustMaster WCS III" };
char axes[JS_TM_MODE_MAX] = { 0, 6, 2, 0, 0 };
char buttons[JS_TM_MODE_MAX] = { 0, 5, 10, 0, 0 };
char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", NULL,
"ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" };
char axes[JS_TM_MODE_MAX] = { 0, 6, 0, 2, 0 };
char buttons[JS_TM_MODE_MAX] = { 0, 5, 0, 10, 0 };
unsigned char data[JS_TM_MAX_LENGTH];
unsigned char u;
......@@ -320,7 +321,7 @@ void cleanup_module(void)
{
struct js_tm_info *info;
while (js_tm_port) {
while (js_tm_port != NULL) {
js_unregister_device(js_tm_port->devs[0]);
info = js_tm_port->info;
release_region(info->io, 1);
......
......@@ -42,21 +42,26 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_PARM(js_tg, "2i");
MODULE_PARM(js_tg_2, "0-2i");
MODULE_PARM(js_tg_3, "0-2i");
MODULE_PARM(js_tg, "2-8i");
MODULE_PARM(js_tg_2, "2-8i");
MODULE_PARM(js_tg_3, "2-8i");
#define JS_TG_BUTTON 3
#define JS_TG_UP 4
#define JS_TG_DOWN 5
#define JS_TG_LEFT 6
#define JS_TG_RIGHT 7
#define JS_TG_BUTTON1 0x08
#define JS_TG_UP 0x10
#define JS_TG_DOWN 0x20
#define JS_TG_LEFT 0x40
#define JS_TG_RIGHT 0x80
#define JS_TG_BUTTON2 0x02
#define JS_TG_BUTTON3 0x04
#define JS_TG_BUTTON4 0x01
#define JS_TG_BUTTON5 0x08
static struct js_port* js_tg_port = NULL;
static int js_tg[] __initdata = { -1, 0 };
static int js_tg_2[] __initdata = { -1, 0 };
static int js_tg_3[] __initdata = { -1, 0 };
static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
struct js_tg_info {
#ifdef USE_PARPORT
......@@ -64,7 +69,7 @@ struct js_tg_info {
#else
int port; /* hw port */
#endif
int count; /* number of joysticks */
int sticks; /* joysticks connected */
};
/*
......@@ -74,17 +79,21 @@ struct js_tg_info {
static int js_tg_read(void *xinfo, int **axes, int **buttons)
{
struct js_tg_info *info = xinfo;
int data, i;
int data1, data2, i;
for (i = 0; i < info->count; i++) {
for (i = 0; i < 7; i++)
if ((info->sticks >> i) & 1) {
JS_PAR_DATA_OUT(~(1 << i), info->port);
data = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT;
axes[i][0] = ((data >> JS_TG_RIGHT) & 1) - ((data >> JS_TG_LEFT) & 1);
axes[i][1] = ((data >> JS_TG_DOWN ) & 1) - ((data >> JS_TG_UP ) & 1);
axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0);
axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP ) ? 1 : 0);
buttons[i][0] = (data >> JS_TG_BUTTON) & 1;
buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0)
| ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0)
| ((data2 & JS_TG_BUTTON5) ? 0x10 : 0);
}
......@@ -97,10 +106,14 @@ static int js_tg_read(void *xinfo, int **axes, int **buttons)
int js_tg_open(struct js_dev *dev)
{
#ifdef USE_PARPORT
struct js_tg_info *info = dev->port->info;
if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
if (!MOD_IN_USE) {
#ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY;
#endif
JS_PAR_CTRL_OUT(0x04, info->port);
}
MOD_INC_USE_COUNT;
return 0;
}
......@@ -111,13 +124,15 @@ int js_tg_open(struct js_dev *dev)
int js_tg_close(struct js_dev *dev)
{
#ifdef USE_PARPORT
struct js_tg_info *info = dev->port->info;
#endif
MOD_DEC_USE_COUNT;
if (!MOD_IN_USE) {
JS_PAR_CTRL_OUT(0x00, info->port);
#ifdef USE_PARPORT
if (!MOD_IN_USE) parport_release(info->port);
parport_release(info->port);
#endif
}
return 0;
}
......@@ -127,9 +142,9 @@ void cleanup_module(void)
struct js_tg_info *info;
int i;
while (js_tg_port) {
while (js_tg_port != NULL) {
for (i = 0; i < js_tg_port->ndevs; i++)
if (js_tg_port->devs[i])
if (js_tg_port->devs[i] != NULL)
js_unregister_device(js_tg_port->devs[i]);
info = js_tg_port->info;
#ifdef USE_PARPORT
......@@ -147,19 +162,20 @@ void cleanup_module(void)
* tg gamepads.
*/
static void __init js_tg_init_corr(int count, struct js_corr **corr)
static void __init js_tg_init_corr(int sticks, struct js_corr **corr)
{
int i, j;
for (i = 0; i < count; i++)
for (j = 0; j < 2; j++) {
corr[i][j].type = JS_CORR_BROKEN;
corr[i][j].prec = 0;
corr[i][j].coef[0] = 0;
corr[i][j].coef[1] = 0;
corr[i][j].coef[2] = (1 << 29);
corr[i][j].coef[3] = (1 << 29);
}
for (i = 0; i < 7; i++)
if ((sticks >> i) & 1)
for (j = 0; j < 2; j++) {
corr[i][j].type = JS_CORR_BROKEN;
corr[i][j].prec = 0;
corr[i][j].coef[0] = 0;
corr[i][j].coef[1] = 0;
corr[i][j].coef[2] = (1 << 29);
corr[i][j].coef[3] = (1 << 29);
}
}
/*
......@@ -168,53 +184,65 @@ static void __init js_tg_init_corr(int count, struct js_corr **corr)
static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
{
struct js_tg_info info;
struct js_tg_info iniinfo;
struct js_tg_info *info = &iniinfo;
int i;
if (config[0] < 0) return port;
if (config[1] < 1 || config[1] > 8) return port;
#ifdef USE_PARPORT
{
struct parport *pp;
if (config[0] > 0x10)
for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
else
for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
if (!pp) {
if (pp == NULL) {
printk(KERN_ERR "joy-tg: no such parport\n");
return port;
}
info.port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!info.port)
info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
if (!info->port)
return port;
}
#else
info.port = config[0];
if (check_region(info.port, 3)) return port;
request_region(info.port, 3, "joystick (turbografx)");
info->port = config[0];
if (check_region(info->port, 3)) return port;
request_region(info->port, 3, "joystick (turbografx)");
#endif
info.count = config[1];
port = js_register_port(port, &info, info.count, sizeof(struct js_tg_info), js_tg_read);
port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
info = port->info;
info->sticks = 0;
for (i = 0; i < info.count; i++)
for (i = 0; i < 7; i++)
if (config[i+1] > 0 && config[i+1] < 6) {
#ifdef USE_PARPORT
printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
js_register_device(port, i, 2, 1, "Multisystem joystick", js_tg_open, js_tg_close),
info.port->port->name);
printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
info->port->port->name);
#else
printk(KERN_INFO "js%d: Multisystem joystick at %#x\n",
js_register_device(port, i, 2, 1, "Multisystem joystick", js_tg_open, js_tg_close),
info.port);
printk(KERN_INFO "js%d: Multisystem joystick at %#x\n",
js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
info->port);
#endif
info->sticks |= (1 << i);
}
js_tg_init_corr(info.count, port->corr);
if (!info->sticks) {
#ifdef USE_PARPORT
parport_unregister_device(info->port);
#else
release_region(info->port, 3);
#endif
return port;
}
js_tg_init_corr(info->sticks, port->corr);
return port;
}
......
......@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
......@@ -456,14 +457,14 @@ static void js_do_timer(unsigned long data)
struct js_dev *curd = js_dev;
unsigned long flags;
while (curp) {
while (curp != NULL) {
curp->read(curp->info, curp->axes, curp->buttons);
curp = curp->next;
}
spin_lock_irqsave(&js_lock, flags);
while (curd) {
while (curd != NULL) {
if (data) {
js_process_data(curd);
js_sync_buff(curd);
......@@ -643,12 +644,12 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
if (orig_tail == jd->tail) {
new_tail = curl->tail;
curl = jd->list;
while (curl && curl->tail != jd->tail) {
while (curl != NULL && curl->tail != jd->tail) {
if (ROT(jd->bhead, new_tail, curl->tail) ||
(jd->bhead == curl->tail)) new_tail = curl->tail;
curl = curl->next;
}
if (!curl) jd->tail = new_tail;
if (curl == NULL) jd->tail = new_tail;
}
spin_unlock_irqrestore(&js_lock, flags);
......@@ -855,42 +856,51 @@ static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
static int js_open(struct inode *inode, struct file *file)
{
struct js_list *curl;
struct js_list *curl, *new;
struct js_dev *jd = js_dev;
int i = MINOR(inode->i_rdev);
unsigned long flags;
int result;
int result;
if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
return -EINVAL;
while (i > 0 && jd) {
spin_lock_irqsave(&js_lock, flags);
while (i > 0 && jd != NULL) {
jd = jd->next;
i--;
}
if (!jd) return -ENODEV;
spin_unlock_irqrestore(&js_lock, flags);
if (jd == NULL) return -ENODEV;
if ((result = jd->open(jd))) return result;
MOD_INC_USE_COUNT;
if (!js_use_count++) js_do_timer(0);
curl = jd->list;
if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL)) != NULL) {
spin_lock_irqsave(&js_lock, flags);
spin_lock_irqsave(&js_lock, flags);
jd->list = kmalloc(sizeof(struct js_list), GFP_KERNEL);
jd->list->next = curl;
jd->list->dev = jd;
jd->list->startup = 0;
jd->list->tail = GOB(jd->bhead);
curl = jd->list;
spin_unlock_irqrestore(&js_lock, flags);
jd->list = new;
jd->list->next = curl;
jd->list->dev = jd;
jd->list->startup = 0;
jd->list->tail = GOB(jd->bhead);
file->private_data = jd->list;
file->private_data = jd->list;
spin_unlock_irqrestore(&js_lock, flags);
return 0;
} else {
result = -ENOMEM;
}
return result;
}
/*
......@@ -915,11 +925,11 @@ static void js_release(struct inode *inode, struct file *file)
while (*curp && (*curp != curl)) curp = &((*curp)->next);
*curp = (*curp)->next;
if (jd->list)
if (jd->list != NULL)
if (curl->tail == jd->tail) {
curl = jd->list;
new_tail = curl->tail;
while (curl && curl->tail != jd->tail) {
while (curl != NULL && curl->tail != jd->tail) {
if (ROT(jd->bhead, new_tail, curl->tail) ||
(jd->bhead == curl->tail)) new_tail = curl->tail;
curl = curl->next;
......@@ -957,7 +967,7 @@ static void js_dump_mem(void)
printk(",--- Dumping Devices:\n");
printk("| js_dev = %x\n", (int) js_dev);
while (curd) {
while (curd != NULL) {
printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
curd->next ? "|":"`",
(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
......@@ -967,7 +977,7 @@ static void js_dump_mem(void)
printk(">--- Dumping ports:\n");
printk("| js_port = %x\n", (int) js_port);
while (curp) {
while (curp != NULL) {
printk("| %s-port %x, next %x, io %#x, devices %d\n",
curp->next ? "|":"`",
(int) curp, (int) curp->next, curp->io, curp->ndevs);
......@@ -995,35 +1005,39 @@ struct js_port *js_register_port(struct js_port *port,
{
struct js_port **ptrp = &js_port;
struct js_port *curp;
void *all;
int i;
unsigned long flags;
spin_lock_irqsave(&js_lock, flags);
if ((all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)) == NULL)
return NULL;
while (*ptrp) ptrp=&((*ptrp)->next);
*ptrp = curp = kmalloc(sizeof(struct js_port), GFP_KERNEL);
curp = all;
curp->next = NULL;
curp->prev = port;
curp->read = read;
curp->ndevs = devs;
curp->devs = kmalloc(devs * sizeof(struct js_dev*), GFP_KERNEL);
for (i = 0; i < devs; i++)
curp->devs[i] = NULL;
curp->devs = all += sizeof(struct js_port);
for (i = 0; i < devs; i++) curp->devs[i] = NULL;
curp->axes = kmalloc(devs * sizeof(int*), GFP_KERNEL);
curp->buttons = kmalloc(devs * sizeof(int*), GFP_KERNEL);
curp->corr = kmalloc(devs * sizeof(struct js_corr*), GFP_KERNEL);
curp->axes = all += devs * sizeof(void*);
curp->buttons = (void*) all += devs * sizeof(void*);
curp->corr = all += devs * sizeof(void*);
if (infos) {
curp->info = kmalloc(infos, GFP_KERNEL);
curp->info = all += devs * sizeof(void*);
memcpy(curp->info, info, infos);
} else {
curp->info = NULL;
}
spin_lock_irqsave(&js_lock, flags);
while (*ptrp != NULL) ptrp=&((*ptrp)->next);
*ptrp = curp;
spin_unlock_irqrestore(&js_lock, flags);
return curp;
......@@ -1037,19 +1051,14 @@ struct js_port *js_unregister_port(struct js_port *port)
spin_lock_irqsave(&js_lock, flags);
while (*curp && (*curp != port)) curp = &((*curp)->next);
while (*curp != NULL && (*curp != port)) curp = &((*curp)->next);
*curp = (*curp)->next;
spin_unlock_irqrestore(&js_lock, flags);
prev = port->prev;
kfree(port->devs);
kfree(port->axes);
kfree(port->buttons);
kfree(port->corr);
if (port->info) kfree(port->info);
kfree(port);
spin_unlock_irqrestore(&js_lock, flags);
return prev;
}
......@@ -1058,17 +1067,16 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
{
struct js_dev **ptrd = &js_dev;
struct js_dev *curd;
void *all;
int i = 0;
unsigned long flags;
spin_lock_irqsave(&js_lock, flags);
while (*ptrd) {
ptrd=&(*ptrd)->next;
i++;
}
if ((all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)) == NULL)
return -1;
*ptrd = curd = kmalloc(sizeof(struct js_dev), GFP_KERNEL);
curd = all;
curd->next = NULL;
curd->list = NULL;
......@@ -1083,20 +1091,25 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
curd->num_axes = axes;
curd->num_buttons = buttons;
curd->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
strcpy(curd->name, name);
curd->cur.axes = all += sizeof(struct js_dev);
curd->cur.buttons = all += axes * sizeof(int);
curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int);
curd->new.buttons = all += axes * sizeof(int);
curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int);
curd->cur.axes = kmalloc(axes * sizeof(int), GFP_KERNEL);
curd->cur.buttons = kmalloc((((buttons - 1) >> 5) + 1) * sizeof(int), GFP_KERNEL);
curd->new.axes = kmalloc(axes * sizeof(int), GFP_KERNEL);
curd->new.buttons = kmalloc((((buttons -1 ) >> 5) + 1) * sizeof(int), GFP_KERNEL);
curd->corr = kmalloc(axes * sizeof(struct js_corr), GFP_KERNEL);
curd->name = all += axes * sizeof(struct js_corr);
strcpy(curd->name, name);
port->devs[number] = curd;
port->axes[number] = curd->new.axes;
port->buttons[number] = curd->new.buttons;
port->corr[number] = curd->corr;
spin_lock_irqsave(&js_lock, flags);
while (*ptrd != NULL) { ptrd=&(*ptrd)->next; i++; }
*ptrd = curd;
spin_unlock_irqrestore(&js_lock, flags);
return i;
......@@ -1109,17 +1122,11 @@ void js_unregister_device(struct js_dev *dev)
spin_lock_irqsave(&js_lock, flags);
while (*curd && (*curd != dev)) curd = &((*curd)->next);
while (*curd != NULL && (*curd != dev)) curd = &((*curd)->next);
*curd = (*curd)->next;
spin_unlock_irqrestore(&js_lock, flags);
kfree(dev->cur.axes);
kfree(dev->new.axes);
kfree(dev->cur.buttons);
kfree(dev->new.buttons);
kfree(dev->corr);
kfree(dev->name);
kfree(dev);
}
......
......@@ -374,13 +374,11 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
/*
* Make sure the directory is empty and the dentry isn't busy.
*/
if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
retval = -ENOTEMPTY;
if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
goto rmdir_done;
retval = -EBUSY;
if (dentry->d_count > 1)
if (!list_empty(&dentry->d_hash))
goto rmdir_done;
if ((retval = affs_remove_header(bh,inode)) < 0)
......
......@@ -520,7 +520,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
struct coda_inode_info *dircnp;
const char *name = de->d_name.name;
int len = de->d_name.len;
int error, rehash = 0;
int error;
ENTRY;
coda_vfs_stat.rmdir++;
......@@ -535,24 +535,13 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
if (len > CFS_MAXNAMLEN)
return -ENAMETOOLONG;
error = -EBUSY;
if (de->d_count > 1) {
/* Attempt to shrink child dentries ... */
shrink_dcache_parent(de);
if (de->d_count > 1)
return error;
}
/* Drop the dentry to force a new lookup */
if (!list_empty(&de->d_hash)) {
d_drop(de);
rehash = 1;
}
if (!list_empty(&de->d_hash))
return -EBUSY;
/* update i_nlink and free the inode before unlinking;
if rmdir fails a new lookup set i_nlink right.*/
if (de->d_inode->i_nlink)
de->d_inode->i_nlink --;
d_delete(de);
error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
......@@ -561,10 +550,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
return error;
}
if (rehash)
d_add(de, NULL);
/* XXX how can mtime be set? */
return 0;
}
......
......@@ -661,27 +661,11 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
if (le32_to_cpu(de->inode) != inode->i_ino)
goto end_rmdir;
/*
* Prune any child dentries so that this dentry becomes negative.
*/
if (dentry->d_count > 1)
shrink_dcache_parent(dentry);
if (!empty_dir (inode))
retval = -ENOTEMPTY;
else if (le32_to_cpu(de->inode) != inode->i_ino)
retval = -ENOENT;
else {
if (dentry->d_count > 1) {
/*
* Are we deleting the last instance of a busy directory?
* Better clean up if so.
*
* Make directory empty (it will be truncated when finally
* dereferenced). This also inhibits ext2_add_entry.
*/
inode->i_size = 0;
}
retval = ext2_delete_entry (de, bh);
dir->i_version = ++event;
}
......@@ -698,6 +682,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
inode->i_nlink);
inode->i_version = ++event;
inode->i_nlink = 0;
inode->i_size = 0;
mark_inode_dirty(inode);
dir->i_nlink--;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
......
......@@ -352,7 +352,7 @@ int hfs_rmdir(struct inode * parent, struct dentry *dentry)
goto hfs_rmdir_put;
error = -EBUSY;
if (dentry->d_count > 1)
if (!list_empty(&dentry->d_hash))
goto hfs_rmdir_put;
if (/* we only have to worry about 2 and 3 for mount points */
......
......@@ -452,7 +452,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
retval = -ENOENT;
goto end_rmdir;
}
if (dentry->d_count > 1) {
if (!list_empty(&dentry->d_hash)) {
retval = -EBUSY;
goto end_rmdir;
}
......
......@@ -452,8 +452,7 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry)
if (res)
goto rmdir_done;
res = -EBUSY;
shrink_dcache_parent(dentry);
if (dentry->d_count > 1) {
if (!list_empty(&dentry->d_hash)) {
#ifdef MSDOS_DEBUG
printk("msdos_rmdir: %s/%s busy, d_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
......
......@@ -881,7 +881,6 @@ static inline int do_rmdir(const char * name)
error = -ENOENT;
if (!dentry->d_inode)
goto exit;
/*
* The dentry->d_count stuff confuses d_delete() enough to
* not kill the inode from under us while it is locked. This
......@@ -919,8 +918,29 @@ static inline int do_rmdir(const char * name)
DQUOT_INIT(dir->d_inode);
if (dentry->d_count > 1)
/*
* We try to drop the dentry early: we should have
* a usage count of 2 if we're the only user of this
* dentry, and if that is true (possibly after pruning
* the dcache), then we drop the dentry now.
*
* A low-level filesystem can, if it choses, legally
* do a
*
* if (!list_empty(&dentry->d_hash))
* return -EBUSY;
*
* if it cannot handle the case of removing a directory
* that is still in use by something else..
*/
switch (dentry->d_count) {
default:
shrink_dcache_parent(dentry);
if (dentry->d_count != 2)
break;
case 2:
d_drop(dentry);
}
error = dir->d_inode->i_op->rmdir(dir->d_inode, dentry);
......
......@@ -24,11 +24,6 @@
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
#ifndef shrink_dcache_parent
#define shrink_dcache_parent(dentry) shrink_dcache_sb((dentry)->d_sb)
#endif
struct ncp_dirent {
struct nw_info_struct i;
struct nw_search_sequence s; /* given back for i */
......@@ -999,17 +994,14 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
goto out;
}
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(dir)))
goto out;
if (dentry->d_count > 1)
{
shrink_dcache_parent(dentry);
error = -EBUSY;
if (dentry->d_count > 1)
goto out;
}
error = -EBUSY;
if (!list_empty(&dentry->d_hash))
goto out;
strncpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
......@@ -1023,7 +1015,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
if (!result)
{
ncp_invalid_dir_cache(dir);
d_delete(dentry);
error = 0;
}
out:
......
......@@ -721,7 +721,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
*/
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error, rehash = 0;
int error;
dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);
......@@ -731,39 +731,24 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
goto out;
error = -EBUSY;
if (dentry->d_count > 1) {
/* Attempt to shrink child dentries ... */
shrink_dcache_parent(dentry);
if (dentry->d_count > 1)
goto out;
}
if (!list_empty(&dentry->d_hash))
goto out;
#ifdef NFS_PARANOIA
if (dentry->d_inode->i_count > 1)
printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
dentry->d_inode->i_count, dentry->d_inode->i_nlink);
#endif
/*
* Unhash the dentry while we remove the directory.
*/
if (!list_empty(&dentry->d_hash)) {
d_drop(dentry);
rehash = 1;
}
/*
* Update i_nlink and free the inode before unlinking.
*/
if (dentry->d_inode->i_nlink)
dentry->d_inode->i_nlink --;
d_delete(dentry);
nfs_invalidate_dircache(dir);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name);
if (!error) {
if (rehash)
d_add(dentry, NULL);
nfs_renew_times(dentry);
}
out:
return error;
}
......
......@@ -199,7 +199,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
goto end_rmdir;
}
#endif
if (dentry->d_count > 1) {
if (!list_empty(&dentry->d_hash)) {
retval = -EBUSY;
goto end_rmdir;
}
......
......@@ -479,22 +479,15 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
smb_close(inode);
/*
* Prune any child dentries so this dentry can become negative.
* Check that nobody else is using the directory..
*/
if (dentry->d_count > 1) {
shrink_dcache_parent(dentry);
error = -EBUSY;
if (dentry->d_count > 1)
goto out;
}
error = -EBUSY;
if (!list_empty(&dentry->d_hash))
goto out;
smb_invalid_dir_cache(dir);
error = smb_proc_rmdir(dentry);
if (!error)
{
smb_renew_times(dentry);
d_delete(dentry);
}
out:
return error;
}
......
......@@ -1008,8 +1008,7 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
goto out;
ret = -EBUSY;
shrink_dcache_parent(dentry);
if (dentry->d_count > 1)
if (!list_empty(&dentry->d_hash))
goto out;
/* check the sticky bit */
......@@ -1065,15 +1064,6 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
else
d_drop(temp);
/* Check again for a busy dentry */
ret = -EBUSY;
shrink_dcache_parent(dentry);
if (dentry->d_count > 1) {
printk("umsdos_rmdir: %s/%s busy\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
goto out_dput;
}
/*
* Attempt to remove the msdos name.
*/
......@@ -1090,11 +1080,8 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
/* dput() temp if we didn't do it above */
out_dput:
if (temp != dentry) {
if (temp != dentry)
dput(temp);
if (!ret)
d_delete (dentry);
}
out:
Printk (("umsdos_rmdir %d\n", ret));
......
......@@ -156,11 +156,8 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
goto out;
ret = -EBUSY;
if (dentry->d_count > 1) {
shrink_dcache_parent(dentry);
if (dentry->d_count > 1)
goto out;
}
if (!list_empty(&dentry->d_hash))
goto out;
ret = msdos_rmdir (dir, dentry);
if (ret != -ENOTEMPTY)
......
......@@ -1422,6 +1422,8 @@ static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) {
return -EBUSY;
}
if (!list_empty(&dentry->d_hash))
return -EBUSY;
res = vfat_empty(dentry->d_inode);
if (res) {
......@@ -1508,18 +1510,16 @@ static void drop_replace_inodes(struct dentry *dentry, struct inode *inode)
tmp = next;
next = tmp->next;
alias = list_entry(tmp, struct dentry, d_alias);
if (alias == dentry)
continue;
if (inode) {
list_del(&alias->d_alias);
iput(alias->d_inode);
d_instantiate(alias, inode);
/* dentry is already accounted for */
if (alias != dentry) {
inode->i_count++;
}
}
if (alias != dentry) {
d_drop(alias);
inode->i_count++;
}
d_drop(alias);
}
}
}
......@@ -1551,10 +1551,12 @@ int vfat_rmdir(struct inode *dir,struct dentry* dentry)
{
int res;
PRINTK1(("vfat_rmdir: dentry=%p, inode=%p\n", dentry, dentry->d_inode));
res = vfat_rmdirx(dir, dentry);
if (res >= 0) {
drop_replace_inodes(dentry, NULL);
d_delete(dentry);
res = -EBUSY;
if (list_empty(&dentry->d_hash)) {
res = vfat_rmdirx(dir, dentry);
if (res >= 0)
drop_replace_inodes(dentry, NULL);
}
return res;
}
......
......@@ -34,7 +34,7 @@
* Version
*/
#define JS_VERSION 0x01020c
#define JS_VERSION 0x01020d
/*
* Types and constants for reading from /dev/js
......@@ -179,18 +179,23 @@ typedef struct { int something; } spinlock_t;
#ifdef USE_PARPORT
#include <linux/parport.h>
#define JS_PAR_STATUS(y) parport_read_status(y->port)
#define JS_PAR_DATA_IN(y) parport_read_data(y->port)
#define JS_PAR_DATA_OUT(x,y) parport_write_data(y->port, x)
#define JS_PAR_STATUS(y) parport_read_status(y->port)
#define JS_PAR_CTRL_IN(y) parport_read_control(y->port)
#define JS_PAR_CTRL_OUT(x,y) parport_write_control(y->port, x)
#define JS_PAR_ECTRL_OUT(x,y) parport_write_econtrol(y->port, x)
#else
#define JS_PAR_STATUS(y) inb(y+1)
#define JS_PAR_DATA_IN(y) inb(y)
#define JS_PAR_DATA_OUT(x,y) outb(x,y)
#define JS_PAR_STATUS(y) inb(y+1)
#define JS_PAR_CTRL_IN(y) inb(y+2)
#define JS_PAR_CTRL_OUT(x,y) outb(x,y+2)
#define JS_PAR_ECTRL_OUT(x,y) outb(x,y+0x402)
#endif
#define JS_PAR_STATUS_INVERT (0x80)
#define JS_PAR_CTRL_INVERT (0x04)
/*
* Internal types
......
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