📄 base.c
字号:
fs_info->devfsd_buffer_in_use = TRUE; next_pos = fs_info->devfsd_buf_in + 1; if (next_pos >= devfsd_buf_size) next_pos = 0; entry = (struct devfsd_buf_entry *) fs_info->devfsd_buffer + fs_info->devfsd_buf_in; entry->data = data; entry->type = type; entry->mode = mode; entry->uid = uid; entry->gid = gid; fs_info->devfsd_buf_in = next_pos; fs_info->devfsd_buffer_in_use = FALSE; spin_unlock_irqrestore (&lock, flags); wake_up_interruptible (&fs_info->devfsd_wait_queue); return (TRUE);} /* End Function devfsd_notify_one *//** * devfsd_notify - Notify all devfsd daemons of a change. * @de: The devfs entry that has changed. * @type: The type of change event. * @wait: If TRUE, the functions waits for all daemons to finish processing * the event. */static void devfsd_notify (struct devfs_entry *de, unsigned int type, int wait){ if (devfsd_notify_one (de, type, de->mode, current->euid, current->egid, &fs_info) && wait) wait_for_devfsd_finished (&fs_info);} /* End Function devfsd_notify *//** * devfs_register - Register a device entry. * @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_*). * @major: The major number. Not needed for regular files. * @minor: The minor number. Not needed for regular files. * @mode: The default file mode. * @ops: The &file_operations or &block_device_operations structure. * This must not be externally deallocated. * @info: An arbitrary pointer which will be written to the @private_data * field of the &file structure passed to the device driver. You can set * 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){ int is_new; struct devfs_entry *de; if (name == NULL) { printk ("%s: devfs_register(): NULL name pointer\n", DEVFS_NAME); return NULL; } if (ops == NULL) { if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major); if (ops == NULL) { printk ("%s: devfs_register(%s): NULL ops pointer\n", DEVFS_NAME, name); return NULL; } printk ("%s: devfs_register(%s): NULL ops, got %p from major table\n", DEVFS_NAME, name, ops); } if ( S_ISDIR (mode) ) { printk("%s: devfs_register(%s): creating directories is not allowed\n", DEVFS_NAME, name); return NULL; } if ( S_ISLNK (mode) ) { printk ("%s: devfs_register(%s): creating symlinks is not allowed\n", DEVFS_NAME, name); return NULL; } if ( S_ISCHR (mode) && (flags & DEVFS_FL_AUTO_DEVNUM) ) { if (next_devnum_char >= MAX_DEVNUM) { printk ("%s: devfs_register(%s): exhausted char device numbers\n", DEVFS_NAME, name); return NULL; } major = next_devnum_char >> 8; minor = next_devnum_char & 0xff; ++next_devnum_char; } if ( S_ISBLK (mode) && (flags & DEVFS_FL_AUTO_DEVNUM) ) { if (next_devnum_block >= MAX_DEVNUM) { printk ("%s: devfs_register(%s): exhausted block device numbers\n", DEVFS_NAME, name); return NULL; } major = next_devnum_block >> 8; minor = next_devnum_block & 0xff; ++next_devnum_block; } de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new, FALSE); if (de == NULL) { printk ("%s: devfs_register(): could not create entry: \"%s\"\n", DEVFS_NAME, name); return NULL; }#ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_REGISTER) printk ("%s: devfs_register(%s): de: %p %s\n", DEVFS_NAME, name, de, is_new ? "new" : "existing");#endif if (!is_new) { /* Existing entry */ if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) ) { printk ("%s: devfs_register(): existing non-device/file entry: \"%s\"\n", DEVFS_NAME, name); return NULL; } if (de->registered) { printk("%s: devfs_register(): device already registered: \"%s\"\n", DEVFS_NAME, name); return NULL; } } de->registered = TRUE; if ( S_ISCHR (mode) || S_ISBLK (mode) ) { de->u.fcb.u.device.major = major; de->u.fcb.u.device.minor = minor; } else if ( S_ISREG (mode) ) de->u.fcb.u.file.size = 0; else { printk ("%s: devfs_register(): illegal mode: %x\n", DEVFS_NAME, mode); return (NULL); } de->info = info; de->mode = mode; if (flags & DEVFS_FL_CURRENT_OWNER) { de->u.fcb.default_uid = current->uid; de->u.fcb.default_gid = current->gid; } else { de->u.fcb.default_uid = 0; de->u.fcb.default_gid = 0; } de->registered = TRUE; 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; if (flags & DEVFS_FL_REMOVABLE) { de->u.fcb.removable = TRUE; ++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; devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT); return de;} /* End Function devfs_register *//** * unregister - Unregister a device entry. * @de: The entry to unregister. */static void unregister (struct devfs_entry *de){ struct devfs_entry *child; if ( (child = de->slave) != NULL ) { de->slave = NULL; /* Unhook first in case slave is parent directory */ unregister (child); } if (de->registered) { devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0); free_dentries (de); } de->info = NULL; if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) ) { de->registered = FALSE; de->u.fcb.ops = NULL; return; } if ( S_ISLNK (de->mode) ) { de->registered = FALSE; if (de->u.symlink.linkname != NULL) kfree (de->u.symlink.linkname); de->u.symlink.linkname = NULL; return; } if ( S_ISFIFO (de->mode) ) { de->registered = FALSE; return; } if (!de->registered) return; if ( !S_ISDIR (de->mode) ) { printk ("%s: unregister(): unsupported type\n", DEVFS_NAME); return; } de->registered = FALSE; /* Now recursively search the subdirectories: this is a stack chomper */ for (child = de->u.dir.first; child != NULL; child = child->next) {#ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_UNREGISTER) printk ("%s: unregister(): child->name: \"%s\" child: %p\n", DEVFS_NAME, child->name, child);#endif unregister (child); }} /* End Function 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. */void devfs_unregister (devfs_handle_t de){ if (de == 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 unregister (de);} /* End Function devfs_unregister *//** * 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 is_new; unsigned int linklength; char *newname; struct devfs_entry *de; if (handle != NULL) *handle = NULL; if (name == NULL) { printk ("%s: devfs_mk_symlink(): NULL name pointer\n", DEVFS_NAME); return -EINVAL; }#ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_REGISTER) printk ("%s: devfs_mk_symlink(%s)\n", DEVFS_NAME, name);#endif if (link == NULL) { printk ("%s: devfs_mk_symlink(): NULL link pointer\n", DEVFS_NAME); 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) { printk ("%s: devfs_mk_symlink(): non-link entry already exists\n", DEVFS_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; de->registered = TRUE; 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; } if (de->u.symlink.linkname != NULL) kfree (de->u.symlink.linkname); de->u.symlink.linkname = newname; memcpy (de->u.symlink.linkname, link, linklength); de->u.symlink.linkname[linklength] = '\0'; de->u.symlink.length = linklength; 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 is_new; struct devfs_entry *de; if (name == NULL) { printk ("%s: devfs_mk_dir(): NULL name pointer\n", DEVFS_NAME); return NULL; } de = search_for_entry (dir, name, strlen (name), TRUE, TRUE, &is_new, FALSE); if (de == NULL) { printk ("%s: devfs_mk_dir(): could not create entry: \"%s\"\n", DEVFS_NAME, name); return NULL; } if (!S_ISDIR (de->mode) && de->registered) { printk ("%s: devfs_mk_dir(): existing non-directory entry: \"%s\"\n", DEVFS_NAME, name); return NULL; }#ifdef CONFIG_DEVFS_DEBUG if (devfs_debug & DEBUG_REGISTER) printk ("%s: devfs_mk_dir(%s): de: %p %s\n", DEVFS_NAME, name, de, is_new ? "new" : "existing");#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -