diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 23:59:27 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 23:59:27 -0800 |
| commit | 25aa595a676f130148eba073cdd5a8d57e9d238f (patch) | |
| tree | dc7925c1ea7bd0f65d483dd024e6cd7c4215dea7 /fs/devfs | |
| parent | 6533333c8946e70120cc9d7fcad01e0f748d7863 (diff) | |
v2.5.1.2 -> v2.5.1.3
- Christoph Hellwig: scsi_register_module cleanup
- Mikael Pettersson: apic.c LVTERR fixes
- Russell King: ARM update (including bio update for icside)
- Jens Axboe: more bio updates
- Al Viro: make ready to switch bread away from kdev_t..
- Davide Libenzi: scheduler cleanups
- Anders Gustafsson: LVM fixes for bio
- Richard Gooch: devfs update
Diffstat (limited to 'fs/devfs')
| -rw-r--r-- | fs/devfs/base.c | 660 |
1 files changed, 369 insertions, 291 deletions
diff --git a/fs/devfs/base.c b/fs/devfs/base.c index 2eeb1b7335c0..db6ec7adfd1a 100644 --- a/fs/devfs/base.c +++ b/fs/devfs/base.c @@ -427,7 +427,7 @@ Work sponsored by SGI. v0.92 20000306 Richard Gooch <rgooch@atnf.csiro.au> - Added DEVFS_FL_NO_PERSISTENCE flag. + Added DEVFS_ FL_NO_PERSISTENCE flag. Removed unnecessary call to <update_devfs_inode_from_entry> in <devfs_readdir>. Work sponsored by SGI. @@ -562,6 +562,45 @@ 20011122 Richard Gooch <rgooch@atnf.csiro.au> Use slab cache rather than fixed buffer for devfsd events. v1.1 + 20011125 Richard Gooch <rgooch@atnf.csiro.au> + Send DEVFSD_NOTIFY_REGISTERED events in <devfs_mk_dir>. + 20011127 Richard Gooch <rgooch@atnf.csiro.au> + Fixed locking bug in <devfs_d_revalidate_wait> due to typo. + Do not send CREATE, CHANGE, ASYNC_OPEN or DELETE events from + devfsd or children. + v1.2 + 20011202 Richard Gooch <rgooch@atnf.csiro.au> + Fixed bug in <devfsd_read>: was dereferencing freed pointer. + v1.3 + 20011203 Richard Gooch <rgooch@atnf.csiro.au> + Fixed bug in <devfsd_close>: was dereferencing freed pointer. + Added process group check for devfsd privileges. + v1.4 + 20011204 Richard Gooch <rgooch@atnf.csiro.au> + Use SLAB_ATOMIC in <devfsd_notify_de> from <devfs_d_delete>. + v1.5 + 20011211 Richard Gooch <rgooch@atnf.csiro.au> + Return old entry in <devfs_mk_dir> for 2.4.x kernels. + 20011212 Richard Gooch <rgooch@atnf.csiro.au> + Increment refcount on module in <check_disc_changed>. + 20011215 Richard Gooch <rgooch@atnf.csiro.au> + Created <devfs_get_handle> and exported <devfs_put>. + Increment refcount on module in <devfs_get_ops>. + Created <devfs_put_ops>. + v1.6 + 20011216 Richard Gooch <rgooch@atnf.csiro.au> + Added poisoning to <devfs_put>. + Improved debugging messages. + v1.7 + 20011221 Richard Gooch <rgooch@atnf.csiro.au> + Corrected (made useful) debugging message in <unregister>. + Moved <kmem_cache_create> in <mount_devfs_fs> to <init_devfs_fs> + 20011224 Richard Gooch <rgooch@atnf.csiro.au> + Added magic number to guard against scribbling drivers. + 20011226 Richard Gooch <rgooch@atnf.csiro.au> + Only return old entry in <devfs_mk_dir> if a directory. + Defined macros for error and debug messages. + v1.8 */ #include <linux/types.h> #include <linux/errno.h> @@ -594,13 +633,16 @@ #include <asm/bitops.h> #include <asm/atomic.h> -#define DEVFS_VERSION "1.1 (20011122)" +#define DEVFS_VERSION "1.8 (20011226)" #define DEVFS_NAME "devfs" #define FIRST_INODE 1 #define STRING_LENGTH 256 +#define FAKE_BLOCK_SIZE 1024 +#define POISON_PTR ( *(void **) poison_array ) +#define MAGIC_VALUE 0x327db823 #ifndef TRUE # define TRUE 1 @@ -637,9 +679,28 @@ #define OPTION_MOUNT 0x01 #define OPTION_ONLY 0x02 -#define OOPS(format, args...) {printk (format, ## args); \ - printk ("Forcing Oops\n"); \ - BUG();} +#define PRINTK(format, args...) \ + {printk (KERN_ERR "%s" format, __FUNCTION__ , ## args);} + +#define OOPS(format, args...) \ + {printk (KERN_CRIT "%s" format, __FUNCTION__ , ## args); \ + printk ("Forcing Oops\n"); \ + BUG();} + +#ifdef CONFIG_DEVFS_DEBUG +# define VERIFY_ENTRY(de) \ + {if ((de) && (de)->magic_number != MAGIC_VALUE) \ + OOPS ("(%p): bad magic value: %x\n", (de), (de)->magic_number);} +# define WRITE_ENTRY_MAGIC(de,magic) (de)->magic_number = (magic) +# define DPRINTK(flag, format, args...) \ + {if (devfs_debug & flag) \ + printk (KERN_INFO "%s" format, __FUNCTION__ , ## args);} +#else +# define VERIFY_ENTRY(de) +# define WRITE_ENTRY_MAGIC(de,magic) +# define DPRINTK(flag, format, args...) +#endif + struct directory_type { @@ -696,6 +757,9 @@ struct devfs_inode /* This structure is for "persistent" inode storage */ struct devfs_entry { +#ifdef CONFIG_DEVFS_DEBUG + unsigned int magic_number; +#endif void *info; atomic_t refcount; /* When this drops to zero, it's unused */ union @@ -740,6 +804,7 @@ struct fs_info /* This structure is for the mounted devfs */ struct devfsd_buf_entry *devfsd_last_event; volatile int devfsd_sleeping; volatile struct task_struct *devfsd_task; + volatile pid_t devfsd_pgrp; volatile struct file *devfsd_file; struct devfsd_notify_struct *devfsd_info; volatile unsigned long devfsd_event_mask; @@ -757,6 +822,8 @@ static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED; static unsigned int stat_num_entries; static unsigned int stat_num_bytes; #endif +static unsigned char poison_array[8] = + {0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a}; #ifdef CONFIG_DEVFS_MOUNT static unsigned int boot_options = OPTION_MOUNT; @@ -802,27 +869,26 @@ static struct file_operations devfsd_fops = static struct devfs_entry *devfs_get (struct devfs_entry *de) { + VERIFY_ENTRY (de); if (de) atomic_inc (&de->refcount); return de; } /* End Function devfs_get */ /** * devfs_put - Put (release) a reference to a devfs entry. - * @de: The devfs entry. + * @de: The handle to the devfs entry. */ -static void devfs_put (struct devfs_entry *de) +void devfs_put (devfs_handle_t de) { if (!de) return; + VERIFY_ENTRY (de); + if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de); if ( !atomic_dec_and_test (&de->refcount) ) return; - if (de == root_entry) - OOPS ("%s: devfs_put(): root entry being freed\n", DEVFS_NAME); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_FREE) - printk ("%s: devfs_put(%s): de: %p, parent: %p \"%s\"\n", - DEVFS_NAME, de->name, de, de->parent, - de->parent ? de->parent->name : "no parent"); -#endif + if (de == root_entry) OOPS ("(%p): root entry being freed\n", de); + DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", + de->name, de, de->parent, + de->parent ? de->parent->name : "no parent"); if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname); if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen ) { @@ -831,6 +897,7 @@ static void devfs_put (struct devfs_entry *de) MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor) ); } + WRITE_ENTRY_MAGIC (de, 0); #ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); --stat_num_entries; @@ -838,6 +905,7 @@ static void devfs_put (struct devfs_entry *de) if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1; spin_unlock (&stat_lock); #endif + de->info = POISON_PTR; kfree (de); } /* End Function devfs_put */ @@ -860,7 +928,7 @@ static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir, if ( !S_ISDIR (dir->mode) ) { - printk ("%s: search_dir(%s): not a directory\n", DEVFS_NAME,dir->name); + PRINTK ("(%s): not a directory\n", dir->name); return NULL; } for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) @@ -893,7 +961,7 @@ static struct devfs_entry *_devfs_alloc_entry (const char *name, if ( name && (namelen < 1) ) namelen = strlen (name); if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL ) return NULL; - memset (new, 0, sizeof *new + namelen); + memset (new, 0, sizeof *new + namelen); /* Will set '\0' on name */ new->mode = mode; if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock); atomic_set (&new->refcount, 1); @@ -902,6 +970,7 @@ static struct devfs_entry *_devfs_alloc_entry (const char *name, spin_unlock (&counter_lock); if (name) memcpy (new->name, name, namelen); new->namelen = namelen; + WRITE_ENTRY_MAGIC (new, MAGIC_VALUE); #ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); ++stat_num_entries; @@ -918,7 +987,7 @@ static struct devfs_entry *_devfs_alloc_entry (const char *name, * @de: The devfs entry to append. * @removable: If TRUE, increment the count of removable devices for %dir. * @old_de: If an existing entry exists, it will be written here. This may - * be %NULL. + * be %NULL. An implicit devfs_get() is performed on this entry. * * Append a devfs entry to a directory's list of children, checking first to * see if an entry of the same name exists. The directory will be locked. @@ -934,8 +1003,7 @@ static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de, if (old_de) *old_de = NULL; if ( !S_ISDIR (dir->mode) ) { - printk ("%s: append_entry(%s): dir: \"%s\" is not a directory\n", - DEVFS_NAME, de->name, dir->name); + PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name); devfs_put (de); return -ENOTDIR; } @@ -1105,15 +1173,13 @@ static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir, if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen, &leaf_pos) ) == NULL ) { - printk ("%s: prepare_leaf(%s): could not create parent path\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not create parent path\n", name); return NULL; } if ( ( de = _devfs_alloc_entry (name + leaf_pos, namelen - leaf_pos,mode) ) == NULL ) { - printk ("%s: prepare_leaf(%s): could not allocate entry\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not allocate entry\n", name); devfs_put (*dir); return NULL; } @@ -1160,19 +1226,20 @@ static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir, /** - * find_by_dev - Find a devfs entry in a directory. + * _devfs_find_by_dev - Find a devfs entry in a directory. * @dir: The directory where to search * @major: The major number to search for. * @minor: The minor number to search for. * @type: The type of special file to search for. This may be either * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. * - * Returns the devfs_entry pointer on success, else %NULL. + * Returns the devfs_entry pointer on success, else %NULL. An implicit + * devfs_get() is performed. */ -static struct devfs_entry *find_by_dev (struct devfs_entry *dir, - unsigned int major, unsigned int minor, - char type) +static struct devfs_entry *_devfs_find_by_dev (struct devfs_entry *dir, + unsigned int major, + unsigned int minor, char type) { struct devfs_entry *entry, *de; @@ -1180,7 +1247,7 @@ static struct devfs_entry *find_by_dev (struct devfs_entry *dir, if (dir == NULL) return NULL; if ( !S_ISDIR (dir->mode) ) { - printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME); + PRINTK ("(%p): not a directory\n", dir); devfs_put (dir); return NULL; } @@ -1205,7 +1272,7 @@ static struct devfs_entry *find_by_dev (struct devfs_entry *dir, for (entry = dir->u.dir.first; entry != NULL; entry = entry->next) { if ( !S_ISDIR (entry->mode) ) continue; - de = find_by_dev (entry, major, minor, type); + de = _devfs_find_by_dev (entry, major, minor, type); if (de) { read_unlock (&dir->u.dir.lock); @@ -1216,51 +1283,51 @@ static struct devfs_entry *find_by_dev (struct devfs_entry *dir, read_unlock (&dir->u.dir.lock); devfs_put (dir); return NULL; -} /* End Function find_by_dev */ +} /* End Function _devfs_find_by_dev */ /** - * find_entry - Find a devfs entry. + * _devfs_find_entry - Find a devfs entry. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * name is relative to the root of the devfs. - * @name: The name of the entry. This is ignored if @handle is not %NULL. - * @namelen: The number of characters in @name, not including a %NULL - * terminator. If this is 0, then @name must be %NULL-terminated and the - * length is computed internally. - * @major: The major number. This is used if @handle and @name are %NULL. - * @minor: The minor number. This is used if @handle and @name are %NULL. + * @name: The name of the entry. This may be %NULL. + * @major: The major number. This is used if lookup by @name fails. + * @minor: The minor number. This is used if lookup by @name fails. * NOTE: If @major and @minor are both 0, searching by major and minor * numbers is disabled. * @type: The type of special file to search for. This may be either * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. * @traverse_symlink: If %TRUE then symbolic links are traversed. * - * Returns the devfs_entry pointer on success, else %NULL. + * Returns the devfs_entry pointer on success, else %NULL. An implicit + * devfs_get() is performed. */ -static struct devfs_entry *find_entry (devfs_handle_t dir, - const char *name, unsigned int namelen, - unsigned int major, unsigned int minor, - char type, int traverse_symlink) +static struct devfs_entry *_devfs_find_entry (devfs_handle_t dir, + const char *name, + unsigned int major, + unsigned int minor, + char type, int traverse_symlink) { struct devfs_entry *entry; if (name != NULL) { - if (namelen < 1) namelen = strlen (name); + unsigned int namelen = strlen (name); + if (name[0] == '/') { /* Skip leading pathname component */ if (namelen < 2) { - printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name); + PRINTK ("(%s): too short\n", name); return NULL; } for (++name, --namelen; (*name != '/') && (namelen > 0); ++name, --namelen); if (namelen < 2) { - printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, name); + PRINTK ("(%s): too short\n", name); return NULL; } ++name; @@ -1271,12 +1338,13 @@ static struct devfs_entry *find_entry (devfs_handle_t dir, } /* Have to search by major and minor: slow */ if ( (major == 0) && (minor == 0) ) return NULL; - return find_by_dev (root_entry, major, minor, type); -} /* End Function find_entry */ + return _devfs_find_by_dev (root_entry, major, minor, type); +} /* End Function _devfs_find_entry */ static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode) { if (inode == NULL) return NULL; + VERIFY_ENTRY ( (struct devfs_entry *) inode->u.generic_ip ); return inode->u.generic_ip; } /* End Function get_devfs_entry_from_vfs_inode */ @@ -1315,10 +1383,14 @@ static int is_devfsd_or_child (struct fs_info *fs_info) { struct task_struct *p; - for (p = current; p != &init_task; p = p->p_opptr) + if (current == fs_info->devfsd_task) return (TRUE); + if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1) + for (p = current->p_opptr; p != &init_task; p = p->p_opptr) { if (p == fs_info->devfsd_task) return (TRUE); } +#endif return (FALSE); } /* End Function is_devfsd_or_child */ @@ -1375,13 +1447,16 @@ static int wait_for_devfsd_finished (struct fs_info *fs_info) static int devfsd_notify_de (struct devfs_entry *de, unsigned short type, umode_t mode, - uid_t uid, gid_t gid, struct fs_info *fs_info) + uid_t uid, gid_t gid, struct fs_info *fs_info, + int atomic) { struct devfsd_buf_entry *entry; struct devfs_entry *curr; if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE); - if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, 0) ) == NULL ) + if ( ( entry = kmem_cache_alloc (devfsd_buf_cache, + atomic ? SLAB_ATOMIC : SLAB_KERNEL) ) + == NULL ) { atomic_inc (&fs_info->devfsd_overrun_count); return (FALSE); @@ -1414,7 +1489,7 @@ static int devfsd_notify_de (struct devfs_entry *de, static void devfsd_notify (struct devfs_entry *de,unsigned short type,int wait) { if (devfsd_notify_de (de, type, de->mode, current->euid, - current->egid, &fs_info) && wait) + current->egid, &fs_info, 0) && wait) wait_for_devfsd_finished (&fs_info); } /* End Function devfsd_notify */ @@ -1451,7 +1526,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, if (name == NULL) { - printk ("%s: devfs_register(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return NULL; } if (ops == NULL) @@ -1459,23 +1534,19 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); if (ops == NULL) { - printk ("%s: devfs_register(%s): NULL ops pointer\n", - DEVFS_NAME, name); + PRINTK ("(%s): NULL ops pointer\n", name); return NULL; } - printk ("%s: devfs_register(%s): NULL ops, got %p from major table\n", - DEVFS_NAME, name, ops); + PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops); } if ( S_ISDIR (mode) ) { - printk("%s: devfs_register(%s): creating directories is not allowed\n", - DEVFS_NAME, name); + PRINTK ("(%s): creating directories is not allowed\n", name); return NULL; } if ( S_ISLNK (mode) ) { - printk ("%s: devfs_register(%s): creating symlinks is not allowed\n", - DEVFS_NAME, name); + PRINTK ("(%s): creating symlinks is not allowed\n", name); return NULL; } if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) && @@ -1483,8 +1554,8 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, { if ( ( devnum = devfs_alloc_devnum (devtype) ) == NODEV ) { - printk ("%s: devfs_register(%s): exhausted %s device numbers\n", - DEVFS_NAME, name, S_ISCHR (mode) ? "char" : "block"); + PRINTK ("(%s): exhausted %s device numbers\n", + name, S_ISCHR (mode) ? "char" : "block"); return NULL; } major = MAJOR (devnum); @@ -1492,8 +1563,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, } if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL ) { - printk ("%s: devfs_register(%s): could not prepare leaf\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not prepare leaf\n", name); if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); return NULL; } @@ -1505,8 +1575,7 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, } else if ( !S_ISREG (mode) ) { - printk ("%s: devfs_register(%s): illegal mode: %x\n", - DEVFS_NAME, name, mode); + PRINTK ("(%s): illegal mode: %x\n", name, mode); devfs_put (de); devfs_put (dir); return (NULL); @@ -1530,17 +1599,13 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) ) != 0 ) { - printk("%s: devfs_register(%s): could not append to parent, err: %d\n", - DEVFS_NAME, name, err); + PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); if (devnum != NODEV) devfs_dealloc_devnum (devtype, devnum); return NULL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_register(%s): de: %p dir: %p \"%s\" pp: %p\n", - DEVFS_NAME, name, de, dir, dir->name, dir->parent); -#endif + DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\" pp: %p\n", + name, de, dir, dir->name, dir->parent); devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT); devfs_put (dir); return de; @@ -1576,7 +1641,7 @@ static int _devfs_unhook (struct devfs_entry *de) /** - * unregister - Unregister a device entry from it's parent. + * _devfs_unregister - Unregister a device entry from it's parent. * @dir: The parent directory. * @de: The entry to unregister. * @@ -1584,7 +1649,7 @@ static int _devfs_unhook (struct devfs_entry *de) * unlocked by this function. */ -static void unregister (struct devfs_entry *dir, struct devfs_entry *de) +static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de) { int unhooked = _devfs_unhook (de); @@ -1603,34 +1668,30 @@ static void unregister (struct devfs_entry *dir, struct devfs_entry *de) write_lock (&de->u.dir.lock); de->u.dir.no_more_additions = TRUE; child = de->u.dir.first; - unregister (de, child); + VERIFY_ENTRY (child); + _devfs_unregister (de, child); if (!child) break; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_UNREGISTER) - printk ("%s: unregister(): child->name: \"%s\" child: %p\n", - DEVFS_NAME, child->name, child); -#endif + DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", + child->name, child, atomic_read (&child->refcount) ); devfs_put (child); } -} /* End Function unregister */ +} /* End Function _devfs_unregister */ /** * devfs_unregister - Unregister a device entry. * @de: A handle previously created by devfs_register() or returned from - * devfs_find_handle(). If this is %NULL the routine does nothing. + * devfs_get_handle(). If this is %NULL the routine does nothing. */ void devfs_unregister (devfs_handle_t de) { + VERIFY_ENTRY (de); if ( (de == NULL) || (de->parent == NULL) ) return; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_UNREGISTER) - printk ("%s: devfs_unregister(): de->name: \"%s\" de: %p\n", - DEVFS_NAME, de->name, de); -#endif + DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p refcount: %d\n", + de->name, de, atomic_read (&de->refcount) ); write_lock (&de->parent->u.dir.lock); - unregister (de->parent, de); + _devfs_unregister (de->parent, de); devfs_put (de); } /* End Function devfs_unregister */ @@ -1646,16 +1707,12 @@ static int devfs_do_symlink (devfs_handle_t dir, const char *name, if (handle != NULL) *handle = NULL; if (name == NULL) { - printk ("%s: devfs_do_symlink(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return -EINVAL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_do_symlink(%s)\n", DEVFS_NAME, name); -#endif if (link == NULL) { - printk ("%s: devfs_do_symlink(): NULL link pointer\n", DEVFS_NAME); + PRINTK ("(%s): NULL link pointer\n", name); return -EINVAL; } linklength = strlen (link); @@ -1666,8 +1723,7 @@ static int devfs_do_symlink (devfs_handle_t dir, const char *name, if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) ) == NULL ) { - printk ("%s: devfs_do_symlink(%s): could not prepare leaf\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not prepare leaf\n", name); kfree (newlink); return -ENOTDIR; } @@ -1677,8 +1733,7 @@ static int devfs_do_symlink (devfs_handle_t dir, const char *name, de->u.symlink.length = linklength; if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) { - printk ("%s: devfs_do_symlink(%s): could not append to parent, err: %d\n", - DEVFS_NAME, name, err); + PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); return err; } @@ -1713,6 +1768,7 @@ int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags, devfs_handle_t de; if (handle != NULL) *handle = NULL; + DPRINTK (DEBUG_REGISTER, "(%s)\n", name); err = devfs_do_symlink (dir, name, flags, link, &de, info); if (err) return err; if (handle != NULL) *handle = de; @@ -1738,39 +1794,47 @@ int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags, devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info) { int err; - struct devfs_entry *de; + struct devfs_entry *de, *old; if (name == NULL) { - printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME); + PRINTK ("(): NULL name pointer\n"); return NULL; } if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL ) { - printk ("%s: devfs_mk_dir(%s): could not prepare leaf\n", - DEVFS_NAME, name); + PRINTK ("(%s): could not prepare leaf\n", name); return NULL; } de->info = info; - if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) + if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 ) { - printk ("%s: devfs_mk_dir(%s): could not append to dir: %p \"%s\", err: %d\n", - DEVFS_NAME, name, dir, dir->name, err); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1) + if ( old && S_ISDIR (old->mode) ) + { + PRINTK ("(%s): using old entry in dir: %p \"%s\"\n", + name, dir, dir->name); + old->vfs_created = FALSE; + devfs_put (dir); + return old; + } +#endif + PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n", + name, dir, dir->name, err); + devfs_put (old); devfs_put (dir); return NULL; } -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_REGISTER) - printk ("%s: devfs_mk_dir(%s): de: %p dir: %p \"%s\"\n", - DEVFS_NAME, name, de, dir, dir->name); -#endif + DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n", + name, de, dir, dir->name); + devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0); devfs_put (dir); return de; } /* End Function devfs_mk_dir */ /** - * devfs_find_handle - Find the handle of a devfs entry. + * devfs_get_handle - Find the handle of a devfs entry. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * name is relative to the root of the devfs. * @name: The name of the entry. @@ -1782,20 +1846,31 @@ devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info) * traversed. Symlinks pointing out of the devfs namespace will cause a * failure. Symlink traversal consumes stack space. * - * Returns a handle which may later be used in a call to devfs_unregister(), - * devfs_get_flags(), or devfs_set_flags(). On failure %NULL is returned. + * Returns a handle which may later be used in a call to + * devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A + * subsequent devfs_put() is required to decrement the refcount. + * On failure %NULL is returned. */ +devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name, + unsigned int major, unsigned int minor, + char type, int traverse_symlinks) +{ + if ( (name != NULL) && (name[0] == '\0') ) name = NULL; + return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks); +} /* End Function devfs_get_handle */ + + +/* Compatibility function. Will be removed in sometime in 2.5 */ + devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name, unsigned int major, unsigned int minor, char type, int traverse_symlinks) { devfs_handle_t de; - if ( (name != NULL) && (name[0] == '\0') ) name = NULL; - de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks); - devfs_put (de); /* FIXME: in 2.5 consider dropping this and require a - call to devfs_put() */ + de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks); + devfs_put (de); return de; } /* End Function devfs_find_handle */ @@ -1813,6 +1888,7 @@ int devfs_get_flags (devfs_handle_t de, unsigned int *flags) unsigned int fl = 0; if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if (de->hide) fl |= DEVFS_FL_HIDE; if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) { @@ -1836,11 +1912,8 @@ int devfs_get_flags (devfs_handle_t de, unsigned int *flags) int devfs_set_flags (devfs_handle_t de, unsigned int flags) { if (de == NULL) return -EINVAL; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_SET_FLAGS) - printk ("%s: devfs_set_flags(): de->name: \"%s\"\n", - DEVFS_NAME, de->name); -#endif + VERIFY_ENTRY (de); + DPRINTK (DEBUG_SET_FLAGS, "(%s): flags: %x\n", de->name, flags); de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE; if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) { @@ -1864,6 +1937,7 @@ int devfs_get_maj_min (devfs_handle_t de, unsigned int *major, unsigned int *minor) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if ( S_ISDIR (de->mode) ) return -EISDIR; if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) ) return -EINVAL; if (major != NULL) *major = de->u.fcb.u.device.major; @@ -1904,6 +1978,7 @@ int devfs_generate_path (devfs_handle_t de, char *path, int buflen) #define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if (de->namelen >= buflen) return -ENAMETOOLONG; /* Must be first */ path[buflen - 1] = '\0'; if (de->parent == NULL) return buflen - 1; /* Don't prepend root */ @@ -1925,18 +2000,57 @@ int devfs_generate_path (devfs_handle_t de, char *path, int buflen) * @de: The handle to the device entry. * * Returns a pointer to the device operations on success, else NULL. + * The use count for the module owning the operations will be incremented. */ void *devfs_get_ops (devfs_handle_t de) { + struct module *owner; + if (de == NULL) return NULL; - if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) - return de->u.fcb.ops; - return NULL; + VERIFY_ENTRY (de); + if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) + return NULL; + if (de->u.fcb.ops == NULL) return NULL; + read_lock (&de->parent->u.dir.lock); /* Prevent module from unloading */ + if (de->next == de) owner = NULL; /* Ops pointer is already stale */ + else if ( S_ISCHR (de->mode) || S_ISREG (de->mode) ) + owner = ( (struct file_operations *) de->u.fcb.ops )->owner; + else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner; + if ( (de->next == de) || !try_inc_mod_count (owner) ) + { /* Entry is already unhooked or module is unloading */ + read_unlock (&de->parent->u.dir.lock); + return NULL; + } + read_unlock (&de->parent->u.dir.lock); /* Module can continue unloading*/ + return de->u.fcb.ops; } /* End Function devfs_get_ops */ /** + * devfs_put_ops - Put the device operations for a devfs entry. + * @de: The handle to the device entry. + * + * The use count for the module owning the operations will be decremented. + */ + +void devfs_put_ops (devfs_handle_t de) +{ + struct module *owner; + + if (de == NULL) return; + VERIFY_ENTRY (de); + if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) + return; + if (de->u.fcb.ops == NULL) return; + if ( S_ISCHR (de->mode) || S_ISREG (de->mode) ) + owner = ( (struct file_operations *) de->u.fcb.ops )->owner; + else owner = ( (struct block_device_operations *) de->u.fcb.ops )->owner; + if (owner) __MOD_DEC_USE_COUNT (owner); +} /* End Function devfs_put_ops */ + + +/** * devfs_set_file_size - Set the file size for a devfs regular file. * @de: The handle to the device entry. * @size: The new file size. @@ -1947,6 +2061,7 @@ void *devfs_get_ops (devfs_handle_t de) int devfs_set_file_size (devfs_handle_t de, unsigned long size) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); if ( !S_ISREG (de->mode) ) return -EINVAL; if (de->u.fcb.u.file.size == size) return 0; de->u.fcb.u.file.size = size; @@ -1966,6 +2081,7 @@ int devfs_set_file_size (devfs_handle_t de, unsigned long size) void *devfs_get_info (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->info; } /* End Function devfs_get_info */ @@ -1980,6 +2096,7 @@ void *devfs_get_info (devfs_handle_t de) int devfs_set_info (devfs_handle_t de, void *info) { if (de == NULL) return -EINVAL; + VERIFY_ENTRY (de); de->info = info; return 0; } /* End Function devfs_set_info */ @@ -1994,6 +2111,7 @@ int devfs_set_info (devfs_handle_t de, void *info) devfs_handle_t devfs_get_parent (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->parent; } /* End Function devfs_get_parent */ @@ -2008,6 +2126,7 @@ devfs_handle_t devfs_get_parent (devfs_handle_t de) devfs_handle_t devfs_get_first_child (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); if ( !S_ISDIR (de->mode) ) return NULL; return de->u.dir.first; } /* End Function devfs_get_first_child */ @@ -2023,6 +2142,7 @@ devfs_handle_t devfs_get_first_child (devfs_handle_t de) devfs_handle_t devfs_get_next_sibling (devfs_handle_t de) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); return de->next; } /* End Function devfs_get_next_sibling */ @@ -2038,14 +2158,15 @@ devfs_handle_t devfs_get_next_sibling (devfs_handle_t de) void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave) { if (master == NULL) return; + VERIFY_ENTRY (master); + VERIFY_ENTRY (slave); if (master->slave != NULL) { /* Because of the dumbness of the layers above, ignore duplicates */ if (master->slave == slave) return; - printk ("%s: devfs_auto_unregister(): only one slave allowed\n", - DEVFS_NAME); - OOPS (" master: \"%s\" old slave: \"%s\" new slave: \"%s\"\n", - master->name, master->slave->name, slave->name); + PRINTK ("(%s): only one slave allowed\n", master->name); + OOPS ("(): old slave: \"%s\" new slave: \"%s\"\n", + master->slave->name, slave->name); } master->slave = slave; } /* End Function devfs_auto_unregister */ @@ -2061,6 +2182,7 @@ void devfs_auto_unregister (devfs_handle_t master, devfs_handle_t slave) devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master) { if (master == NULL) return NULL; + VERIFY_ENTRY (master); return master->slave; } /* End Function devfs_get_unregister_slave */ @@ -2076,6 +2198,7 @@ devfs_handle_t devfs_get_unregister_slave (devfs_handle_t master) const char *devfs_get_name (devfs_handle_t de, unsigned int *namelen) { if (de == NULL) return NULL; + VERIFY_ENTRY (de); if (namelen != NULL) *namelen = de->namelen; return de->name; } /* End Function devfs_get_name */ @@ -2218,10 +2341,12 @@ static int __init devfs_setup (char *str) __setup("devfs=", devfs_setup); +EXPORT_SYMBOL(devfs_put); EXPORT_SYMBOL(devfs_register); EXPORT_SYMBOL(devfs_unregister); EXPORT_SYMBOL(devfs_mk_symlink); EXPORT_SYMBOL(devfs_mk_dir); +EXPORT_SYMBOL(devfs_get_handle); EXPORT_SYMBOL(devfs_find_handle); EXPORT_SYMBOL(devfs_get_flags); EXPORT_SYMBOL(devfs_set_flags); @@ -2268,8 +2393,9 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info, buf->parent = parent; buf->namelen = namelen; buf->u.name = name; + WRITE_ENTRY_MAGIC (buf, MAGIC_VALUE); if ( !devfsd_notify_de (buf, DEVFSD_NOTIFY_LOOKUP, 0, - current->euid, current->egid, fs_info) ) + current->euid, current->egid, fs_info, 0) ) return -ENOENT; /* Possible success */ return 0; @@ -2286,14 +2412,17 @@ static int try_modload (struct devfs_entry *parent, struct fs_info *fs_info, static int check_disc_changed (struct devfs_entry *de) { int tmp; + int retval = 0; kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor); - struct block_device_operations *bdops = de->u.fcb.ops; + struct block_device_operations *bdops; extern int warn_no_part; if ( !S_ISBLK (de->mode) ) return 0; - if (bdops == NULL) return 0; - if (bdops->check_media_change == NULL) return 0; - if ( !bdops->check_media_change (dev) ) return 0; + bdops = devfs_get_ops (de); + if (!bdops) return 0; + if (bdops->check_media_change == NULL) goto out; + if ( !bdops->check_media_change (dev) ) goto out; + retval = 1; printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n", kdevname (dev) ); if (invalidate_device(dev, 0)) @@ -2303,7 +2432,9 @@ static int check_disc_changed (struct devfs_entry *de) warn_no_part = 0; if (bdops->revalidate) bdops->revalidate (dev); warn_no_part = tmp; - return 1; +out: + devfs_put_ops (de); + return retval; } /* End Function check_disc_changed */ @@ -2375,16 +2506,10 @@ static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr) if (retval != 0) return retval; retval = inode_setattr (inode, iattr); if (retval != 0) return retval; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_CHANGE) - { - 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 + DPRINTK (DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", + (int) inode->i_ino, inode, de); + DPRINTK (DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", + (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid); /* Inode is not on hash chains, thus must save permissions here rather than in a write_inode() method */ if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) && @@ -2397,16 +2522,17 @@ static int devfs_notify_change (struct dentry *dentry, struct iattr *iattr) de->inode.atime = inode->i_atime; de->inode.mtime = inode->i_mtime; de->inode.ctime = inode->i_ctime; - if ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) + if ( ( iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID) ) && + !is_devfsd_or_child (fs_info) ) devfsd_notify_de (de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_notify_change */ static int devfs_statfs (struct super_block *sb, struct statfs *buf) { buf->f_type = DEVFS_SUPER_MAGIC; - buf->f_bsize = PAGE_SIZE / sizeof (long); + buf->f_bsize = FAKE_BLOCK_SIZE; buf->f_bfree = 0; buf->f_bavail = 0; buf->f_ffree = 0; @@ -2428,7 +2554,7 @@ static struct super_operations devfs_sops = /** - * get_vfs_inode - Get a VFS inode. + * _devfs_get_vfs_inode - Get a VFS inode. * @sb: The super block. * @de: The devfs inode. * @dentry: The dentry to register with the devfs inode. @@ -2437,9 +2563,9 @@ static struct super_operations devfs_sops = * performed if the inode is created. */ -static struct inode *get_vfs_inode (struct super_block *sb, - struct devfs_entry *de, - struct dentry *dentry) +static struct inode *_devfs_get_vfs_inode (struct super_block *sb, + struct devfs_entry *de, + struct dentry *dentry) { int is_fcb = FALSE; struct inode *inode; @@ -2447,8 +2573,7 @@ static struct inode *get_vfs_inode (struct super_block *sb, if (de->prev == de) return NULL; /* Quick check to see if unhooked */ if ( ( inode = new_inode (sb) ) == NULL ) { - printk ("%s: get_vfs_inode(%s): new_inode() failed, de: %p\n", - DEVFS_NAME, de->name, de); + PRINTK ("(%s): new_inode() failed, de: %p\n", de->name, de); return NULL; } if (de->parent) @@ -2465,13 +2590,10 @@ static struct inode *get_vfs_inode (struct super_block *sb, } inode->u.generic_ip = devfs_get (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 + DPRINTK (DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", + (int) inode->i_ino, inode, de); inode->i_blocks = 0; - inode->i_blksize = 1024; + inode->i_blksize = FAKE_BLOCK_SIZE; inode->i_op = &devfs_iops; inode->i_fop = &devfs_fops; inode->i_rdev = NODEV; @@ -2491,8 +2613,7 @@ static struct inode *get_vfs_inode (struct super_block *sb, 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 PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino); is_fcb = TRUE; } else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops; @@ -2519,14 +2640,10 @@ static struct inode *get_vfs_inode (struct super_block *sb, 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 + DPRINTK (DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", + (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid); return inode; -} /* End Function get_vfs_inode */ +} /* End Function _devfs_get_vfs_inode */ /* File operations for device entries follow */ @@ -2542,11 +2659,8 @@ static int devfs_readdir (struct file *file, void *dirent, filldir_t filldir) fs_info = inode->i_sb->u.generic_sbp; parent = get_devfs_entry_from_vfs_inode (file->f_dentry->d_inode); if ( (long) file->f_pos < 0 ) return -EINVAL; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_F_READDIR) - printk ("%s: readdir(): fs_info: %p pos: %ld\n", DEVFS_NAME, - fs_info, (long) file->f_pos); -#endif + DPRINTK (DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", + parent->name, fs_info, (long) file->f_pos); switch ( (long) file->f_pos ) { case 0: @@ -2637,9 +2751,9 @@ static int devfs_open (struct inode *inode, struct file *file) inode->i_uid = current->euid; inode->i_gid = current->egid; } - if (df->aopen_notify) + if ( df->aopen_notify && !is_devfsd_or_child (fs_info) ) devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode, - current->euid, current->egid, fs_info); + current->euid, current->egid, fs_info, 0); return 0; } /* End Function devfs_open */ @@ -2666,13 +2780,7 @@ static struct file_operations devfs_dir_fops = static void devfs_d_release (struct dentry *dentry) { -#ifdef CONFIG_DEVFS_DEBUG - struct inode *inode = dentry->d_inode; - - if (devfs_debug & DEBUG_D_RELEASE) - printk ("%s: d_release(): dentry: %p inode: %p\n", - DEVFS_NAME, dentry, inode); -#endif + DPRINTK (DEBUG_D_RELEASE, "(%p): inode: %p\n", dentry, dentry->d_inode); } /* End Function devfs_d_release */ /** @@ -2686,14 +2794,11 @@ static void devfs_d_iput (struct dentry *dentry, struct inode *inode) struct devfs_entry *de; de = get_devfs_entry_from_vfs_inode (inode); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_IPUT) - printk ("%s: d_iput(): dentry: %p inode: %p de: %p de->dentry: %p\n", - DEVFS_NAME, dentry, inode, de, de->inode.dentry); -#endif + DPRINTK (DEBUG_D_IPUT,"(%s): dentry: %p inode: %p de: %p de->dentry: %p\n", + de->name, dentry, inode, de, de->inode.dentry); if ( de->inode.dentry && (de->inode.dentry != dentry) ) - OOPS ("%s: d_iput(%s): de: %p dentry: %p de->dentry: %p\n", - DEVFS_NAME, de->name, de, dentry, de->inode.dentry); + OOPS ("(%s): de: %p dentry: %p de->dentry: %p\n", + de->name, de, dentry, de->inode.dentry); de->inode.dentry = NULL; iput (inode); devfs_put (de); @@ -2733,20 +2838,13 @@ static int devfs_d_delete (struct dentry *dentry) /* Unhash dentry if negative (has no inode) */ if (inode == NULL) { -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_DELETE) - printk ("%s: d_delete(): dropping negative dentry: %p\n", - DEVFS_NAME, dentry); -#endif + DPRINTK (DEBUG_D_DELETE, "(%p): dropping negative dentry\n", dentry); return 1; } fs_info = inode->i_sb->u.generic_sbp; de = get_devfs_entry_from_vfs_inode (inode); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_D_DELETE) - printk ("%s: d_delete(): dentry: %p inode: %p devfs_entry: %p\n", - DEVFS_NAME, dentry, inode, de); -#endif + DPRINTK (DEBUG_D_DELETE, "(%p): inode: %p devfs_entry: %p\n", + dentry, inode, de); if (de == NULL) return 0; if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) return 0; @@ -2754,7 +2852,7 @@ static int devfs_d_delete (struct dentry *dentry) de->u.fcb.open = FALSE; if (de->u.fcb.aopen_notify) devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode, - current->euid, current->egid, fs_info); + current->euid, current->egid, fs_info, 1); if (!de->u.fcb.auto_owner) return 0; /* Change the ownership/protection back */ inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO; @@ -2774,25 +2872,19 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) devfs_handle_t parent = get_devfs_entry_from_vfs_inode (dir); struct inode *inode; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: d_revalidate(%s): dentry: %p by: \"%s\"\n", - DEVFS_NAME, dentry->d_name.name, dentry, current->comm); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p by: \"%s\"\n", + dentry->d_name.name, dentry, current->comm); read_lock (&parent->u.dir.lock); de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len); - read_lock (&parent->u.dir.lock); + read_unlock (&parent->u.dir.lock); if (de == NULL) return 1; /* Create an inode, now that the driver information is available */ - inode = get_vfs_inode (dir->i_sb, de, dentry); + inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry); devfs_put (de); if (!inode) return 1; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: d_revalidate(): new VFS inode(%u): %p devfs_entry: %p\n", - DEVFS_NAME, de->inode.ino, inode, de); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n", + de->name, de->inode.ino, inode, de); d_instantiate (dentry, inode); return 1; } @@ -2805,21 +2897,17 @@ static int devfs_d_revalidate_wait (struct dentry *dentry, int flags) static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) { - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; /* Set up the dentry operations before anything else, to ensure cleaning up on any error */ dentry->d_op = &devfs_dops; - 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); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: lookup(%s): dentry: %p parent: %p by: \"%s\"\n", - DEVFS_NAME, dentry->d_name.name, dentry, parent,current->comm); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): dentry: %p parent: %p by: \"%s\"\n", + dentry->d_name.name, dentry, parent, current->comm); if (parent == NULL) return ERR_PTR (-ENOENT); read_lock (&parent->u.dir.lock); de = _devfs_search_dir (parent, dentry->d_name.name, dentry->d_name.len); @@ -2872,14 +2960,11 @@ static struct dentry *devfs_lookup (struct inode *dir, struct dentry *dentry) d_add (dentry, NULL); /* Open the floodgates */ } /* Create an inode, now that the driver information is available */ - inode = get_vfs_inode (dir->i_sb, de, dentry); + inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry); devfs_put (de); if (!inode) return ERR_PTR (-ENOMEM); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_LOOKUP) - printk ("%s: lookup(): new VFS inode(%u): %p devfs_entry: %p\n", - DEVFS_NAME, de->inode.ino, inode, de); -#endif + DPRINTK (DEBUG_I_LOOKUP, "(%s): new VFS inode(%u): %p de: %p\n", + de->name, de->inode.ino, inode, de); d_instantiate (dentry, inode); if (dentry->d_op == &devfs_wait_dops) { /* Unlock directory semaphore, which will release any waiters. They @@ -2897,20 +2982,19 @@ static int devfs_unlink (struct inode *dir, struct dentry *dentry) int unhooked; struct devfs_entry *de; struct inode *inode = dentry->d_inode; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_UNLINK) - printk ("%s: unlink(%s)\n", DEVFS_NAME, dentry->d_name.name); -#endif de = get_devfs_entry_from_vfs_inode (inode); + DPRINTK (DEBUG_I_UNLINK, "(%s): de: %p\n", dentry->d_name.name, de); if (de == NULL) return -ENOENT; if (!de->vfs_created) return -EPERM; write_lock (&de->parent->u.dir.lock); unhooked = _devfs_unhook (de); write_unlock (&de->parent->u.dir.lock); if (!unhooked) return -ENOENT; - devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, dir->i_sb->u.generic_sbp); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); free_dentry (de); devfs_put (de); return 0; @@ -2920,21 +3004,17 @@ static int devfs_symlink (struct inode *dir, struct dentry *dentry, const char *symname) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; - 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); if (parent == NULL) return -ENOENT; err = devfs_do_symlink (parent, dentry->d_name.name, DEVFS_FL_NONE, symname, &de, NULL); -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: symlink(): errcode from <devfs_do_symlink>: %d\n", - DEVFS_NAME, err); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): errcode from <devfs_do_symlink>: %d\n", + dentry->d_name.name, err); if (err < 0) return err; de->vfs_created = TRUE; de->inode.uid = current->euid; @@ -2942,28 +3022,25 @@ static int devfs_symlink (struct inode *dir, struct dentry *dentry, de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: symlink(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", + dentry->d_name.name, de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_symlink */ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; mode = (mode & ~S_IFMT) | S_IFDIR; /* VFS doesn't pass S_IFMT part */ - fs_info = dir->i_sb->u.generic_sbp; parent = get_devfs_entry_from_vfs_inode (dir); if (parent == NULL) return -ENOENT; de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode); @@ -2976,16 +3053,14 @@ static int devfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_DISABLED) - printk ("%s: mkdir(): new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_DISABLED, "(%s): new VFS inode(%u): %p dentry: %p\n", + dentry->d_name.name, de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_mkdir */ @@ -2993,11 +3068,10 @@ static int devfs_rmdir (struct inode *dir, struct dentry *dentry) { int err = 0; struct devfs_entry *de; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct inode *inode = dentry->d_inode; if (dir->i_sb->u.generic_sbp != inode->i_sb->u.generic_sbp) return -EINVAL; - fs_info = dir->i_sb->u.generic_sbp; de = get_devfs_entry_from_vfs_inode (inode); if (de == NULL) return -ENOENT; if ( !S_ISDIR (de->mode) ) return -ENOTDIR; @@ -3013,8 +3087,9 @@ static int devfs_rmdir (struct inode *dir, struct dentry *dentry) if ( !_devfs_unhook (de) ) err = -ENOENT; write_unlock (&de->parent->u.dir.lock); if (err) return err; - devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_DELETE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); free_dentry (de); devfs_put (de); return 0; @@ -3024,16 +3099,12 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, int rdev) { int err; - struct fs_info *fs_info; + struct fs_info *fs_info = dir->i_sb->u.generic_sbp; struct devfs_entry *parent, *de; struct inode *inode; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_MKNOD) - printk ("%s: mknod(%s): mode: 0%o dev: %d\n", - DEVFS_NAME, dentry->d_name.name, mode, rdev); -#endif - fs_info = dir->i_sb->u.generic_sbp; + DPRINTK (DEBUG_I_MKNOD, "(%s): mode: 0%o dev: %d\n", + dentry->d_name.name, mode, rdev); parent = get_devfs_entry_from_vfs_inode (dir); if (parent == NULL) return -ENOENT; de = _devfs_alloc_entry (dentry->d_name.name, dentry->d_name.len, mode); @@ -3051,16 +3122,14 @@ static int devfs_mknod (struct inode *dir, struct dentry *dentry, int mode, de->inode.atime = CURRENT_TIME; de->inode.mtime = CURRENT_TIME; de->inode.ctime = CURRENT_TIME; - if ( ( inode = get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) + if ( ( inode = _devfs_get_vfs_inode (dir->i_sb, de, dentry) ) == NULL ) return -ENOMEM; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_I_MKNOD) - printk ("%s: new VFS inode(%u): %p dentry: %p\n", - DEVFS_NAME, de->inode.ino, inode, dentry); -#endif + DPRINTK (DEBUG_I_MKNOD, ": new VFS inode(%u): %p dentry: %p\n", + de->inode.ino, inode, dentry); d_instantiate (dentry, inode); - devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, - inode->i_uid, inode->i_gid, fs_info); + if ( !is_devfsd_or_child (fs_info) ) + devfsd_notify_de (de, DEVFSD_NOTIFY_CREATE, inode->i_mode, + inode->i_uid, inode->i_gid, fs_info, 0); return 0; } /* End Function devfs_mknod */ @@ -3124,15 +3193,11 @@ static struct super_block *devfs_read_super (struct super_block *sb, sb->s_blocksize_bits = 10; sb->s_magic = DEVFS_SUPER_MAGIC; sb->s_op = &devfs_sops; - if ( ( root_inode = get_vfs_inode (sb, root_entry, NULL) ) == NULL ) + if ( ( root_inode = _devfs_get_vfs_inode (sb, root_entry, NULL) ) == NULL ) goto out_no_root; sb->s_root = d_alloc_root (root_inode); if (!sb->s_root) goto out_no_root; -#ifdef CONFIG_DEVFS_DEBUG - if (devfs_debug & DEBUG_S_READ) - printk ("%s: read super, made devfs ptr: %p\n", - DEVFS_NAME, sb->u.generic_sbp); -#endif + DPRINTK (DEBUG_S_READ, "(): made devfs ptr: %p\n", sb->u.generic_sbp); return sb; out_no_root: @@ -3233,11 +3298,17 @@ static ssize_t devfsd_read (struct file *file, char *buf, size_t len, tlen = rpos - *ppos; if (done) { + devfs_handle_t parent; + spin_lock (&fs_info->devfsd_buffer_lock); fs_info->devfsd_first_event = entry->next; if (entry->next == NULL) fs_info->devfsd_last_event = NULL; spin_unlock (&fs_info->devfsd_buffer_lock); - for (; de != NULL; de = de->parent) devfs_put (de); + for (; de != NULL; de = parent) + { + parent = de->parent; + devfs_put (de); + } kmem_cache_free (devfsd_buf_cache, entry); if (ival > 0) atomic_sub (ival, &fs_info->devfsd_overrun_count); *ppos = 0; @@ -3274,6 +3345,8 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, } fs_info->devfsd_task = current; spin_unlock (&lock); + fs_info->devfsd_pgrp = (current->pgrp == current->pid) ? + current->pgrp : 0; fs_info->devfsd_file = file; fs_info->devfsd_info = kmalloc (sizeof *fs_info->devfsd_info, GFP_KERNEL); @@ -3304,7 +3377,7 @@ static int devfsd_ioctl (struct inode *inode, struct file *file, static int devfsd_close (struct inode *inode, struct file *file) { - struct devfsd_buf_entry *entry; + struct devfsd_buf_entry *entry, *next; struct fs_info *fs_info = inode->i_sb->u.generic_sbp; if (fs_info->devfsd_file != file) return 0; @@ -3320,10 +3393,14 @@ static int devfsd_close (struct inode *inode, struct file *file) fs_info->devfsd_info = NULL; } spin_unlock (&fs_info->devfsd_buffer_lock); + fs_info->devfsd_pgrp = 0; fs_info->devfsd_task = NULL; wake_up (&fs_info->revalidate_wait_queue); - for (; entry; entry = entry->next) + for (; entry; entry = next) + { + next = entry->next; kmem_cache_free (devfsd_buf_cache, entry); + } return 0; } /* End Function devfsd_close */ @@ -3353,14 +3430,15 @@ static int __init init_devfs_fs (void) printk ("%s: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", DEVFS_NAME, DEVFS_VERSION); + devfsd_buf_cache = kmem_cache_create ("devfsd_event", + sizeof (struct devfsd_buf_entry), + 0, 0, NULL, NULL); + if (!devfsd_buf_cache) OOPS ("(): unable to allocate event slab\n"); #ifdef CONFIG_DEVFS_DEBUG devfs_debug = devfs_debug_init; printk ("%s: devfs_debug: 0x%0x\n", DEVFS_NAME, devfs_debug); #endif printk ("%s: boot_options: 0x%0x\n", DEVFS_NAME, boot_options); - devfsd_buf_cache = kmem_cache_create ("devfsd_event", - sizeof (struct devfsd_buf_entry), - 0, 0, NULL, NULL); err = register_filesystem (&devfs_fs_type); if (!err) { |
