If enough people respond here, and all responses are "it doesn't screw
my data", it might convince Linus that this patch is indeed safe :-)
So please test and report back here. I've been running this patch for
over a month now, and it works fine. Other people have tried it too
and it works fine for them.
The patch was generated against 2.4.10-pre3 but applies cleanly
against 2.4.10-pre4 as well.
Regards,
Richard....
Permanent: rgooch@atnf.csiro.au
Current: rgooch@ras.ucalgary.ca
diff -urN linux-2.4.10-pre3/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.10-pre3/Documentation/Configure.help Sun Sep 2 10:22:26 2001
+++ linux/Documentation/Configure.help Sun Sep 2 10:23:53 2001
@@ -5453,6 +5453,17 @@
located on a SCSI disk. In this case, do not compile the driver for
your SCSI host adapter (below) as a module either.
+Many SCSI Discs support
+CONFIG_SD_MANY
+ This allows you to support a very large number of SCSI discs
+ (approximately 2144). You will also need to set CONFIG_DEVFS_FS=y
+ later. This option may consume all unassigned block majors
+ (i.e. those which do not have an allocation in
+ Documentation/devices.txt). Enabling this will consume a few extra
+ kilobytes of kernel memory.
+
+ Unless you have a large storage array, say N.
+
Extra SCSI Disks
CONFIG_SD_EXTRA_DEVS
This controls the amount of additional space allocated in tables for
diff -urN linux-2.4.10-pre3/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- linux-2.4.10-pre3/Documentation/filesystems/devfs/ChangeLog Wed Jul 11 15:55:41 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog Sun Sep 2 10:23:53 2001
@@ -1675,3 +1675,79 @@
- Fixed number leak for /dev/cdroms/cdrom%d
- Fixed number leak for /dev/discs/disc%d
+===============================================================================
+Changes for patch v183
+
+- Fixed bug in <devfs_setup> which could hang boot process
+===============================================================================
+Changes for patch v184
+
+- Support large numbers of SCSI discs (~2144)
+
+- Documentation typo fix for fs/devfs/util.c
+
+- Fixed drivers/char/stallion.c for devfs
+
+- Added DEVFSD_NOTIFY_DELETE event
+
+- Updated README from master HTML file
+
+- Removed #include <asm/segment.h> from fs/devfs/base.c
+===============================================================================
+Changes for patch v185
+
+- Made <block_semaphore> and <char_semaphore> in fs/devfs/util.c
+ private
+
+- Fixed inode table races by removing it and using inode->u.generic_ip
+ instead
+
+- Moved <devfs_read_inode> into <get_vfs_inode>
+
+- Moved <devfs_write_inode> into <devfs_notify_change>
+===============================================================================
+Changes for patch v186
+
+- Fixed race in <devfs_do_symlink> for uni-processor
+
+- Fixed drivers/scsi/sd.h for when CONFIG_SD_MANY=n
+
+- Updated README from master HTML file
+===============================================================================
+Changes for patch v187
+
+- Fixed drivers/char/stallion.c for devfs
+
+- Fixed drivers/char/rocket.c for devfs
+
+- Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
+===============================================================================
+Changes for patch v188
+
+- Updated major masks in fs/devfs/util.c up to Linus' "no new majors"
+ proclamation. Block: were 126 now 122 free, char: were 26 now 19 free
+
+- Updated README from master HTML file
+
+- Removed remnant of multi-mount support in <devfs_mknod>
+
+- Removed unused DEVFS_FL_SHOW_UNREG flag
+===============================================================================
+Changes for patch v189
+
+- Removed nlink field from struct devfs_inode
+
+- Removed auto-ownership for /dev/pty/* (BSD ptys) and used
+ DEVFS_FL_CURRENT_OWNER|DEVFS_FL_NO_PERSISTENCE for /dev/pty/s* (just
+ like Unix98 pty slaves) and made /dev/pty/m* rw-rw-rw- access
+===============================================================================
+Changes for patch v190
+
+- Updated README from master HTML file
+
+- Replaced BKL with global rwsem to protect symlink data (quick and
+ dirty hack)
+===============================================================================
+Changes for patch v191
+
+- Replaced global rwsem for symlink with per-link refcount
diff -urN linux-2.4.10-pre3/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- linux-2.4.10-pre3/Documentation/filesystems/devfs/README Tue Jun 12 11:57:46 2001
+++ linux/Documentation/filesystems/devfs/README Sun Sep 2 10:23:53 2001
@@ -3,7 +3,7 @@
Linux Devfs (Device File System) FAQ
Richard Gooch
-26-APR-2001
+23-AUG-2001
-----------------------------------------------------------------------------
@@ -18,17 +18,14 @@
http://www.atnf.csiro.au/~rgooch/linux/
-NEWSFLASH: The official 2.3.46 kernel has
-included the devfs patch. Future patches will be released which
-build on this. These patches are rolled into Linus' tree from time to
-time.
-
A mailing list is available which you may subscribe to. Send
email
to majordomo@oss.sgi.com with the following line in the
body of the message:
subscribe devfs
-The list is archived at
+To unsubscribe, send the message body:
+unsubscribe devfs
+instead. The list is archived at
http://oss.sgi.com/projects/devfs/archive/.
@@ -71,6 +68,8 @@
Other resources
+Translations of this document
+
-----------------------------------------------------------------------------
@@ -82,7 +81,7 @@
name rather than major and minor numbers. These devices will appear in
devfs automatically, with whatever default ownership and
protection the driver specified. A daemon (devfsd) can be used to
-override these defaults.
+override these defaults. Devfs has been in the kernel since 2.3.46.
NOTE that devfs is entirely optional. If you prefer the old
disc-based device nodes, then simply leave CONFIG_DEVFS_FS=n (the
@@ -604,6 +603,20 @@
has problems with symbolic links. Append the following lines to your
/etc/securetty file:
+vc/1
+vc/2
+vc/3
+vc/4
+vc/5
+vc/6
+vc/7
+vc/8
+
+This will not weaken security. If you have a version of util-linux
+earlier than 2.10.h, please upgrade to 2.10.h or later. If you
+absolutely cannot upgrade, then also append the following lines to
+your /etc/securetty file:
+
1
2
3
@@ -618,27 +631,13 @@
are problems with dealing with symlinks, I'm suspicious of the level
of security offered in any case.
-A better solution is to install util-linux-2.10.h or later, which
-fixes a bug with ttyname handling in the login programme. Then append
-the following lines to your /etc/securetty file:
-
-vc/1
-vc/2
-vc/3
-vc/4
-vc/5
-vc/6
-vc/7
-vc/8
-
-This will not weaken security.
-
XFree86
While not essential, it's probably a good idea to upgrade to XFree86
4.0, as patches went in to make it more devfs-friendly. If you don't,
you'll probably need to apply the following patch to
/etc/security/console.perms so that ordinary users can run
-startx.
+startx. Note that not all distributions have this file (e.g. Debian),
+so if it's not present, don't worry about it.
--- /etc/security/console.perms.orig Sat Apr 17 16:26:47 1999
+++ /etc/security/console.perms Fri Feb 25 23:53:55 2000
@@ -691,9 +690,12 @@
described above.
The Kernel
-Finally, you need to make sure devfs is compiled into your
-kernel. Set CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y and recompile
-your kernel. At boot, devfs will be mounted onto /dev.
+Finally, you need to make sure devfs is compiled into your kernel. Set
+CONFIG_EXPERIMENTAL=y, CONFIG_DEVFS_FS=y and CONFIG_DEVFS_MOUNT=y by
+using favourite configuration tool (i.e. make config or
+make xconfig) and then make dep; make clean and then
+recompile your kernel and modules. At boot, devfs will be mounted onto
+/dev.
If you encounter problems booting (for example if you forgot a
configuration step), you can pass devfs=nomount at the kernel
@@ -805,8 +807,17 @@
directory to store the database. The sample /etc/devfsd.conf
file above may still be used. You will need to create the
/dev-state directory prior to installing devfsd. If you have
-old permissions in /dev, then just copy the device nodes over
-to the new directory.
+old permissions in /dev, then just copy (or move) the device
+nodes over to the new directory.
+
+Which method is better?
+
+The best method is to have the permissions database stored in the
+mounted-over /dev. This is because you will not need to copy
+device nodes over to /dev-state, and because it allows you to
+switch between devfs and non-devfs kernels, without requiring you to
+copy permissions between /dev-state (for devfs) and
+/dev (for non-devfs).
Dealing with drivers without devfs support
@@ -1038,6 +1049,13 @@
directory tree that reflects the topology of available devices. The
topological tree is useful for finding how your devices are arranged.
+Below is a list of the naming schemes for the most common drivers. A
+list of reserved device names is
+available for reference. Please send email to
+rgooch@atnf.csiro.au to obtain an allocation. Please be
+patient (the maintainer is busy). An alternative name may be allocated
+instead of the requested name, at the discretion of the maintainer.
+
Disc Devices
All discs, whether SCSI, IDE or whatever, are placed under the
@@ -1486,6 +1504,47 @@
namespace, but have had no response.
+How can I test if I have devfs compiled into my kernel?
+
+All filesystems built-in or currently loaded are listed in
+/proc/filesystems. If you see a devfs entry, then
+you know that devfs was compiled into your kernel. If you have
+correctly configured and rebuilt your kernel, then devfs will be
+built-in. If you think you've configured it in, but
+/proc/filesystems doesn't show it, you've made a mistake.
+Common mistakes include:
+
+Using a 2.2.x kernel without applying the devfs patch (if you
+don't know how to patch your kernel, use 2.4.x instead, don't bother
+asking me how to patch)
+Forgetting to set CONFIG_EXPERIMENTAL=y
+Forgetting to set CONFIG_DEVFS_FS=y
+Forgetting to set CONFIG_DEVFS_MOUNT=y (if you want devfs
+to be automatically mounted at boot)
+Editing your .config manually, instead of using make
+config or make xconfig
+Forgetting to run make dep; make clean after changing the
+configuration and before compiling
+Forgetting to compile your kernel and modules
+Forgetting to install your kernel
+Forgetting to install your modules
+
+Please check twice that you've done all these steps before sending in
+a bug report.
+
+
+
+How can I test if devfs is mounted on /dev?
+
+The device filesystem will always create an entry called
+".devfsd", which is used to communicate with the daemon. Even
+if the daemon is not running, this entry will exist. Testing for the
+existence of this entry is the approved method of determining if devfs
+is mounted or not. Note that the type of entry (i.e. regular file,
+character device, named pipe, etc.) may change without notice. Only
+the existence of the entry should be relied upon.
+
+
@@ -1713,6 +1772,23 @@
2nd Annual Storage Management Workshop held in Miamia, Florida,
U.S.A. in October 2000.
+
+
+
+
+-----------------------------------------------------------------------------
+
+
+Translations of this document
+
+This document has been translated into other languages.
+
+
+
+
+A Korean translation by viatoris@nownuri.net is available at
+
+http://home.nownuri.net/~viatoris/devfs/devfs.html
diff -urN linux-2.4.10-pre3/Documentation/filesystems/devfs/boot-options linux/Documentation/filesystems/devfs/boot-options
--- linux-2.4.10-pre3/Documentation/filesystems/devfs/boot-options Mon May 8 23:00:41 2000
+++ linux/Documentation/filesystems/devfs/boot-options Sun Sep 2 10:23:53 2001
@@ -4,7 +4,7 @@
Richard Gooch <rgooch@atnf.csiro.au>
- 30-APR-2000
+ 18-AUG-2001
When CONFIG_DEVFS_DEBUG is enabled, you can pass several boot options
@@ -19,6 +19,8 @@
devfs=dmod,dreg
+You may prefix "no" to any option. This will invert the option.
+
Debugging Options
=================
@@ -42,11 +44,11 @@
dilookup print inode lookup requests
-diread print inode reads
+diget print VFS inode allocations
diunlink print inode unlinks
-diwrite print inode writes
+dichange print inode changes
dimknod print calls to mknod(2)
@@ -58,10 +60,6 @@
These control the default behaviour of devfs. The options are:
-show show unregistered devices by default
-
mount mount devfs onto /dev at boot time
-
-nomount do not mount devfs onto /dev at boot time
only disable non-devfs device nodes for devfs-capable drivers
diff -urN linux-2.4.10-pre3/drivers/char/pty.c linux/drivers/char/pty.c
--- linux-2.4.10-pre3/drivers/char/pty.c Thu Jun 29 19:25:50 2000
+++ linux/drivers/char/pty.c Sun Sep 2 10:23:53 2001
@@ -334,7 +334,8 @@
/* Register a slave for the master */
if (tty->driver.major == PTY_MASTER_MAJOR)
tty_register_devfs(&tty->link->driver,
- DEVFS_FL_AUTO_OWNER | DEVFS_FL_WAIT,
+ DEVFS_FL_CURRENT_OWNER |
+ DEVFS_FL_NO_PERSISTENCE | DEVFS_FL_WAIT,
tty->link->driver.minor_start +
MINOR(tty->device)-tty->driver.minor_start);
retval = 0;
diff -urN linux-2.4.10-pre3/drivers/char/rocket.c linux/drivers/char/rocket.c
--- linux-2.4.10-pre3/drivers/char/rocket.c Mon Jul 2 14:56:41 2001
+++ linux/drivers/char/rocket.c Sun Sep 2 10:23:53 2001
@@ -2185,7 +2185,11 @@
*/
memset(&rocket_driver, 0, sizeof(struct tty_driver));
rocket_driver.magic = TTY_DRIVER_MAGIC;
+#ifdef CONFIG_DEVFS_FS
+ rocket_driver.name = "tts/R%d";
+#else
rocket_driver.name = "ttyR";
+#endif
rocket_driver.major = TTY_ROCKET_MAJOR;
rocket_driver.minor_start = 0;
rocket_driver.num = MAX_RP_PORTS;
@@ -2227,7 +2231,11 @@
* the minor number and the subtype code.
*/
callout_driver = rocket_driver;
+#ifdef CONFIG_DEVFS_FS
+ callout_driver.name = "cua/R%d";
+#else
callout_driver.name = "cur";
+#endif
callout_driver.major = CUA_ROCKET_MAJOR;
callout_driver.minor_start = 0;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
diff -urN linux-2.4.10-pre3/drivers/char/stallion.c linux/drivers/char/stallion.c
--- linux-2.4.10-pre3/drivers/char/stallion.c Fri Mar 2 12:12:07 2001
+++ linux/drivers/char/stallion.c Sun Sep 2 10:23:53 2001
@@ -139,8 +139,13 @@
static char *stl_drvtitle = "Stallion Multiport Serial Driver";
static char *stl_drvname = "stallion";
static char *stl_drvversion = "5.6.0";
+#ifdef CONFIG_DEVFS_FS
+static char *stl_serialname = "tts/E%d";
+static char *stl_calloutname = "cua/E%d";
+#else
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
+#endif
static struct tty_driver stl_serial;
static struct tty_driver stl_callout;
diff -urN linux-2.4.10-pre3/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.4.10-pre3/drivers/char/tty_io.c Sun Aug 12 18:36:24 2001
+++ linux/drivers/char/tty_io.c Sun Sep 2 10:23:53 2001
@@ -2021,7 +2021,7 @@
break;
default:
if (driver->major == PTY_MASTER_MAJOR)
- flags |= DEVFS_FL_AUTO_OWNER;
+ mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
break;
}
if ( (minor < driver->minor_start) ||
diff -urN linux-2.4.10-pre3/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- linux-2.4.10-pre3/drivers/scsi/Config.in Thu Jul 5 12:28:16 2001
+++ linux/drivers/scsi/Config.in Sun Sep 2 10:23:53 2001
@@ -3,7 +3,8 @@
dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then
- int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
+ bool ' Many (~2144) SCSI discs support (requires devfs)' CONFIG_SD_MANY
+ int ' Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40
fi
dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
diff -urN linux-2.4.10-pre3/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- linux-2.4.10-pre3/drivers/scsi/hosts.h Wed Aug 15 15:23:11 2001
+++ linux/drivers/scsi/hosts.h Sun Sep 2 10:23:53 2001
@@ -506,9 +506,8 @@
const char * tag;
struct module * module; /* Used for loadable modules */
unsigned char scsi_type;
- unsigned int major;
- unsigned int min_major; /* Minimum major in range. */
- unsigned int max_major; /* Maximum major in range. */
+ unsigned int *majors; /* Array of majors used by driver */
+ unsigned int num_majors; /* Number of majors used by driver */
unsigned int nr_dev; /* Number currently attached */
unsigned int dev_noticed; /* Number of devices detected. */
unsigned int dev_max; /* Current size of arrays */
diff -urN linux-2.4.10-pre3/drivers/scsi/osst.c linux/drivers/scsi/osst.c
--- linux-2.4.10-pre3/drivers/scsi/osst.c Thu Jul 19 22:18:15 2001
+++ linux/drivers/scsi/osst.c Sun Sep 2 10:23:53 2001
@@ -160,7 +160,6 @@
name: "OnStream tape",
tag: "osst",
scsi_type: TYPE_TAPE,
- major: OSST_MAJOR,
detect: osst_detect,
init: osst_init,
attach: osst_attach,
diff -urN linux-2.4.10-pre3/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- linux-2.4.10-pre3/drivers/scsi/scsi_lib.c Sun Aug 12 11:51:42 2001
+++ linux/drivers/scsi/scsi_lib.c Sun Sep 2 10:23:53 2001
@@ -788,25 +788,10 @@
* Search for a block device driver that supports this
* major.
*/
- if (spnt->blk && spnt->major == major) {
- return spnt;
- }
- /*
- * I am still not entirely satisfied with this solution,
- * but it is good enough for now. Disks have a number of
- * major numbers associated with them, the primary
- * 8, which we test above, and a secondary range of 7
- * different consecutive major numbers. If this ever
- * becomes insufficient, then we could add another function
- * to the structure, and generalize this completely.
- */
- if( spnt->min_major != 0
- && spnt->max_major != 0
- && major >= spnt->min_major
- && major <= spnt->max_major )
- {
- return spnt;
- }
+ int i;
+ if (!spnt->blk || !spnt->majors) continue;
+ for (i = 0; i < spnt->num_majors; ++i)
+ if (spnt->majors[i] == major) return spnt;
}
return NULL;
}
diff -urN linux-2.4.10-pre3/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- linux-2.4.10-pre3/drivers/scsi/sd.c Sun Sep 2 10:22:27 2001
+++ linux/drivers/scsi/sd.c Sun Sep 2 10:23:53 2001
@@ -28,6 +28,8 @@
*
* Modified by Alex Davis <letmein@erols.com>
* Fix problem where removable media could be ejected after sd_open.
+ *
+ * Modified by Richard Gooch rgooch@atnf.csiro.au to support >128 discs.
*/
#include <linux/config.h>
@@ -65,7 +67,7 @@
* static const char RCSid[] = "$Header:";
*/
-#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
+#define SD_MAJOR(i) sd_template.majors[(i)]
#define SCSI_DISKS_PER_MAJOR 16
#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8)
@@ -108,12 +110,6 @@
name:"disk",
tag:"sd",
scsi_type:TYPE_DISK,
- major:SCSI_DISK0_MAJOR,
- /*
- * Secondary range of majors that this driver handles.
- */
- min_major:SCSI_DISK1_MAJOR,
- max_major:SCSI_DISK7_MAJOR,
blk:1,
detect:sd_detect,
init:sd_init,
@@ -123,6 +119,19 @@
init_command:sd_init_command,
};
+#ifdef CONFIG_SD_MANY
+static inline int sd_devnum_to_index (int devnum)
+{
+ int i, major = MAJOR (devnum);
+
+ for (i = 0; i < sd_template.num_majors; ++i)
+ {
+ if (sd_template.majors[i] != major) continue;
+ return (i << 4) | (MINOR (devnum) >> 4);
+ }
+ return -ENODEV;
+}
+#endif
static void rw_intr(Scsi_Cmnd * SCpnt);
@@ -1054,6 +1063,43 @@
return i;
}
+static int sd_alloc_majors (void)
+/* Allocate as many majors as required
+ */
+{
+ int i, major;
+
+ if ( ( sd_template.majors =
+ kmalloc (sizeof *sd_template.majors * N_USED_SD_MAJORS,
+ GFP_KERNEL) ) == NULL ) {
+ printk ("sd.c: unable to allocate major array\n");
+ return -ENOMEM;
+ }
+ sd_template.majors[0] = SCSI_DISK0_MAJOR;
+ for (i = 1; (i < N_USED_SD_MAJORS) && (i <N_SD_PREASSIGNED_MAJORS);++i)
+ sd_template.majors[i] = SCSI_DISK1_MAJOR + i - 1;
+ for (; (i >= N_SD_PREASSIGNED_MAJORS) && (i < N_USED_SD_MAJORS); ++i) {
+ if ( ( major = devfs_alloc_major (DEVFS_SPECIAL_BLK) ) < 0 ) {
+ printk (KERN_WARNING __FUNCTION__ "() major[%d] allocation failed\n", i);
+ break;
+ }
+ sd_template.majors[i] = major;
+ }
+ sd_template.dev_max = i * SCSI_DISKS_PER_MAJOR;
+ sd_template.num_majors = i;
+ return 0;
+} /* End Function sd_alloc_majors */
+
+static void sd_dealloc_majors (void)
+/* Deallocate all the allocated majors
+ */
+{
+ int i;
+
+ for (i = sd_template.num_majors - 1; i >= N_SD_PREASSIGNED_MAJORS; --i)
+ devfs_dealloc_major (DEVFS_SPECIAL_BLK, sd_template.majors[i]);
+} /* End Function sd_dealloc_majors */
+
/*
* The sd_init() function looks at all SCSI drives present, determines
* their size, and reads partition table entries for them.
@@ -1068,16 +1114,20 @@
if (sd_template.dev_noticed == 0)
return 0;
- if (!rscsi_disks)
+ if (!rscsi_disks) {
+ if ( in_interrupt () ) {
+ printk (__FUNCTION__ "(): called from interrupt\n");
+ return 1;
+ }
sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-
- if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR)
- sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR;
+ if ( sd_alloc_majors() ) return 1;
+ }
if (!sd_registered) {
for (i = 0; i < N_USED_SD_MAJORS; i++) {
if (devfs_register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
+ sd_dealloc_majors();
return 1;
}
}
@@ -1087,22 +1137,22 @@
if (rscsi_disks)
return 0;
- rscsi_disks = kmalloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+ rscsi_disks = vmalloc(sd_template.dev_max * sizeof(Scsi_Disk));
if (!rscsi_disks)
goto cleanup_devfs;
memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
/* for every (necessary) major: */
- sd_sizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+ sd_sizes = vmalloc((sd_template.dev_max << 4) * sizeof(int));
if (!sd_sizes)
goto cleanup_disks;
memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
- sd_blocksizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+ sd_blocksizes = vmalloc((sd_template.dev_max << 4) * sizeof(int));
if (!sd_blocksizes)
goto cleanup_sizes;
- sd_hardsizes = kmalloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+ sd_hardsizes = vmalloc((sd_template.dev_max << 4) * sizeof(int));
if (!sd_hardsizes)
goto cleanup_blocksizes;
@@ -1115,9 +1165,7 @@
blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4);
hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
}
- sd = kmalloc((sd_template.dev_max << 4) *
- sizeof(struct hd_struct),
- GFP_ATOMIC);
+ sd = vmalloc((sd_template.dev_max << 4) * sizeof(struct hd_struct));
if (!sd)
goto cleanup_sd;
memset(sd, 0, (sd_template.dev_max << 4) * sizeof(struct hd_struct));
@@ -1164,19 +1212,20 @@
}
kfree(sd_gendisks);
cleanup_sd_gendisks:
- kfree(sd);
+ vfree(sd);
cleanup_sd:
- kfree(sd_hardsizes);
+ vfree(sd_hardsizes);
cleanup_blocksizes:
- kfree(sd_blocksizes);
+ vfree(sd_blocksizes);
cleanup_sizes:
- kfree(sd_sizes);
+ vfree(sd_sizes);
cleanup_disks:
- kfree(rscsi_disks);
+ vfree(rscsi_disks);
cleanup_devfs:
for (i = 0; i < N_USED_SD_MAJORS; i++) {
devfs_unregister_blkdev(SD_MAJOR(i), "sd");
}
+ sd_dealloc_majors();
sd_registered--;
return 1;
}
@@ -1384,6 +1433,7 @@
scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
+ sd_dealloc_majors();
for (i = 0; i < N_USED_SD_MAJORS; i++)
devfs_unregister_blkdev(SD_MAJOR(i), "sd");
diff -urN linux-2.4.10-pre3/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- linux-2.4.10-pre3/drivers/scsi/sd.h Wed Aug 15 15:23:15 2001
+++ linux/drivers/scsi/sd.h Sun Sep 2 10:23:53 2001
@@ -42,10 +42,14 @@
*/
extern kdev_t sd_find_target(void *host, int tgt);
-#define N_SD_MAJORS 8
+#define N_SD_PREASSIGNED_MAJORS 8
-#define SD_MAJOR_MASK (N_SD_MAJORS - 1)
+#ifdef CONFIG_SD_MANY
+#define SD_PARTITION(i) ((sd_devnum_to_index((i)) << 4) | ((i)&0x0f))
+#else
+#define SD_MAJOR_MASK (N_SD_PREASSIGNED_MAJORS - 1)
#define SD_PARTITION(i) (((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255))
+#endif
#endif
diff -urN linux-2.4.10-pre3/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- linux-2.4.10-pre3/drivers/scsi/sg.c Wed Jul 4 16:39:28 2001
+++ linux/drivers/scsi/sg.c Sun Sep 2 10:23:53 2001
@@ -123,7 +123,6 @@
{
tag:"sg",
scsi_type:0xff,
- major:SCSI_GENERIC_MAJOR,
detect:sg_detect,
init:sg_init,
finish:sg_finish,
diff -urN linux-2.4.10-pre3/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- linux-2.4.10-pre3/drivers/scsi/sr.c Sun Sep 2 10:22:27 2001
+++ linux/drivers/scsi/sr.c Sun Sep 2 10:23:53 2001
@@ -69,12 +69,15 @@
static int sr_init_command(Scsi_Cmnd *);
+static unsigned int sr_major = SCSI_CDROM_MAJOR;
+
static struct Scsi_Device_Template sr_template =
{
name:"cdrom",
tag:"sr",
scsi_type:TYPE_ROM,
- major:SCSI_CDROM_MAJOR,
+ majors:&sr_major,
+ num_majors:1,
blk:1,
detect:sr_detect,
init:sr_init,
diff -urN linux-2.4.10-pre3/drivers/scsi/st.c linux/drivers/scsi/st.c
--- linux-2.4.10-pre3/drivers/scsi/st.c Sun Aug 12 12:21:47 2001
+++ linux/drivers/scsi/st.c Sun Sep 2 10:23:53 2001
@@ -166,7 +166,6 @@
name:"tape",
tag:"st",
scsi_type:TYPE_TAPE,
- major:SCSI_TAPE_MAJOR,
detect:st_detect,
init:st_init,
attach:st_attach,
diff -urN linux-2.4.10-pre3/fs/devfs/base.c linux/fs/devfs/base.c
--- linux-2.4.10-pre3/fs/devfs/base.c Wed Jul 11 15:55:41 2001
+++ linux/fs/devfs/base.c Sun Sep 2 10:23:53 2001
@@ -388,7 +388,7 @@
Work sponsored by SGI.
v0.83
19991107 Richard Gooch <rgooch@atnf.csiro.au>
- Added DEVFS_ FL_WAIT flag.
+ Added DEVFS_FL_WAIT flag.
Work sponsored by SGI.
v0.84
19991107 Richard Gooch <rgooch@atnf.csiro.au>
@@ -511,6 +511,37 @@
Removed broken devnum allocation and use <devfs_alloc_devnum>.
Fixed old devnum leak by calling new <devfs_dealloc_devnum>.
v0.107
+ 20010712 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bug in <devfs_setup> which could hang boot process.
+ v0.108
+ 20010730 Richard Gooch <rgooch@atnf.csiro.au>
+ Added DEVFSD_NOTIFY_DELETE event.
+ 20010801 Richard Gooch <rgooch@atnf.csiro.au>
+ Removed #include <asm/segment.h>.
+ v0.109
+ 20010807 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed inode table races by removing it and using
+ inode->u.generic_ip instead.
+ Moved <devfs_read_inode> into <get_vfs_inode>.
+ Moved <devfs_write_inode> into <devfs_notify_change>.
+ v0.110
+ 20010808 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed race in <devfs_do_symlink> for uni-processor.
+ v0.111
+ 20010818 Richard Gooch <rgooch@atnf.csiro.au>
+ Removed remnant of multi-mount support in <devfs_mknod>.
+ Removed unused DEVFS_FL_SHOW_UNREG flag.
+ v0.112
+ 20010820 Richard Gooch <rgooch@atnf.csiro.au>
+ Removed nlink field from struct devfs_inode.
+ v0.113
+ 20010823 Richard Gooch <rgooch@atnf.csiro.au>
+ Replaced BKL with global rwsem to protect symlink data (quick
+ and dirty hack).
+ v0.114
+ 20010827 Richard Gooch <rgooch@atnf.csiro.au>
+ Replaced global rwsem for symlink with per-link refcount.
+ v0.115
*/
#include <linux/types.h>
#include <linux/errno.h>
@@ -533,21 +564,20 @@
#include <linux/smp_lock.h>
#include <linux/smp.h>
#include <linux/version.h>
+#include <linux/rwsem.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
-#define DEVFS_VERSION "0.107 (20010709)"
+#define DEVFS_VERSION "0.115 (20010827)"
#define DEVFS_NAME "devfs"
-#define INODE_TABLE_INC 250
#define FIRST_INODE 1
#define STRING_LENGTH 256
@@ -557,7 +587,7 @@
# define FALSE 0
#endif
-#define IS_HIDDEN(de) (( ((de)->hide && !is_devfsd_or_child(fs_info)) || (!(de)->registered&& !(de)->show_unreg)))
+#define IS_HIDDEN(de) (( ((de)->hide && !is_devfsd_or_child(fs_info)) || !(de)->registered))
#define DEBUG_NONE 0x00000
#define DEBUG_MODULE_LOAD 0x00001
@@ -567,8 +597,8 @@
#define DEBUG_S_PUT 0x00010
#define DEBUG_I_LOOKUP 0x00020
#define DEBUG_I_CREATE 0x00040
-#define DEBUG_I_READ 0x00080
-#define DEBUG_I_WRITE 0x00100
+#define DEBUG_I_GET 0x00080
+#define DEBUG_I_CHANGE 0x00100
#define DEBUG_I_UNLINK 0x00200
#define DEBUG_I_RLINK 0x00400
#define DEBUG_I_FLINK 0x00800
@@ -577,16 +607,12 @@
#define DEBUG_D_DELETE 0x04000
#define DEBUG_D_RELEASE 0x08000
#define DEBUG_D_IPUT 0x10000
-#define DEBUG_ALL (DEBUG_MODULE_LOAD | DEBUG_REGISTER | \
- DEBUG_SET_FLAGS | DEBUG_I_LOOKUP | \
- DEBUG_I_UNLINK | DEBUG_I_MKNOD | \
- DEBUG_D_RELEASE | DEBUG_D_IPUT)
+#define DEBUG_ALL 0xfffff
#define DEBUG_DISABLED DEBUG_NONE
#define OPTION_NONE 0x00
-#define OPTION_SHOW 0x01
-#define OPTION_MOUNT 0x02
-#define OPTION_ONLY 0x04
+#define OPTION_MOUNT 0x01
+#define OPTION_ONLY 0x02
#define OOPS(format, args...) {printk (format, ## args); \
printk ("Forcing Oops\n"); \
@@ -630,8 +656,10 @@
struct symlink_type
{
- unsigned int length; /* Not including the NULL-termimator */
- char *linkname; /* This is NULL-terminated */
+ atomic_t refcount; /* When this drops to zero, it's unused */
+ rwlock_t lock; /* Lock around the registered flag */
+ unsigned int length; /* Not including the NULL-termimator */
+ char *linkname; /* This is NULL-terminated */
};
struct fifo_type
@@ -650,7 +678,6 @@
umode_t mode;
uid_t uid;
gid_t gid;
- nlink_t nlink;
};
struct devfs_entry
@@ -672,7 +699,6 @@
umode_t mode;
unsigned short namelen; /* I think 64k+ filenames are a way off... */
unsigned char registered:1;
- unsigned char show_unreg:1;
unsigned char hide:1;
unsigned char no_persistence:1;
char name[1]; /* This is just a dummy: the allocated array is
@@ -693,9 +719,6 @@
struct fs_info /* This structure is for the mounted devfs */
{
- unsigned int num_inodes; /* Number of inodes created */
- unsigned int table_size; /* Size of the inode pointer table */
- struct devfs_entry **table;
struct super_block *sb;
volatile struct devfsd_buf_entry *devfsd_buffer;
spinlock_t devfsd_buffer_lock;
@@ -765,7 +788,7 @@
unsigned int namelen,
int traverse_symlink)
{
- struct devfs_entry *curr;
+ struct devfs_entry *curr, *retval;
if ( !S_ISDIR (parent->mode) )
{
@@ -781,48 +804,41 @@
if (curr == NULL) return NULL;
if (!S_ISLNK (curr->mode) || !traverse_symlink) return curr;
/* Need to follow the link: this is a stack chomper */
- return search_for_entry (parent,
- curr->u.symlink.linkname, curr->u.symlink.length,
- FALSE, FALSE, NULL, TRUE);
+ read_lock (&curr->u.symlink.lock);
+ if (!curr->registered)
+ {
+ read_unlock (&curr->u.symlink.lock);
+ return NULL;
+ }
+ atomic_inc (&curr->u.symlink.refcount);
+ read_unlock (&curr->u.symlink.lock);
+ retval = search_for_entry (parent, curr->u.symlink.linkname,
+ curr->u.symlink.length, FALSE, FALSE, NULL,
+ TRUE);
+ if ( atomic_dec_and_test (&curr->u.symlink.refcount) )
+ kfree (curr->u.symlink.linkname);
+ return retval;
} /* End Function search_for_entry_in_dir */
static struct devfs_entry *create_entry (struct devfs_entry *parent,
const char *name,unsigned int namelen)
{
- struct devfs_entry *new, **table;
+ struct devfs_entry *new;
+ static unsigned long inode_counter = FIRST_INODE;
+ static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED;
- /* First ensure table size is enough */
- if (fs_info.num_inodes >= fs_info.table_size)
- {
- if ( ( table = kmalloc (sizeof *table *
- (fs_info.table_size + INODE_TABLE_INC),
- GFP_KERNEL) ) == NULL ) return NULL;
- fs_info.table_size += INODE_TABLE_INC;
-#ifdef CONFIG_DEVFS_DEBUG
- if (devfs_debug & DEBUG_I_CREATE)
- printk ("%s: create_entry(): grew inode table to: %u entries\n",
- DEVFS_NAME, fs_info.table_size);
-#endif
- if (fs_info.table)
- {
- memcpy (table, fs_info.table, sizeof *table *fs_info.num_inodes);
- kfree (fs_info.table);
- }
- fs_info.table = table;
- }
if ( name && (namelen < 1) ) namelen = strlen (name);
if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL )
return NULL;
/* Magic: this will set the ctime to zero, thus subsequent lookups will
trigger the call to <update_devfs_inode_from_entry> */
memset (new, 0, sizeof *new + namelen);
+ spin_lock (&counter_lock);
+ new->inode.ino = inode_counter++;
+ spin_unlock (&counter_lock);
new->parent = parent;
if (name) memcpy (new->name, name, namelen);
new->namelen = namelen;
- new->inode.ino = fs_info.num_inodes + FIRST_INODE;
- new->inode.nlink = 1;
- fs_info.table[fs_info.num_inodes] = new;
- ++fs_info.num_inodes;
if (parent == NULL) return new;
new->prev = parent->u.dir.last;
/* Insert into the parent directory's list of children */
@@ -1083,14 +1099,10 @@
int do_check)
{
struct devfs_entry *de;
- struct fs_info *fs_info;
if (inode == NULL) return NULL;
- if (inode->i_ino < FIRST_INODE) return NULL;
- fs_info = inode->i_sb->u.generic_sbp;
- if (fs_info == NULL) return NULL;
- if (inode->i_ino - FIRST_INODE >= fs_info->num_inodes) return NULL;
- de = fs_info->table[inode->i_ino - FIRST_INODE];
+ de = inode->u.generic_ip;
+ if (!de) printk (__FUNCTION__ "(): NULL de for inode %ld\n", inode->i_ino);
if (do_check && de && !de->registered) de = NULL;
return de;
} /* End Function get_devfs_entry_from_vfs_inode */
@@ -1342,12 +1354,12 @@
return NULL;
}
}
- de->u.fcb.autogen = 0;
+ de->u.fcb.autogen = FALSE;
if ( S_ISCHR (mode) || S_ISBLK (mode) )
{
de->u.fcb.u.device.major = major;
de->u.fcb.u.device.minor = minor;
- de->u.fcb.autogen = (devnum == NODEV) ? 0 : 1;
+ de->u.fcb.autogen = (devnum == NODEV) ? FALSE : TRUE;
}
else if ( S_ISREG (mode) ) de->u.fcb.u.file.size = 0;
else
@@ -1377,8 +1389,6 @@
++de->parent->u.dir.num_removable;
}
de->u.fcb.open = FALSE;
- de->show_unreg = ( (boot_options & OPTION_SHOW)
- || (flags & DEVFS_FL_SHOW_UNREG) ) ? TRUE : FALSE;
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
de->no_persistence = (flags & DEVFS_FL_NO_PERSISTENCE) ? TRUE : FALSE;
de->registered = TRUE;
@@ -1418,13 +1428,16 @@
MKDEV (de->u.fcb.u.device.major,
de->u.fcb.u.device.minor) );
}
- de->u.fcb.autogen = 0;
+ de->u.fcb.autogen = FALSE;
return;
}
if (S_ISLNK (de->mode) && de->registered)
{
+ write_lock (&de->u.symlink.lock);
de->registered = FALSE;
- kfree (de->u.symlink.linkname);
+ write_unlock (&de->u.symlink.lock);
+ if ( atomic_dec_and_test (&de->u.symlink.refcount) )
+ kfree (de->u.symlink.linkname);
return;
}
if ( S_ISFIFO (de->mode) )
@@ -1475,7 +1488,7 @@
{
int is_new;
unsigned int linklength;
- char *newname;
+ char *newlink;
struct devfs_entry *de;
if (handle != NULL) *handle = NULL;
@@ -1494,49 +1507,32 @@
return -EINVAL;
}
linklength = strlen (link);
- de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new,
- FALSE);
- if (de == NULL) return -ENOMEM;
- if (!S_ISLNK (de->mode) && de->registered)
+ if ( ( newlink = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )
+ return -ENOMEM;
+ memcpy (newlink, link, linklength);
+ newlink[linklength] = '\0';
+ if ( ( de = search_for_entry (dir, name, strlen (name), TRUE, TRUE,
+ &is_new, FALSE) ) == NULL )
{
- printk ("%s: devfs_do_symlink(): non-link entry already exists\n",
- DEVFS_NAME);
+ kfree (newlink);
+ return -ENOMEM;
+ }
+ if (de->registered)
+ {
+ kfree (newlink);
+ printk ("%s: devfs_do_symlink(%s): entry already exists\n",
+ DEVFS_NAME, name);
return -EEXIST;
}
- if (handle != NULL) *handle = de;
de->mode = S_IFLNK | S_IRUGO | S_IXUGO;
de->info = info;
- de->show_unreg = ( (boot_options & OPTION_SHOW)
- || (flags & DEVFS_FL_SHOW_UNREG) ) ? TRUE : FALSE;
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
- /* Note there is no need to fiddle the dentry cache if the symlink changes
- as the symlink follow method is called every time it's needed */
- if ( de->registered && (linklength == de->u.symlink.length) )
- {
- /* New link is same length as old link */
- if (memcmp (link, de->u.symlink.linkname, linklength) == 0) return 0;
- return -EEXIST; /* Contents would change */
- }
- /* Have to create/update */
- if (de->registered) return -EEXIST;
- if ( ( newname = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )
- {
- struct devfs_entry *parent = de->parent;
-
- if (!is_new) return -ENOMEM;
- /* Have to clean up */
- if (de->prev == NULL) parent->u.dir.first = de->next;
- else de->prev->next = de->next;
- if (de->next == NULL) parent->u.dir.last = de->prev;
- else de->next->prev = de->prev;
- kfree (de);
- return -ENOMEM;
- }
- de->u.symlink.linkname = newname;
- memcpy (de->u.symlink.linkname, link, linklength);
- de->u.symlink.linkname[linklength] = '\0';
+ de->u.symlink.linkname = newlink;
de->u.symlink.length = linklength;
+ atomic_set (&de->u.symlink.refcount, 1);
+ rwlock_init (&de->u.symlink.lock);
de->registered = TRUE;
+ if (handle != NULL) *handle = de;
return 0;
} /* End Function devfs_do_symlink */
@@ -1621,7 +1617,6 @@
de->mode = S_IFDIR | S_IRUGO | S_IXUGO;
de->info = info;
if (!de->registered) de->u.dir.num_removable = 0;
- de->show_unreg = (boot_options & OPTION_SHOW) ? TRUE : FALSE;
de->hide = FALSE;
de->registered = TRUE;
return de;
@@ -1674,7 +1669,6 @@
if (de == NULL) return -EINVAL;
if (!de->registered) return -ENODEV;
- if (de->show_unreg) fl |= DEVFS_FL_SHOW_UNREG;
if (de->hide) fl |= DEVFS_FL_HIDE;
if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
{
@@ -1704,7 +1698,6 @@
printk ("%s: devfs_set_flags(): de->name: \"%s\"\n",
DEVFS_NAME, de->name);
#endif
- de->show_unreg = (flags & DEVFS_FL_SHOW_UNREG) ? TRUE : FALSE;
de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
{
@@ -2053,16 +2046,16 @@
{"dmod", DEBUG_MODULE_LOAD, &devfs_debug_init},
{"dreg", DEBUG_REGISTER, &devfs_debug_init},
{"dunreg", DEBUG_UNREGISTER, &devfs_debug_init},
- {"diread", DEBUG_I_READ, &devfs_debug_init},
+ {"diget", DEBUG_I_GET, &devfs_debug_init},
{"dchange", DEBUG_SET_FLAGS, &devfs_debug_init},
- {"diwrite", DEBUG_I_WRITE, &devfs_debug_init},
+ {"dichange", DEBUG_I_CHANGE, &devfs_debug_init},
{"dimknod", DEBUG_I_MKNOD, &devfs_debug_init},
{"dilookup", DEBUG_I_LOOKUP, &devfs_debug_init},
{"diunlink", DEBUG_I_UNLINK, &devfs_debug_init},
#endif /* CONFIG_DEVFS_DEBUG */
- {"show", OPTION_SHOW, &boot_options},
{"only", OPTION_ONLY, &boot_options},
{"mount", OPTION_MOUNT, &boot_options},
+ {NULL, 0, NULL}
};
while ( (*str != '\0') && !isspace (*str) )
@@ -2074,7 +2067,7 @@
invert = 1;
str += 2;
}
- for (i = 0; i < sizeof (devfs_options_tab); i++)
+ for (i = 0; devfs_options_tab[i].name != NULL; i++)
{
int len = strlen (devfs_options_tab[i].name);
@@ -2247,121 +2240,36 @@
static struct file_operations devfs_dir_fops;
static struct inode_operations devfs_symlink_iops;
-static void devfs_read_inode (struct inode *inode)
-{
- struct devfs_entry *de;
-
- de = get_devfs_entry_from_vfs_inode (inode, TRUE);
- if (de == NULL)
- {
- printk ("%s: read_inode(%d): VFS inode: %p NO devfs_entry\n",
- DEVFS_NAME, (int) inode->i_ino, inode);
- return;
- }
-#ifdef CONFIG_DEVFS_DEBUG
- if (devfs_debug & DEBUG_I_READ)
- printk ("%s: read_inode(%d): VFS inode: %p devfs_entry: %p\n",
- DEVFS_NAME, (int) inode->i_ino, inode, de);
-#endif
- inode->i_blocks = 0;
- inode->i_blksize = 1024;
- inode->i_op = &devfs_iops;
- inode->i_fop = &devfs_fops;
- inode->i_rdev = NODEV;
- if ( S_ISCHR (de->inode.mode) )
- {
- inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
- inode->i_cdev = cdget (kdev_t_to_nr(inode->i_rdev));
- }
- else if ( S_ISBLK (de->inode.mode) )
- {
- inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
- de->u.fcb.u.device.minor);
- inode->i_bdev = bdget (kdev_t_to_nr(inode->i_rdev));
- if (inode->i_bdev)
- {
- if (!inode->i_bdev->bd_op && de->u.fcb.ops)
- inode->i_bdev->bd_op = de->u.fcb.ops;
- }
- else printk ("%s: read_inode(%d): no block device from bdget()\n",
- DEVFS_NAME, (int) inode->i_ino);
- }
- else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops;
- else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size;
- else if ( S_ISDIR (de->inode.mode) )
- {
- inode->i_op = &devfs_dir_iops;
- inode->i_fop = &devfs_dir_fops;
- }
- else if ( S_ISLNK (de->inode.mode) )
- {
- inode->i_op = &devfs_symlink_iops;
- inode->i_size = de->u.symlink.length;
- }
- inode->i_mode = de->inode.mode;
- inode->i_uid = de->inode.uid;
- inode->i_gid = de->inode.gid;
- inode->i_atime = de->inode.atime;
- inode->i_mtime = de->inode.mtime;
- inode->i_ctime = de->inode.ctime;
- inode->i_nlink = de->inode.nlink;
-#ifdef CONFIG_DEVFS_DEBUG
- if (devfs_debug & DEBUG_I_READ)
- printk ("%s: mode: 0%o uid: %d gid: %d\n",
- DEVFS_NAME, (int) inode->i_mode,
- (int) inode->i_uid, (int) inode->i_gid);
-#endif
-} /* End Function devfs_read_inode */
-
-static void devfs_write_inode (struct inode *inode, int wait)
+static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr)
{
- int index;
+ int retval;
struct devfs_entry *de;
+ struct inode *inode = dentry->d_inode;
struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
- if (inode->i_ino < FIRST_INODE) return;
- index = inode->i_ino - FIRST_INODE;
- lock_kernel ();
- if (index >= fs_info->num_inodes)
- {
- printk ("%s: writing inode: %lu for which there is no entry!\n",
- DEVFS_NAME, inode->i_ino);
- unlock_kernel ();
- return;
- }
- de = fs_info->table[index];
+ de = get_devfs_entry_from_vfs_inode (inode, TRUE);
+ if (de == NULL) return -ENODEV;
+ retval = inode_change_ok (inode, iattr);
+ if (retval != 0) return retval;
+ inode_setattr (inode, iattr);
#ifdef CONFIG_DEVFS_DEBUG
- if (devfs_debug & DEBUG_I_WRITE)
+ if (devfs_debug & DEBUG_I_CHANGE)
{
- printk ("%s: write_inode(%d): VFS inode: %p devfs_entry: %p\n",
+ printk ("%s: notify_change(%d): VFS inode: %p devfs_entry: %p\n",
DEVFS_NAME, (int) inode->i_ino, inode, de);
printk ("%s: mode: 0%o uid: %d gid: %d\n",
DEVFS_NAME, (int) inode->i_mode,
(int) inode->i_uid, (int) inode->i_gid);
}
#endif
+ /* Inode is not on hash chains, thus must save permissions here rather
+ than in a write_inode() method */
de->inode.mode = inode->i_mode;
de->inode.uid = inode->i_uid;
de->inode.gid = inode->i_gid;
de->inode.atime = inode->i_atime;
de->inode.mtime = inode->i_mtime;
de->inode.ctime = inode->i_ctime;
- unlock_kernel ();
-} /* End Function devfs_write_inode */
-
-static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr)
-{
- int retval;
- struct devfs_entry *de;
- struct inode *inode = dentry->d_inode;
- struct fs_info *fs_info = inode->i_sb->u.generic_sbp;
-
- de = get_devfs_entry_from_vfs_inode (inode, TRUE);
- if (de == NULL) return -ENODEV;
- retval = inode_change_ok (inode, iattr);
- if (retval != 0) return retval;
- inode_setattr (inode, iattr);
if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) )
devfsd_notify_one (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode,
inode->i_uid, inode->i_gid, fs_info);
@@ -2381,8 +2289,7 @@
static struct super_operations devfs_sops =
{
- read_inode: devfs_read_inode,
- write_inode: devfs_write_inode,
+ put_inode: force_delete,
statfs: devfs_statfs,
};
@@ -2411,8 +2318,68 @@
printk (" old inode: %p\n", de->inode.dentry->d_inode);
return NULL;
}
- if ( ( inode = iget (sb, de->inode.ino) ) == NULL ) return NULL;
+ if ( ( inode = new_inode (sb) ) == NULL )
+ {
+ printk ("%s: get_vfs_inode(%s): new_inode() failed, de: %p\n",
+ DEVFS_NAME, de->name, de);
+ return NULL;
+ }
de->inode.dentry = dentry;
+ inode->u.generic_ip = de;
+ inode->i_ino = de->inode.ino;
+#ifdef CONFIG_DEVFS_DEBUG
+ if (devfs_debug & DEBUG_I_GET)
+ printk ("%s: get_vfs_inode(%d): VFS inode: %p devfs_entry: %p\n",
+ DEVFS_NAME, (int) inode->i_ino, inode, de);
+#endif
+ inode->i_blocks = 0;
+ inode->i_blksize = 1024;
+ inode->i_op = &devfs_iops;
+ inode->i_fop = &devfs_fops;
+ inode->i_rdev = NODEV;
+ if ( S_ISCHR (de->inode.mode) )
+ {
+ inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
+ inode->i_cdev = cdget (kdev_t_to_nr(inode->i_rdev));
+ }
+ else if ( S_ISBLK (de->inode.mode) )
+ {
+ inode->i_rdev = MKDEV (de->u.fcb.u.device.major,
+ de->u.fcb.u.device.minor);
+ inode->i_bdev = bdget (kdev_t_to_nr(inode->i_rdev));
+ if (inode->i_bdev)
+ {
+ if (!inode->i_bdev->bd_op && de->u.fcb.ops)
+ inode->i_bdev->bd_op = de->u.fcb.ops;
+ }
+ else printk ("%s: get_vfs_inode(%d): no block device from bdget()\n",
+ DEVFS_NAME, (int) inode->i_ino);
+ }
+ else if ( S_ISFIFO (de->inode.mode) ) inode->i_fop = &def_fifo_fops;
+ else if ( S_ISREG (de->inode.mode) ) inode->i_size = de->u.fcb.u.file.size;
+ else if ( S_ISDIR (de->inode.mode) )
+ {
+ inode->i_op = &devfs_dir_iops;
+ inode->i_fop = &devfs_dir_fops;
+ }
+ else if ( S_ISLNK (de->inode.mode) )
+ {
+ inode->i_op = &devfs_symlink_iops;
+ inode->i_size = de->u.symlink.length;
+ }
+ inode->i_mode = de->inode.mode;
+ inode->i_uid = de->inode.uid;
+ inode->i_gid = de->inode.gid;
+ inode->i_atime = de->inode.atime;
+ inode->i_mtime = de->inode.mtime;
+ inode->i_ctime = de->inode.ctime;
+#ifdef CONFIG_DEVFS_DEBUG
+ if (devfs_debug & DEBUG_I_GET)
+ printk ("%s: mode: 0%o uid: %d gid: %d\n",
+ DEVFS_NAME, (int) inode->i_mode,
+ (int) inode->i_uid, (int) inode->i_gid);
+#endif
return inode;
} /* End Function get_vfs_inode */
@@ -2725,14 +2692,14 @@
memcpy (txt, dentry->d_name.name,
(dentry->d_name.len >= STRING_LENGTH) ?
(STRING_LENGTH - 1) : dentry->d_name.len);
-#ifdef CONFIG_DEVFS_DEBUG
- if (devfs_debug & DEBUG_I_LOOKUP)
- printk ("%s: lookup(%s): dentry: %p by: \"%s\"\n",
- DEVFS_NAME, txt, dentry, current->comm);
-#endif
fs_info = dir->i_sb->u.generic_sbp;
/* First try to get the devfs entry for this directory */
parent = get_devfs_entry_from_vfs_inode (dir, TRUE);
+#ifdef CONFIG_DEVFS_DEBUG
+ if (devfs_debug & DEBUG_I_LOOKUP)
+ printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n",
+ DEVFS_NAME, txt, dentry, parent, current->comm);
+#endif
if (parent == NULL) return ERR_PTR (-ENOENT);
/* Try to reclaim an existing devfs entry */
de = search_for_entry_in_dir (parent,
@@ -2823,6 +2790,7 @@
static int devfs_unlink (struct inode *dir, struct dentry *dentry)
{
struct devfs_entry *de;
+ struct inode *inode = dentry->d_inode;
#ifdef CONFIG_DEVFS_DEBUG
char txt[STRING_LENGTH];
@@ -2838,9 +2806,18 @@
de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
if (de == NULL) return -ENOENT;
- de->registered = FALSE;
+ devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+ inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp);
+ if ( S_ISLNK (de->mode) )
+ {
+ write_lock (&de->u.symlink.lock);
+ de->registered = FALSE;
+ write_unlock (&de->u.symlink.lock);
+ if ( atomic_dec_and_test (&de->u.symlink.refcount) )
+ kfree (de->u.symlink.linkname);
+ }
+ else de->registered = FALSE;
de->hide = TRUE;
- if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname);
free_dentries (de);
return 0;
} /* End Function devfs_unlink */
@@ -2954,6 +2931,8 @@
}
}
if (has_children) return -ENOTEMPTY;
+ devfsd_notify_one (de, DEVFSD_NOTIFY_DELETE, inode->i_mode,
+ inode->i_uid, inode->i_gid, fs_info);
de->hide = TRUE;
de->registered = FALSE;
free_dentries (de);
@@ -2989,29 +2968,29 @@
de = search_for_entry (parent, dentry->d_name.name, dentry->d_name.len,
FALSE, TRUE, &is_new, FALSE);
if (de == NULL) return -ENOMEM;
- if (!de->registered)
+ if (de->registered)
{
- /* Since we created the devfs entry we get to choose things */
- de->info = NULL;
- de->mode = mode;
- if ( S_ISBLK (mode) || S_ISCHR (mode) )
- {
- de->u.fcb.u.device.major = MAJOR (rdev);
- de->u.fcb.u.device.minor = MINOR (rdev);
- de->u.fcb.default_uid = current->euid;
- de->u.fcb.default_gid = current->egid;
- de->u.fcb.ops = NULL;
- de->u.fcb.auto_owner = FALSE;
- de->u.fcb.aopen_notify = FALSE;
- de->u.fcb.open = FALSE;
- }
- else if ( S_ISFIFO (mode) )
- {
- de->u.fifo.uid = current->euid;
- de->u.fifo.gid = current->egid;
- }
+ printk ("%s: mknod(): existing entry\n", DEVFS_NAME);
+ return -EEXIST;
+ }
+ de->info = NULL;
+ de->mode = mode;
+ if ( S_ISBLK (mode) || S_ISCHR (mode) )
+ {
+ de->u.fcb.u.device.major = MAJOR (rdev);
+ de->u.fcb.u.device.minor = MINOR (rdev);
+ de->u.fcb.default_uid = current->euid;
+ de->u.fcb.default_gid = current->egid;
+ de->u.fcb.ops = NULL;
+ de->u.fcb.auto_owner = FALSE;
+ de->u.fcb.aopen_notify = FALSE;
+ de->u.fcb.open = FALSE;
+ }
+ else if ( S_ISFIFO (mode) )
+ {
+ de->u.fifo.uid = current->euid;
+ de->u.fifo.gid = current->egid;
}
- de->show_unreg = FALSE;
de->hide = FALSE;
de->inode.mode = mode;
de->inode.uid = current->euid;
@@ -3038,11 +3017,19 @@
int err;
struct devfs_entry *de;
- lock_kernel ();
de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
- err = de ? vfs_readlink (dentry, buffer, buflen,
- de->u.symlink.linkname) : -ENODEV;
- unlock_kernel ();
+ if (!de) return -ENODEV;
+ read_lock (&de->u.symlink.lock);
+ if (!de->registered)
+ {
+ read_unlock (&de->u.symlink.lock);
+ return -ENODEV;
+ }
+ atomic_inc (&de->u.symlink.refcount);
+ read_unlock (&de->u.symlink.lock);
+ err = vfs_readlink (dentry, buffer, buflen, de->u.symlink.linkname);
+ if ( atomic_dec_and_test (&de->u.symlink.refcount) )
+ kfree (de->u.symlink.linkname);
return err;
} /* End Function devfs_readlink */
@@ -3051,10 +3038,19 @@
int err;
struct devfs_entry *de;
- lock_kernel ();
de = get_devfs_entry_from_vfs_inode (dentry->d_inode, TRUE);
- err = de ? vfs_follow_link (nd, de->u.symlink.linkname) : -ENODEV;
- unlock_kernel ();
+ if (!de) return -ENODEV;
+ read_lock (&de->u.symlink.lock);
+ if (!de->registered)
+ {
+ read_unlock (&de->u.symlink.lock);
+ return -ENODEV;
+ }
+ atomic_inc (&de->u.symlink.refcount);
+ read_unlock (&de->u.symlink.lock);
+ err = vfs_follow_link (nd, de->u.symlink.linkname);
+ if ( atomic_dec_and_test (&de->u.symlink.refcount) )
+ kfree (de->u.symlink.linkname);
return err;
} /* End Function devfs_follow_link */
diff -urN linux-2.4.10-pre3/fs/devfs/util.c linux/fs/devfs/util.c
--- linux-2.4.10-pre3/fs/devfs/util.c Wed Jul 11 15:55:41 2001
+++ linux/fs/devfs/util.c Sun Sep 2 10:23:53 2001
@@ -39,6 +39,15 @@
Created <devfs_*alloc_major> and <devfs_*alloc_devnum>.
20010710 Richard Gooch <rgooch@atnf.csiro.au>
Created <devfs_*alloc_unique_number>.
+ 20010730 Richard Gooch <rgooch@atnf.csiro.au>
+ Documentation typo fix.
+ 20010806 Richard Gooch <rgooch@atnf.csiro.au>
+ Made <block_semaphore> and <char_semaphore> private.
+ 20010813 Richard Gooch <rgooch@atnf.csiro.au>
+ Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
+ 20010818 Richard Gooch <rgooch@atnf.csiro.au>
+ Updated major masks up to Linus' "no new majors" proclamation.
+ Block: were 126 now 122 free, char: were 26 now 19 free.
*/
#include <linux/module.h>
#include <linux/init.h>
@@ -181,15 +190,15 @@
};
/* Block majors already assigned:
- 0-3, 7-9, 11-12, 13-63, 65-93, 95-99, 101, 103-111, 120-127, 199, 201,
- 240-255
+ 0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
+ Total free: 122
*/
static struct major_list block_major_list =
{SPIN_LOCK_UNLOCKED,
{0xfffffb8f, /* Majors 0 to 31 */
0xffffffff, /* Majors 32 to 63 */
- 0xbffffffe, /* Majors 64 to 95 */
- 0xff00ffaf, /* Majors 96 to 127 */
+ 0xfffffffe, /* Majors 64 to 95 */
+ 0xff03ffef, /* Majors 96 to 127 */
0x00000000, /* Majors 128 to 159 */
0x00000000, /* Majors 160 to 191 */
0x00000280, /* Majors 192 to 223 */
@@ -197,7 +206,8 @@
};
/* Char majors already assigned:
- 0-7, 9-151, 154-158, 160-195, 198-211, 216-221, 224-225, 240-255
+ 0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
+ Total free: 19
*/
static struct major_list char_major_list =
{SPIN_LOCK_UNLOCKED,
@@ -207,14 +217,14 @@
0xffffffff, /* Majors 96 to 127 */
0x7cffffff, /* Majors 128 to 159 */
0xffffffff, /* Majors 160 to 191 */
- 0x3f0fffcf, /* Majors 192 to 223 */
- 0xffff0003} /* Majors 224 to 255 */
+ 0x3f0fffff, /* Majors 192 to 223 */
+ 0xffff007f} /* Majors 224 to 255 */
};
/**
* devfs_alloc_major - Allocate a major number.
- * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK)
+ * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
* Returns the allocated major, else -1 if none are available.
* This routine is thread safe and does not block.
@@ -238,7 +248,7 @@
/**
* devfs_dealloc_major - Deallocate a major number.
- * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK)
+ * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
* @major: The major number.
* This routine is thread safe and does not block.
*/
@@ -273,16 +283,16 @@
int none_free;
};
-DECLARE_MUTEX (block_semaphore);
+static DECLARE_MUTEX (block_semaphore);
static struct device_list block_list;
-DECLARE_MUTEX (char_semaphore);
+static DECLARE_MUTEX (char_semaphore);
static struct device_list char_list;
/**
* devfs_alloc_devnum - Allocate a device number.
- * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK).
+ * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
*
* Returns the allocated device number, else NODEV if none are available.
* This routine is thread safe and may block.
@@ -347,7 +357,7 @@
/**
* devfs_dealloc_devnum - Dellocate a device number.
- * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLOCK).
+ * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
* @devnum: The device number.
*
* This routine is thread safe and does not block.
@@ -437,6 +447,7 @@
space->length = length;
}
number = find_first_zero_bit (space->bits, space->length << 3);
+ --space->num_free;
__set_bit (number, space->bits);
up (&space->semaphore);
return number;
diff -urN linux-2.4.10-pre3/include/linux/blk.h linux/include/linux/blk.h
--- linux-2.4.10-pre3/include/linux/blk.h Wed Aug 15 15:21:32 2001
+++ linux/include/linux/blk.h Sun Sep 2 10:23:53 2001
@@ -144,7 +144,11 @@
#define DEVICE_NAME "scsidisk"
#define TIMEOUT_VALUE (2*HZ)
+#ifdef CONFIG_SD_MANY
+#define DEVICE_NR(device) sd_devnum_to_index((device))
+#else
#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+#endif
/* Kludge to use the same number for both char and block major numbers */
#elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
diff -urN linux-2.4.10-pre3/include/linux/devfs_fs.h linux/include/linux/devfs_fs.h
--- linux-2.4.10-pre3/include/linux/devfs_fs.h Wed Feb 16 16:42:06 2000
+++ linux/include/linux/devfs_fs.h Sun Sep 2 10:23:53 2001
@@ -20,6 +20,7 @@
#define DEVFSD_NOTIFY_LOOKUP 4
#define DEVFSD_NOTIFY_CHANGE 5
#define DEVFSD_NOTIFY_CREATE 6
+#define DEVFSD_NOTIFY_DELETE 7
#define DEVFS_PATHLEN 1024 /* Never change this otherwise the
binary interface will change */
diff -urN linux-2.4.10-pre3/include/linux/devfs_fs_kernel.h linux/include/linux/devfs_fs_kernel.h
--- linux-2.4.10-pre3/include/linux/devfs_fs_kernel.h Wed Aug 15 15:21:30 2001
+++ linux/include/linux/devfs_fs_kernel.h Sun Sep 2 10:23:53 2001
@@ -30,17 +30,15 @@
is closed, ownership reverts back to
<<uid>> and <<gid>> and the protection
is set to read-write for all */
-#define DEVFS_FL_SHOW_UNREG 0x002 /* Show unregistered entries in
- directory listings */
-#define DEVFS_FL_HIDE 0x004 /* Do not show entry in directory list */
-#define DEVFS_FL_AUTO_DEVNUM 0x008 /* Automatically generate device number
+#define DEVFS_FL_HIDE 0x002 /* Do not show entry in directory list */
+#define DEVFS_FL_AUTO_DEVNUM 0x004 /* Automatically generate device number
*/
-#define DEVFS_FL_AOPEN_NOTIFY 0x010 /* Asynchronously notify devfsd on open
+#define DEVFS_FL_AOPEN_NOTIFY 0x008 /* Asynchronously notify devfsd on open
*/
-#define DEVFS_FL_REMOVABLE 0x020 /* This is a removable media device */
-#define DEVFS_FL_WAIT 0x040 /* Wait for devfsd to finish */
-#define DEVFS_FL_NO_PERSISTENCE 0x080 /* Forget changes after unregister */
-#define DEVFS_FL_CURRENT_OWNER 0x100 /* Set initial ownership to current */
+#define DEVFS_FL_REMOVABLE 0x010 /* This is a removable media device */
+#define DEVFS_FL_WAIT 0x020 /* Wait for devfsd to finish */
+#define DEVFS_FL_NO_PERSISTENCE 0x040 /* Forget changes after unregister */
+#define DEVFS_FL_CURRENT_OWNER 0x080 /* Set initial ownership to current */
#define DEVFS_FL_DEFAULT DEVFS_FL_NONE
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/