Commit 9910fd91 authored by Linus Torvalds's avatar Linus Torvalds

v2.4.0.7 -> v2.4.0.8

  - USB hotplug updates/fixes
  - boots on real i386 machines
  - fix n_tty "canon" mode SMP race
  - FAT fat_cache SMP race fix
parent 3175e85b
......@@ -2625,13 +2625,14 @@ CONFIG_HOTPLUG
One well known example of this is PCMCIA- or PC-cards, credit-card
size devices such as network cards, modems or hard drives which are
plugged into slots found on all modern laptop computers.
Another example, used on modern desktops as well as laptops, is USB.
Enable HOTPLUG with USB and KMOD, and your kernel will automatically
call out to a user mode "policy agent" to load modules and set up
software needed to use USB devices you plug in. Get agent software
(at http://www.linux-usb.org/policy.html) and install it.
plugged into slots found on all modern laptop computers. Another
example, used on modern desktops as well as laptops, is USB.
Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
software (at http://linux-hotplug.sourceforge.net) and install it.
Then your kernel will automatically call out to a user mode "policy
agent" (/sbin/hotplug) to load modules and set up software needed
to use devices as you hotplug them.
PCMCIA/Cardbus support
CONFIG_PCMCIA
......
USB HOTPLUGGING
LINUX HOTPLUGGING
In hotpluggable busses like USB (and Cardbus PCI), end-users plug devices
into the bus with power on. In most cases, users expect the devices to become
......@@ -8,7 +8,7 @@ immediately usable. That means the system must do many things, including:
loading a kernel module; newer drivers can use modutils to
publish their device (and class) support to user utilities.
- Bind a driver to that device. That's done using the USB
- Bind a driver to that device. Bus frameworks do that using a
device driver's probe() routine.
- Tell other subsystems to configure the new device. Print
......@@ -26,6 +26,10 @@ Those triggered actions must support a system's administrative policies;
such programs are called "policy agents" here. Typically they involve
shell scripts that dispatch to more familiar administration tools.
Because some of those actions rely on information about drivers (metadata)
that is currently available only when the drivers are dynamically linked,
you get the best hotplugging when you configure a highly modular system.
KERNEL HOTPLUG HELPER (/sbin/hotplug)
......@@ -40,9 +44,14 @@ some kernel event. That name is used as the first key for further event
dispatch; any other argument and environment parameters are specified by
the subsystem making that invocation.
A reference implementation of a /sbin/hotplug script is available at the
http://www.linux-usb.org website, which works USB for but also knows how to
delegate to any /etc/hotplug/$TYPE.agent policy agent present.
Hotplug software and other resources is available at:
http://linux-hotplug.sourceforge.net
Mailing list information is also available at that site.
--------------------------------------------------------------------------
USB POLICY AGENT
......
......@@ -223,7 +223,7 @@ Generic Serial driver
To enable the generic driver to recognize your device, build the driver
as a module and load it by the following invocation:
insmod usb-serial vendor=0x#### product=0x####
insmod usbserial vendor=0x#### product=0x####
where the #### is replaced with the hex representation of your device's
vendor id and product id.
......
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 1
EXTRAVERSION =-pre7
EXTRAVERSION =-pre8
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
......
......@@ -86,6 +86,15 @@ static inline void free_buf(unsigned char *buf)
free_page((unsigned long) buf);
}
static inline void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
{
if (tty->read_cnt < N_TTY_BUF_SIZE) {
tty->read_buf[tty->read_head] = c;
tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
tty->read_cnt++;
}
}
static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
{
unsigned long flags;
......@@ -94,11 +103,7 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
* Why didn't anyone see this one comming? --AJK
*/
spin_lock_irqsave(&tty->read_lock, flags);
if (tty->read_cnt < N_TTY_BUF_SIZE) {
tty->read_buf[tty->read_head] = c;
tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
tty->read_cnt++;
}
put_tty_queue_nolock(c, tty);
spin_unlock_irqrestore(&tty->read_lock, flags);
}
......@@ -499,6 +504,8 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
unsigned long flags;
if (tty->raw) {
put_tty_queue(c, tty);
return;
......@@ -651,10 +658,12 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, tty);
handle_newline:
spin_lock_irqsave(&tty->read_lock, flags);
set_bit(tty->read_head, &tty->read_flags);
put_tty_queue(c, tty);
put_tty_queue_nolock(c, tty);
tty->canon_head = tty->read_head;
tty->canon_data++;
spin_unlock_irqrestore(&tty->read_lock, flags);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
......@@ -1055,12 +1064,6 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
tty->read_tail = ((tty->read_tail+1) &
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
put_user(c, b++);
nr--;
}
if (eol) {
/* this test should be redundant:
* we shouldn't be reading data if
......@@ -1068,8 +1071,15 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file,
*/
if (--tty->canon_data < 0)
tty->canon_data = 0;
break;
}
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
put_user(c, b++);
nr--;
}
if (eol)
break;
}
} else {
int uncopied;
......
......@@ -247,6 +247,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
return 0;
err_out:
up(&(rio->lock));
return retval;
}
......@@ -389,7 +390,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
result, partial, this_read);
return -EIO;
} else {
unlock_kernel();
up(&(rio->lock));
return (0);
}
......
......@@ -22,6 +22,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
bool ' USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
bool ' USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
fi
dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
......
......@@ -15,7 +15,13 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (12/29/2000) gkh
* (12/12/2000) gkh
* Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
* moved them to the serial_open and serial_close functions.
* Also fixed bug with there not being a MOD_DEC for the generic driver
* (thanks to Gary Brubaker for finding this.)
*
* (11/29/2000) gkh
* Small NULL pointer initialization cleanup which saves a bit of disk image
*
* (11/01/2000) Adam J. Richter
......@@ -471,6 +477,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
return -ENODEV;
}
MOD_INC_USE_COUNT;
/* set up our port structure making the tty driver remember our port object, and us it */
portNumber = MINOR(tty->device) - serial->minor;
port = &serial->port[portNumber];
......@@ -508,6 +516,8 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
} else {
generic_close(port, filp);
}
MOD_DEC_USE_COUNT;
}
......@@ -721,12 +731,13 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
if (port_paranoia_check (port, __FUNCTION__))
return -ENODEV;
MOD_INC_USE_COUNT;
dbg(__FUNCTION__ " - port %d", port->number);
spin_lock_irqsave (&port->port_lock, flags);
++port->open_count;
MOD_INC_USE_COUNT;
if (!port->active) {
port->active = 1;
......@@ -776,6 +787,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp)
}
spin_unlock_irqrestore (&port->port_lock, flags);
MOD_DEC_USE_COUNT;
}
......@@ -1069,7 +1081,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
}
/* found all that we need */
MOD_INC_USE_COUNT;
info("%s converter detected", type->name);
#ifdef CONFIG_USB_SERIAL_GENERIC
......@@ -1077,7 +1088,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
num_ports = num_bulk_out;
if (num_ports == 0) {
err("Generic device with no bulk out, not allowed.");
MOD_DEC_USE_COUNT;
return NULL;
}
} else
......@@ -1087,7 +1097,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
serial = get_free_serial (num_ports, &minor);
if (serial == NULL) {
err("No more free serial devices");
MOD_DEC_USE_COUNT;
return NULL;
}
......@@ -1233,7 +1242,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
/* free up any memory that we allocated */
kfree (serial);
MOD_DEC_USE_COUNT;
return NULL;
}
......@@ -1300,7 +1308,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
info("device disconnected");
}
MOD_DEC_USE_COUNT;
}
......
......@@ -11,6 +11,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (12/12/2000) gkh
* Moved MOD_DEC to end of visor_close to be nicer, as the final write
* message can sleep.
*
* (11/12/2000) gkh
* Fixed bug with data being dropped on the floor by forcing tty->low_latency
* to be on. Hopefully this fixes the OHCI issue!
......@@ -214,7 +218,6 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
spin_lock_irqsave (&port->port_lock, flags);
--port->open_count;
MOD_DEC_USE_COUNT;
if (port->open_count <= 0) {
transfer_buffer = kmalloc (0x12, GFP_KERNEL);
......@@ -237,6 +240,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
/* Uncomment the following line if you want to see some statistics in your syslog */
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
MOD_DEC_USE_COUNT;
}
......
/* Driver for USB Mass Storage compliant devices
* Debugging Functions Header File
*
* $Id: debug.h,v 1.5 2000/09/04 02:12:47 groovyjava Exp $
* $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
......
......@@ -248,7 +248,7 @@ static int bus_reset( Scsi_Cmnd *srb )
for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *intf =
&us->pusb_dev->actconfig->interface[i];
const struct usb_device_id *id;
struct usb_device_id *id;
/* if this is an unclaimed interface, skip it */
if (!intf->driver) {
......
/* Driver for USB Mass Storage compliant devices
* Ununsual Devices File
*
* $Id: unusual_devs.h,v 1.1 2000/12/05 05:38:31 mdharm Exp $
*
* Current development and maintenance by:
* (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Initial work by:
* (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
*
* Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
* information about this driver.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* IMPORTANT NOTE: This file must be included in another file which does
* both of the following things for it to work:
* (1) <include/config.h> _must_ be included before this file
* (2) The macro UNUSUAL_DEV() must be defined before this file is included
*/
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
*/
UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245,
"Mitsumi",
"CD-R/RW Drive",
US_SC_8020, US_PR_CBI, NULL, 0),
UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
US_SC_8070, US_PR_CB, NULL, 0),
#ifdef CONFIG_USB_STORAGE_HP8200e
UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0),
#endif
UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0200,
"Shuttle",
"eUSB MMC Adapter",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0),
UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0210,
"Sony",
"DSC-S30/S70/505V/F505",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CBI, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
"LaCie",
"USB Hard Disk",
US_SC_RBC, US_PR_CB, NULL, 0 ),
UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0100,
"In-System",
"USB/IDE Bridge (ATAPI ONLY!)",
US_SC_8070, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
US_SC_UFI, US_PR_CB, NULL, 0 ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
"Olympus",
"Camedia MAUSB-2",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara",
"FlashGate SmartMedia",
US_SC_SCSI, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
US_SC_SCSI, US_PR_BULK, NULL, 0 ),
UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
"ImageMate SDDR-05a",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP),
UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN ),
#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x0781, 0x0200, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP ),
#endif
UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009,
"Sandisk",
"ImageMate SDDR-31",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_IGNORE_SER),
UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-DB25",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_FREECOM
UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
"Freecom",
"USB-IDE",
US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
#endif
UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP ),
#endif
/* Driver for USB Mass Storage compliant devices
*
* $Id: usb.c,v 1.57 2000/11/21 02:56:41 mdharm Exp $
* $Id: usb.c,v 1.61 2001/01/13 00:10:59 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
......@@ -11,6 +11,9 @@
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
*
* usb_device_id support by Adam J. Richter (adam@yggdrasil.com):
* (c) 2000 Yggdrasil Computing, Inc.
*
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in
......@@ -95,11 +98,133 @@ struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
static void storage_disconnect(struct usb_device *dev, void *ptr);
/* The entries in this table, except for final ones here
* (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
* line for line with the entries of us_unsuaul_dev_list[].
* For now, we duplicate idVendor and idProduct in us_unsual_dev_list,
* just to avoid alignment bugs.
*/
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName, productName,useProtocol, useTransport, \
initFunction, flags) \
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
static struct usb_device_id storage_usb_ids [] = {
# include "unusual_devs.h"
#undef UNUSUAL_DEV
/* Control/Bulk transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
/* Control/Bulk/Interrupt transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
/* Bulk-only transport for all SubClass values */
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
/* Terminating entry */
{ }
};
MODULE_DEVICE_TABLE (usb, storage_usb_ids);
/* This is the list of devices we recognize, along with their flag data */
/* The vendor name should be kept at eight characters or less, and
* the product name should be kept at 16 characters or less. If a device
* has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
* normally generated by a device thorugh the INQUIRY response will be
* taken from this list, and this is the reason for the above size
* restriction. However, if the flag is not present, then you
* are free to use as many characters as you like.
*/
#undef UNUSUAL_DEV
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
vendorName: vendor_name, \
productName: product_name, \
useProtocol: use_protocol, \
useTransport: use_transport, \
initFunction : init_function, \
flags: Flags, \
}
static struct us_unusual_dev us_unusual_dev_list[] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
/* Control/Bulk transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_CB},
{ useProtocol: US_SC_8020,
useTransport: US_PR_CB},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_CB},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_CB},
{ useProtocol: US_SC_8070,
useTransport: US_PR_CB},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_CB},
/* Control/Bulk/Interrupt transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_8020,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_8070,
useTransport: US_PR_CBI},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_CBI},
/* Bulk-only transport for all SubClass values */
{ useProtocol: US_SC_RBC,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_8020,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_QIC,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_UFI,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_8070,
useTransport: US_PR_BULK},
{ useProtocol: US_SC_SCSI,
useTransport: US_PR_BULK},
/* Terminating entry */
{ 0 }
};
struct usb_driver usb_storage_driver = {
name: "usb-storage",
probe: storage_probe,
disconnect: storage_disconnect,
id_table: storage_usb_ids,
};
/*
......@@ -325,246 +450,6 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
/* This is the list of devices we recognize, along with their flag data */
/* The vendor name should be kept at eight characters or less, and
* the product name should be kept at 16 characters or less. If a device
* has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
* normally generated by a device thorugh the INQUIRY response will be
* taken from this list, and this is the reason for the above size
* restriction. However, if the flag is not present, then you
* are free to use as many characters as you like.
*/
static struct us_unusual_dev us_unusual_dev_list[] = {
{ 0x03ee, 0x0000, 0x0000, 0x0245,
"Mitsumi",
"CD-R/RW Drive",
US_SC_8020, US_PR_CBI, NULL, 0},
{ 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
US_SC_8070, US_PR_CB, NULL, 0},
#ifdef CONFIG_USB_STORAGE_HP8200e
{ 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0},
#endif
{ 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x04e6, 0x0003, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
#ifdef CONFIG_USB_STORAGE_DPCM
{ 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP },
#endif
{ 0x04e6, 0x0006, 0x0100, 0x0200,
"Shuttle",
"eUSB MMC Adapter",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
{ 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
{ 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0},
{ 0x054c, 0x0010, 0x0106, 0x0210,
"Sony",
"DSC-S30/S70/505V/F505",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
{ 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
{ 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CB, NULL,
US_FL_SINGLE_LUN},
{ 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CBI, NULL,
US_FL_SINGLE_LUN},
{ 0x059f, 0xa601, 0x0200, 0x0200,
"LaCie",
"USB Hard Disk",
US_SC_RBC, US_PR_CB, NULL, 0 },
{ 0x05ab, 0x0031, 0x0100, 0x0100,
"In-System",
"USB/IDE Bridge (ATAPI ONLY!)",
US_SC_8070, US_PR_BULK, NULL, 0 },
{ 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
US_SC_UFI, US_PR_CB, NULL, 0 },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x066b, 0x0105, 0x0100, 0x0100,
"Olympus",
"Camedia MAUSB-2",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
{ 0x0693, 0x0002, 0x0100, 0x0100,
"Hagiwara",
"FlashGate SmartMedia",
US_SC_SCSI, US_PR_BULK, NULL, 0 },
{ 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
US_SC_SCSI, US_PR_BULK, NULL, 0 },
{ 0x0781, 0x0001, 0x0200, 0x0200,
"Sandisk",
"ImageMate SDDR-05a",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP},
{ 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN },
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x0781, 0x0200, 0x0100, 0x0208,
"Sandisk",
"ImageMate SDDR-09",
US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP },
#endif
{ 0x0781, 0x0002, 0x0009, 0x0009,
"Sandisk",
"ImageMate SDDR-31",
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_IGNORE_SER},
{ 0x07af, 0x0004, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-DB25",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_FREECOM
{ 0x07ab, 0xfc01, 0x0000, 0x9999,
"Freecom",
"USB-IDE",
US_SC_QIC, US_PR_FREECOM, freecom_init, 0},
#endif
{ 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG },
#ifdef CONFIG_USB_STORAGE_DPCM
{ 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL,
US_FL_START_STOP },
#endif
{ 0 }
};
/* Search our ususual device list, based on vendor/product combinations
* to see if we can support this device. Returns a pointer to a structure
* defining how we should support this device, or NULL if it's not in the
* list
*/
static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
u16 bcdDevice)
{
struct us_unusual_dev* ptr;
US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
idVendor, idProduct, bcdDevice);
ptr = us_unusual_dev_list;
while ((ptr->idVendor != 0x0000) &&
!((ptr->idVendor == idVendor) &&
(ptr->idProduct == idProduct) &&
(ptr->bcdDeviceMin <= bcdDevice) &&
(ptr->bcdDeviceMax >= bcdDevice)))
ptr++;
/* if the search ended because we hit the end record, we failed */
if (ptr->idVendor == 0x0000) {
US_DEBUGP("-- did not find a matching device\n");
return NULL;
}
/* otherwise, we found one! */
US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName,
ptr->productName);
return ptr;
}
/* Set up the IRQ pipe and handler
* Note that this function assumes that all the data in the us_data
* strucuture is current. This includes the ep_int field, which gives us
......@@ -620,6 +505,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
int i;
const int id_index = id - storage_usb_ids;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */
......@@ -640,47 +526,48 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
u8 subclass = 0;
u8 protocol = 0;
/* the altsettting 0 on the interface we're probing */
/* the altsettting on the interface we're probing that matched our
* usb_match_id table
*/
struct usb_interface *intf = dev->actconfig->interface;
struct usb_interface_descriptor *altsetting =
&(dev->actconfig->interface[ifnum].altsetting[0]);
intf[ifnum].altsetting + intf[ifnum].act_altsetting;
US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */
memset(mf, 0, sizeof(mf));
memset(prod, 0, sizeof(prod));
memset(serial, 0, sizeof(serial));
/* search for this device in our unusual device list */
unusual_dev = us_find_dev(dev->descriptor.idVendor,
dev->descriptor.idProduct,
dev->descriptor.bcdDevice);
/*
* Can we support this device, either because we know about it
* from our unusual device list, or because it advertises that it's
* compliant to the specification?
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
if (!unusual_dev &&
!(dev->descriptor.bDeviceClass == 0 &&
altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
altsetting->bInterfaceSubClass >= US_SC_MIN &&
altsetting->bInterfaceSubClass <= US_SC_MAX)) {
/* if it's not a mass storage, we go no further */
US_DEBUGP("id_index calculated to be: %d\n", id_index);
US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0]));
if (id_index <
sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) {
unusual_dev = &us_unusual_dev_list[id_index];
if (unusual_dev->vendorName)
US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
if (unusual_dev->productName)
US_DEBUGP("Product: %s\n", unusual_dev->productName);
} else
/* no, we can't support it */
return NULL;
}
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */
if (unusual_dev) {
subclass = unusual_dev->useProtocol;
protocol = unusual_dev->useTransport;
flags = unusual_dev->flags;
} else {
subclass = altsetting->bInterfaceSubClass;
protocol = altsetting->bInterfaceProtocol;
flags = 0;
}
/*
* Find the endpoints we need
......@@ -728,7 +615,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Sanity check failed. Rejecting device.\n");
US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return NULL;
}
......@@ -861,7 +748,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
strncpy(ss->product, prod, USB_STOR_STRING_LEN);
strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
if (strlen(ss->vendor) == 0) {
if (unusual_dev)
if (unusual_dev->vendorName)
strncpy(ss->vendor, unusual_dev->vendorName,
USB_STOR_STRING_LEN);
else
......@@ -869,7 +756,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
USB_STOR_STRING_LEN);
}
if (strlen(ss->product) == 0) {
if (unusual_dev)
if (unusual_dev->productName)
strncpy(ss->product, unusual_dev->productName,
USB_STOR_STRING_LEN);
else
......@@ -1118,6 +1005,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void)
{
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
/* initialize internal global data elements */
us_list = NULL;
init_MUTEX(&us_list_semaphore);
......
/* Driver for USB Mass Storage compliant devices
* Main Header File
*
* $Id: usb.h,v 1.11 2000/11/13 22:38:55 mdharm Exp $
* $Id: usb.h,v 1.12 2000/12/05 03:33:49 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
......@@ -84,13 +84,6 @@ struct us_data;
*/
struct us_unusual_dev {
/* we search the list based on these parameters */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDeviceMin;
__u16 bcdDeviceMax;
/* the list specifies these parameters */
const char* vendorName;
const char* productName;
__u8 useProtocol;
......
......@@ -24,6 +24,7 @@
#endif
static struct fat_cache *fat_cache,cache[FAT_CACHE];
static spinlock_t fat_cache_lock = SPIN_LOCK_UNLOCKED;
/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If
new_value is != -1, that FAT entry is replaced by it. */
......@@ -133,13 +134,16 @@ int default_fat_access(struct super_block *sb,int nr,int new_value)
return next;
}
void fat_cache_init(void)
{
static int initialized = 0;
int count;
if (initialized) return;
spin_lock(&fat_cache_lock);
if (initialized) {
spin_unlock(&fat_cache_lock);
return;
}
fat_cache = &cache[0];
for (count = 0; count < FAT_CACHE; count++) {
cache[count].device = 0;
......@@ -147,6 +151,7 @@ void fat_cache_init(void)
&cache[count+1];
}
initialized = 1;
spin_unlock(&fat_cache_lock);
}
......@@ -157,6 +162,7 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
if (!first)
return;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next)
if (inode->i_dev == walk->device
&& walk->start_cluster == first
......@@ -166,8 +172,12 @@ void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
#ifdef DEBUG
printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
#endif
if ((*f_clu = walk->file_cluster) == cluster) return;
if ((*f_clu = walk->file_cluster) == cluster) {
spin_unlock(&fat_cache_lock);
return;
}
}
spin_unlock(&fat_cache_lock);
#ifdef DEBUG
printk("cache miss\n");
#endif
......@@ -197,6 +207,7 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
int first = MSDOS_I(inode)->i_start;
last = NULL;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk->next; walk = (last = walk)->next)
if (inode->i_dev == walk->device
&& walk->start_cluster == first
......@@ -204,17 +215,22 @@ void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
if (walk->disk_cluster != d_clu) {
printk("FAT cache corruption inode=%ld\n",
inode->i_ino);
spin_unlock(&fat_cache_lock);
fat_cache_inval_inode(inode);
return;
}
/* update LRU */
if (last == NULL) return;
if (last == NULL) {
spin_unlock(&fat_cache_lock);
return;
}
last->next = walk->next;
walk->next = fat_cache;
fat_cache = walk;
#ifdef DEBUG
list_cache();
#endif
spin_unlock(&fat_cache_lock);
return;
}
walk->device = inode->i_dev;
......@@ -224,6 +240,7 @@ list_cache();
last->next = NULL;
walk->next = fat_cache;
fat_cache = walk;
spin_unlock(&fat_cache_lock);
#ifdef DEBUG
list_cache();
#endif
......@@ -238,10 +255,12 @@ void fat_cache_inval_inode(struct inode *inode)
struct fat_cache *walk;
int first = MSDOS_I(inode)->i_start;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next)
if (walk->device == inode->i_dev
&& walk->start_cluster == first)
walk->device = 0;
spin_unlock(&fat_cache_lock);
}
......@@ -249,9 +268,11 @@ void fat_cache_inval_dev(kdev_t device)
{
struct fat_cache *walk;
spin_lock(&fat_cache_lock);
for (walk = fat_cache; walk; walk = walk->next)
if (walk->device == device)
walk->device = 0;
spin_unlock(&fat_cache_lock);
}
......
......@@ -1853,6 +1853,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
struct reiserfs_transaction_handle th ;
reiserfs_wait_on_write_block(inode->i_sb) ;
lock_kernel();
prevent_flush_page_lock(page, inode) ;
ret = generic_commit_write(f, page, from, to) ;
/* we test for O_SYNC here so we can commit the transaction
......@@ -1866,6 +1867,7 @@ static int reiserfs_commit_write(struct file *f, struct page *page,
journal_end_sync(&th, inode->i_sb, 1) ;
}
allow_flush_page_lock(page, inode) ;
unlock_kernel();
return ret ;
}
......
......@@ -54,6 +54,7 @@ extern void wait_for_keypress(void);
extern int root_mountflags;
static int do_remount_sb(struct super_block *sb, int flags, char * data);
static int do_remount(const char *dir, int flags, char * data);
/* this is initialized in init/main.c */
kdev_t ROOT_DEV;
......@@ -1025,15 +1026,12 @@ static int do_umount(struct vfsmount *mnt, int umount_root, int flags)
* call reboot(9). Then init(8) could umount root and exec /reboot.
*/
if (mnt == current->fs->rootmnt && !umount_root) {
int retval = 0;
/*
* Special case for "unmounting" root ...
* we just try to remount it readonly.
*/
mntput(mnt);
if (!(sb->s_flags & MS_RDONLY))
retval = do_remount_sb(sb, MS_RDONLY, 0);
return retval;
return do_remount("/", MS_RDONLY, NULL);
}
spin_lock(&dcache_lock);
......
......@@ -386,6 +386,7 @@ extern void clear_page_tables(struct mm_struct *, unsigned long, int);
struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share);
struct file *shmem_file_setup(char * name, loff_t size);
extern void shmem_lock(struct file * file, int lock);
extern int shmem_zero_setup(struct vm_area_struct *);
extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
......
......@@ -117,11 +117,43 @@ shmem_truncate_part (swp_entry_t * dir, unsigned long size,
return 0;
}
/*
* shmem_recalc_inode - recalculate the size of an inode
*
* @inode: inode to recalc
*
* We have to calculate the free blocks since the mm can drop pages
* behind our back
*
* But we know that normally
* inodes->i_blocks == inode->i_mapping->nrpages + info->swapped
*
* So the mm freed
* inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped)
*
* It has to be called with the spinlock held.
*/
static void shmem_recalc_inode(struct inode * inode)
{
unsigned long freed;
freed = inode->i_blocks -
(inode->i_mapping->nrpages + inode->u.shmem_i.swapped);
if (freed){
struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
inode->i_blocks -= freed;
spin_lock (&info->stat_lock);
info->free_blocks += freed;
spin_unlock (&info->stat_lock);
}
}
static void shmem_truncate (struct inode * inode)
{
int clear_base;
unsigned long start;
unsigned long mmfreed, freed = 0;
unsigned long freed = 0;
swp_entry_t **base, **ptr;
struct shmem_inode_info * info = &inode->u.shmem_i;
......@@ -154,26 +186,9 @@ static void shmem_truncate (struct inode * inode)
info->i_indirect = 0;
out:
/*
* We have to calculate the free blocks since we do not know
* how many pages the mm discarded
*
* But we know that normally
* inodes->i_blocks == inode->i_mapping->nrpages + info->swapped
*
* So the mm freed
* inodes->i_blocks - (inode->i_mapping->nrpages + info->swapped)
*/
mmfreed = inode->i_blocks - (inode->i_mapping->nrpages + info->swapped);
info->swapped -= freed;
inode->i_blocks -= freed + mmfreed;
shmem_recalc_inode(inode);
spin_unlock (&info->lock);
spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
inode->i_sb->u.shmem_sb.free_blocks += freed + mmfreed;
spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
}
static void shmem_delete_inode(struct inode * inode)
......@@ -208,6 +223,7 @@ static int shmem_writepage(struct page * page)
return 1;
spin_lock(&info->lock);
shmem_recalc_inode(page->mapping->host);
entry = shmem_swp_entry (info, page->index);
if (!entry) /* this had been allocted on page allocation */
BUG();
......@@ -269,6 +285,9 @@ struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, i
entry = shmem_swp_entry (info, idx);
if (!entry)
goto oom;
spin_lock (&info->lock);
shmem_recalc_inode(inode);
spin_unlock (&info->lock);
if (entry->val) {
unsigned long flags;
......
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