Commit bc93ea47 authored by Richard Gooch's avatar Richard Gooch

Fixed race when devfs lookup()/readdir() triggers partition rescanning.

parent d7760f3b
...@@ -1926,3 +1926,8 @@ Changes for patch v211 ...@@ -1926,3 +1926,8 @@ Changes for patch v211
Changes for patch v212 Changes for patch v212
- Added BKL to <devfs_open> because drivers still need it - Added BKL to <devfs_open> because drivers still need it
===============================================================================
Changes for patch v213
- Protected <scan_dir_for_removable> and <get_removable_partition>
from changing directory contents
...@@ -626,6 +626,10 @@ ...@@ -626,6 +626,10 @@
20020510 Richard Gooch <rgooch@atnf.csiro.au> 20020510 Richard Gooch <rgooch@atnf.csiro.au>
Added BKL to <devfs_open> because drivers still need it. Added BKL to <devfs_open> because drivers still need it.
v1.15 v1.15
20020512 Richard Gooch <rgooch@atnf.csiro.au>
Protected <scan_dir_for_removable> and <get_removable_partition>
from changing directory contents.
v1.16
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -658,7 +662,7 @@ ...@@ -658,7 +662,7 @@
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#define DEVFS_VERSION "1.15 (20020510)" #define DEVFS_VERSION "1.16 (20020512)"
#define DEVFS_NAME "devfs" #define DEVFS_NAME "devfs"
...@@ -2415,6 +2419,9 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info, ...@@ -2415,6 +2419,9 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info,
* @de: The device. * @de: The device.
* *
* Returns 1 if the media was changed, else 0. * Returns 1 if the media was changed, else 0.
*
* This function may block, and may indirectly cause the parent directory
* contents to be changed due to partition re-reading.
*/ */
static int check_disc_changed (struct devfs_entry *de) static int check_disc_changed (struct devfs_entry *de)
...@@ -2449,6 +2456,10 @@ static int check_disc_changed (struct devfs_entry *de) ...@@ -2449,6 +2456,10 @@ static int check_disc_changed (struct devfs_entry *de)
/** /**
* scan_dir_for_removable - Scan a directory for removable media devices and check media. * scan_dir_for_removable - Scan a directory for removable media devices and check media.
* @dir: The directory. * @dir: The directory.
*
* This function may block, and may indirectly cause the directory
* contents to be changed due to partition re-reading. The directory will
* be locked for reading.
*/ */
static void scan_dir_for_removable (struct devfs_entry *dir) static void scan_dir_for_removable (struct devfs_entry *dir)
...@@ -2456,12 +2467,15 @@ static void scan_dir_for_removable (struct devfs_entry *dir) ...@@ -2456,12 +2467,15 @@ static void scan_dir_for_removable (struct devfs_entry *dir)
struct devfs_entry *de; struct devfs_entry *de;
if (dir->u.dir.num_removable < 1) return; if (dir->u.dir.num_removable < 1) return;
read_lock (&dir->u.dir.lock);
for (de = dir->u.dir.first; de != NULL; de = de->next) for (de = dir->u.dir.first; de != NULL; de = de->next)
{ {
if ( !S_ISBLK (de->mode) ) continue; if (S_ISBLK (de->mode) && de->u.fcb.removable) break;
if (!de->u.fcb.removable) continue;
check_disc_changed (de);
} }
devfs_get (de);
read_unlock (&dir->u.dir.lock);
if (de) check_disc_changed (de);
devfs_put (de);
} /* End Function scan_dir_for_removable */ } /* End Function scan_dir_for_removable */
/** /**
...@@ -2471,25 +2485,37 @@ static void scan_dir_for_removable (struct devfs_entry *dir) ...@@ -2471,25 +2485,37 @@ static void scan_dir_for_removable (struct devfs_entry *dir)
* @namelen: The number of characters in <<name>>. * @namelen: The number of characters in <<name>>.
* *
* Returns 1 if the media was changed, else 0. * Returns 1 if the media was changed, else 0.
*
* This function may block, and may indirectly cause the directory
* contents to be changed due to partition re-reading. The directory must
* be locked for reading upon entry, and will be unlocked upon exit.
*/ */
static int get_removable_partition (struct devfs_entry *dir, const char *name, static int get_removable_partition (struct devfs_entry *dir, const char *name,
unsigned int namelen) unsigned int namelen)
{ {
int retval;
struct devfs_entry *de; struct devfs_entry *de;
if (dir->u.dir.num_removable < 1)
{
read_unlock (&dir->u.dir.lock);
return 0;
}
for (de = dir->u.dir.first; de != NULL; de = de->next) for (de = dir->u.dir.first; de != NULL; de = de->next)
{ {
if ( !S_ISBLK (de->mode) ) continue; if (!S_ISBLK (de->mode) || !de->u.fcb.removable) continue;
if (!de->u.fcb.removable) continue; if (strcmp (de->name, "disc") == 0) break;
if (strcmp (de->name, "disc") == 0) return check_disc_changed (de);
/* Support for names where the partition is appended to the disc name /* Support for names where the partition is appended to the disc name
*/ */
if (de->namelen >= namelen) continue; if (de->namelen >= namelen) continue;
if (strncmp (de->name, name, de->namelen) != 0) continue; if (strncmp (de->name, name, de->namelen) == 0) break;
return check_disc_changed (de);
} }
return 0; devfs_get (de);
read_unlock (&dir->u.dir.lock);
retval = de ? check_disc_changed (de) : 0;
devfs_put (de);
return retval;
} /* End Function get_removable_partition */ } /* End Function get_removable_partition */
...@@ -2942,15 +2968,17 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) ...@@ -2942,15 +2968,17 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry)
if (parent == NULL) return ERR_PTR (-ENOENT); if (parent == NULL) return ERR_PTR (-ENOENT);
read_lock (&parent->u.dir.lock); read_lock (&parent->u.dir.lock);
de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len); de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len);
read_unlock (&parent->u.dir.lock); if (de) read_unlock (&parent->u.dir.lock);
if ( (de == NULL) && (parent->u.dir.num_removable > 0) && else
get_removable_partition (parent, dentry->d_name.name, { /* Try re-reading the partition (media may have changed) */
dentry->d_name.len) ) if ( get_removable_partition (parent, dentry->d_name.name,
{ dentry->d_name.len) ) /* Unlocks */
read_lock (&parent->u.dir.lock); { /* Media did change */
de = _devfs_search_dir (parent, dentry->d_name.name, read_lock (&parent->u.dir.lock);
dentry->d_name.len); de = _devfs_search_dir (parent, dentry->d_name.name,
read_unlock (&parent->u.dir.lock); dentry->d_name.len);
read_unlock (&parent->u.dir.lock);
}
} }
lookup_info.de = de; lookup_info.de = de;
init_waitqueue_head (&lookup_info.wait_queue); init_waitqueue_head (&lookup_info.wait_queue);
......
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