📄 base.c
字号:
} 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); 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 */ if (parent->u.dir.first == NULL) parent->u.dir.first = new; else parent->u.dir.last->next = new; parent->u.dir.last = new; return new;} /* End Function create_entry */static void update_devfs_inode_from_entry (struct devfs_entry *de){ if (de == NULL) return; if ( S_ISDIR (de->mode) ) { de->inode.mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; de->inode.uid = 0; de->inode.gid = 0; } else if ( S_ISLNK (de->mode) ) { de->inode.mode = S_IFLNK | S_IRUGO | S_IXUGO; de->inode.uid = 0; de->inode.gid = 0; } else if ( S_ISFIFO (de->mode) ) { de->inode.mode = de->mode; de->inode.uid = de->u.fifo.uid; de->inode.gid = de->u.fifo.gid; } else { if (de->u.fcb.auto_owner) de->inode.mode = (de->mode & ~S_IALLUGO) | S_IRUGO | S_IWUGO; else de->inode.mode = de->mode; de->inode.uid = de->u.fcb.default_uid; de->inode.gid = de->u.fcb.default_gid; }} /* End Function update_devfs_inode_from_entry *//** * get_root_entry - Get the root devfs entry. * * Returns the root devfs entry on success, else %NULL. */static struct devfs_entry *get_root_entry (void){ struct devfs_entry *new; /* Always ensure the root is created */ if (root_entry != NULL) return root_entry; if ( ( root_entry = create_entry (NULL, NULL, 0) ) == NULL ) return NULL; root_entry->registered = TRUE; root_entry->mode = S_IFDIR; /* Force an inode update, because lookup() is never done for the root */ update_devfs_inode_from_entry (root_entry); /* And create the entry for ".devfsd" */ if ( ( new = create_entry (root_entry, ".devfsd", 0) ) == NULL ) return NULL; new->registered = TRUE; new->u.fcb.u.device.major = next_devnum_char >> 8; new->u.fcb.u.device.minor = next_devnum_char & 0xff; ++next_devnum_char; new->mode = S_IFCHR | S_IRUSR | S_IWUSR; new->u.fcb.default_uid = 0; new->u.fcb.default_gid = 0; new->u.fcb.ops = &devfsd_fops; return root_entry;} /* End Function get_root_entry *//** * search_for_entry - Search for an entry in the devfs tree. * @dir: The parent directory to search from. If this is %NULL the root is used * @name: The name of the entry. * @namelen: The number of characters in @name. * @mkdir: If %TRUE intermediate directories are created as needed. * @mkfile: If %TRUE the file entry is created if it doesn't exist. * @is_new: If the returned entry was newly made, %TRUE is written here. If * this is %NULL nothing is written here. * @traverse_symlink: If %TRUE then symbolic links are traversed. * * If the entry is created, then it will be in the unregistered state. * Returns a pointer to the entry on success, else %NULL. */static struct devfs_entry *search_for_entry (struct devfs_entry *dir, const char *name, unsigned int namelen, int mkdir, int mkfile, int *is_new, int traverse_symlink){ int len; const char *subname, *stop, *ptr; struct devfs_entry *entry; if (is_new) *is_new = FALSE; if (dir == NULL) dir = get_root_entry (); if (dir == NULL) return NULL; /* Extract one filename component */ subname = name; stop = name + namelen; while (subname < stop) { /* Search for a possible '/' */ for (ptr = subname; (ptr < stop) && (*ptr != '/'); ++ptr); if (ptr >= stop) { /* Look for trailing component */ len = stop - subname; entry = search_for_entry_in_dir (dir, subname, len, traverse_symlink); if (entry != NULL) return entry; if (!mkfile) return NULL; entry = create_entry (dir, subname, len); if (entry && is_new) *is_new = TRUE; return entry; } /* Found '/': search for directory */ if (strncmp (subname, "../", 3) == 0) { /* Going up */ dir = dir->parent; if (dir == NULL) return NULL; /* Cannot escape from devfs */ subname += 3; continue; } len = ptr - subname; entry = search_for_entry_in_dir (dir, subname, len, traverse_symlink); if (!entry && !mkdir) return NULL; if (entry == NULL) { /* Make it */ if ( ( entry = create_entry (dir, subname, len) ) == NULL ) return NULL; entry->mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; if (is_new) *is_new = TRUE; } if ( !S_ISDIR (entry->mode) ) { printk ("%s: existing non-directory entry\n", DEVFS_NAME); return NULL; } /* Ensure an unregistered entry is re-registered and visible */ entry->registered = TRUE; entry->hide = FALSE; subname = ptr + 1; dir = entry; } return NULL;} /* End Function search_for_entry *//** * 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. */static struct devfs_entry *find_by_dev (struct devfs_entry *dir, unsigned int major, unsigned int minor, char type){ struct devfs_entry *entry, *de; if (dir == NULL) return NULL; if ( !S_ISDIR (dir->mode) ) { printk ("%s: find_by_dev(): not a directory\n", DEVFS_NAME); return NULL; } /* First search files in this directory */ for (entry = dir->u.dir.first; entry != NULL; entry = entry->next) { if ( !S_ISCHR (entry->mode) && !S_ISBLK (entry->mode) ) continue; if ( S_ISCHR (entry->mode) && (type != DEVFS_SPECIAL_CHR) ) continue; if ( S_ISBLK (entry->mode) && (type != DEVFS_SPECIAL_BLK) ) continue; if ( (entry->u.fcb.u.device.major == major) && (entry->u.fcb.u.device.minor == minor) ) return entry; /* Not found: try the next one */ } /* Now recursively search the subdirectories: this is a stack chomper */ 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); if (de) return de; } return NULL;} /* End Function find_by_dev *//** * 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. * 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. * * FIXME: What the hell is @handle? - ch * Returns the devfs_entry pointer on success, else %NULL. */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){ struct devfs_entry *entry; if (name != NULL) { if (namelen < 1) namelen = strlen (name); if (name[0] == '/') { /* Skip leading pathname component */ if (namelen < 2) { printk ("%s: find_entry(%s): too short\n", DEVFS_NAME, 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); return NULL; } ++name; --namelen; } entry = search_for_entry (dir, name, namelen, FALSE, FALSE, NULL, traverse_symlink); if (entry != NULL) return entry; } /* 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 */static struct devfs_entry *get_devfs_entry_from_vfs_inode (struct inode *inode){ 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; return fs_info->table[inode->i_ino - FIRST_INODE];} /* End Function get_devfs_entry_from_vfs_inode *//** * free_dentries - Free the dentries for a device entry and invalidate inodes. * @de: The entry. */static void free_dentries (struct devfs_entry *de){ struct dentry *dentry; spin_lock(&dcache_lock); dentry = de->inode.dentry; if (dentry != NULL) { dget_locked (dentry); de->inode.dentry = NULL; spin_unlock(&dcache_lock); /* Forcefully remove the inode */ if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; d_drop (dentry); dput (dentry); } else spin_unlock(&dcache_lock);} /* End Function free_dentries *//** * is_devfsd_or_child - Test if the current process is devfsd or one of its children. * @fs_info: The filesystem information. * * Returns %TRUE if devfsd or child, else %FALSE. */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 (p == fs_info->devfsd_task) return (TRUE); } return (FALSE);} /* End Function is_devfsd_or_child *//** * devfsd_queue_empty - Test if devfsd has work pending in its event queue. * @fs_info: The filesystem information. * * Returns %TRUE if the queue is empty, else %FALSE. */static inline int devfsd_queue_empty (struct fs_info *fs_info){ return (fs_info->devfsd_buf_out == fs_info->devfsd_buf_in) ? TRUE : FALSE;} /* End Function devfsd_queue_empty *//** * wait_for_devfsd_finished - Wait for devfsd to finish processing its event queue. * @fs_info: The filesystem information. * * Returns %TRUE if no more waiting will be required, else %FALSE. */static int wait_for_devfsd_finished (struct fs_info *fs_info){ DECLARE_WAITQUEUE (wait, current); if (fs_info->devfsd_task == NULL) return (TRUE); if (devfsd_queue_empty (fs_info) && fs_info->devfsd_sleeping) return TRUE; if ( is_devfsd_or_child (fs_info) ) return (FALSE); add_wait_queue (&fs_info->revalidate_wait_queue, &wait); current->state = TASK_UNINTERRUPTIBLE; if (!devfsd_queue_empty (fs_info) || !fs_info->devfsd_sleeping) if (fs_info->devfsd_task) schedule(); remove_wait_queue (&fs_info->revalidate_wait_queue, &wait); current->state = TASK_RUNNING; return (TRUE);} /* End Function wait_for_devfsd_finished *//** * devfsd_notify_one - Notify a single devfsd daemon of a change. * @data: Data to be passed. * @type: The type of change. * @mode: The mode of the entry. * @uid: The user ID. * @gid: The group ID. * @fs_info: The filesystem info. * * Returns %TRUE if an event was queued and devfsd woken up, else %FALSE. */static int devfsd_notify_one (void *data, unsigned int type, umode_t mode, uid_t uid, gid_t gid, struct fs_info *fs_info){ unsigned int next_pos; unsigned long flags; struct devfsd_buf_entry *entry; static spinlock_t lock = SPIN_LOCK_UNLOCKED; if ( !( fs_info->devfsd_event_mask & (1 << type) ) ) return (FALSE); next_pos = fs_info->devfsd_buf_in + 1; if (next_pos >= devfsd_buf_size) next_pos = 0; if (next_pos == fs_info->devfsd_buf_out) { /* Running up the arse of the reader: drop it */ atomic_inc (&fs_info->devfsd_overrun_count); return (FALSE); } spin_lock_irqsave (&lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -