📄 base.c
字号:
* this to whatever you like, and change it once the file is opened (the next * file opened will not see this change). * * Returns a handle which may later be used in a call to devfs_unregister(). * On failure %NULL is returned. */devfs_handle_t devfs_register (devfs_handle_t dir, const char *name, unsigned int flags, unsigned int major, unsigned int minor, umode_t mode, void *ops, void *info){ char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK; int err; kdev_t devnum = NODEV; struct devfs_entry *de; if (name == NULL) { PRINTK ("(): NULL name pointer\n"); return NULL; } if (ops == NULL) { if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); if (ops == NULL) { PRINTK ("(%s): NULL ops pointer\n", name); return NULL; } PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops); } if ( S_ISDIR (mode) ) { PRINTK ("(%s): creating directories is not allowed\n", name); return NULL; } if ( S_ISLNK (mode) ) { PRINTK ("(%s): creating symlinks is not allowed\n", name); return NULL; } if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) && (flags & DEVFS_FL_AUTO_DEVNUM) ) { if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) ) { PRINTK ("(%s): exhausted %s device numbers\n", name, S_ISCHR (mode) ? "char" : "block"); return NULL; } major = major (devnum); minor = minor (devnum); } if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL ) { PRINTK ("(%s): could not prepare leaf\n", name); if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum); return NULL; } 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 = kdev_none (devnum) ? FALSE : TRUE; } else if ( !S_ISREG (mode) ) { PRINTK ("(%s): illegal mode: %x\n", name, mode); devfs_put (de); devfs_put (dir); return (NULL); } de->info = info; if (flags & DEVFS_FL_CURRENT_OWNER) { de->inode.uid = current->uid; de->inode.gid = current->gid; } else { de->inode.uid = 0; de->inode.gid = 0; } de->u.fcb.ops = ops; de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE; de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE; de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE; if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE; if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) ) != 0 ) { PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum); return NULL; } 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;} /* End Function devfs_register *//** * _devfs_unhook - Unhook a device entry from its parents list * @de: The entry to unhook. * * Returns %TRUE if the entry was unhooked, else %FALSE if it was * previously unhooked. * The caller must have a write lock on the parent directory. */static int _devfs_unhook (struct devfs_entry *de){ struct devfs_entry *parent; if ( !de || (de->prev == de) ) return FALSE; parent = de->parent; 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; de->prev = de; /* Indicate we're unhooked */ de->next = NULL; /* Force early termination for <devfs_readdir> */ if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.removable ) --parent->u.dir.num_removable; return TRUE;} /* End Function _devfs_unhook *//** * _devfs_unregister - Unregister a device entry from it's parent. * @dir: The parent directory. * @de: The entry to unregister. * * The caller must have a write lock on the parent directory, which is * unlocked by this function. */static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de){ int unhooked = _devfs_unhook (de); write_unlock (&dir->u.dir.lock); if (!unhooked) return; devfs_get (dir); devfs_unregister (de->slave); /* Let it handle the locking */ devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0); free_dentry (de); devfs_put (dir); if ( !S_ISDIR (de->mode) ) return; while (TRUE) /* Recursively unregister: this is a stack chomper */ { struct devfs_entry *child; write_lock (&de->u.dir.lock); de->u.dir.no_more_additions = TRUE; child = de->u.dir.first; VERIFY_ENTRY (child); _devfs_unregister (de, child); if (!child) break; DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p refcount: %d\n", child->name, child, atomic_read (&child->refcount) ); devfs_put (child); }} /* End Function _devfs_unregister *//** * devfs_unregister - Unregister a device entry. * @de: A handle previously created by devfs_register() or returned from * 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; DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p refcount: %d\n", de->name, de, atomic_read (&de->refcount) ); write_lock (&de->parent->u.dir.lock); _devfs_unregister (de->parent, de); devfs_put (de);} /* End Function devfs_unregister */static int devfs_do_symlink (devfs_handle_t dir, const char *name, unsigned int flags, const char *link, devfs_handle_t *handle, void *info){ int err; unsigned int linklength; char *newlink; struct devfs_entry *de; if (handle != NULL) *handle = NULL; if (name == NULL) { PRINTK ("(): NULL name pointer\n"); return -EINVAL; } if (link == NULL) { PRINTK ("(%s): NULL link pointer\n", name); return -EINVAL; } linklength = strlen (link); if ( ( newlink = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL ) return -ENOMEM; memcpy (newlink, link, linklength); newlink[linklength] = '\0'; if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) ) == NULL ) { PRINTK ("(%s): could not prepare leaf\n", name); kfree (newlink); return -ENOTDIR; } de->info = info; de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE; de->u.symlink.linkname = newlink; de->u.symlink.length = linklength; if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 ) { PRINTK ("(%s): could not append to parent, err: %d\n", name, err); devfs_put (dir); return err; } devfs_put (dir);#ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); stat_num_bytes += linklength + 1; spin_unlock (&stat_lock);#endif if (handle != NULL) *handle = de; return 0;} /* End Function devfs_do_symlink *//** * devfs_mk_symlink Create a symbolic link in the devfs namespace. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * new name is relative to the root of the devfs. * @name: The name of the entry. * @flags: A set of bitwise-ORed flags (DEVFS_FL_*). * @link: The destination name. * @handle: The handle to the symlink entry is written here. This may be %NULL. * @info: An arbitrary pointer which will be associated with the entry. * * Returns 0 on success, else a negative error code is returned. */int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags, const char *link, devfs_handle_t *handle, void *info){ int err; 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) de->vfs_deletable = TRUE; else *handle = de; devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT); return 0;} /* End Function devfs_mk_symlink *//** * devfs_mk_dir - Create a directory in the devfs namespace. * @dir: The handle to the parent devfs directory entry. If this is %NULL the * new name is relative to the root of the devfs. * @name: The name of the entry. * @info: An arbitrary pointer which will be associated with the entry. * * Use of this function is optional. The devfs_register() function * will automatically create intermediate directories as needed. This function * is provided for efficiency reasons, as it provides a handle to a directory. * Returns a handle which may later be used in a call to devfs_unregister(). * On failure %NULL is returned. */devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info){ int err; struct devfs_entry *de, *old; if (name == NULL) { PRINTK ("(): NULL name pointer\n"); return NULL; } if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL ) { PRINTK ("(%s): could not prepare leaf\n", name); return NULL; } de->info = info; if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 ) {#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_deletable = 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; } 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_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. * @major: The major number. This is used if @name is %NULL. * @minor: The minor number. This is used if @name is %NULL. * @type: The type of special file to search for. This may be either * %DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. * @traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are * 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(). 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; de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks); devfs_put (de); return de;} /* End Function devfs_find_handle *//** * devfs_get_flags - Get the flags for a devfs entry. * @de: The handle to the device entry. * @flags: The flags are written here. * * Returns 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -