📄 base.c
字号:
*leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0; for (; namelen > 0; name += next_pos, namelen -= next_pos) { struct devfs_entry *de, *old; if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL ) { de = _devfs_alloc_entry (name, next_pos, MODE_DIR); devfs_get (de); if ( !de || _devfs_append_entry (dir, de, FALSE, &old) ) { devfs_put (de); if ( !old || !S_ISDIR (old->mode) ) { devfs_put (old); devfs_put (dir); return NULL; } de = old; /* Use the existing directory */ } } if (de == dir->parent) { devfs_put (dir); devfs_put (de); return NULL; } devfs_put (dir); dir = de; if (name[next_pos] == '/') ++next_pos; } return dir;} /* End Function _devfs_make_parent_for_leaf */static devfs_handle_t _devfs_prepare_leaf (devfs_handle_t *dir, const char *name, umode_t mode){ int namelen, leaf_pos; struct devfs_entry *de; namelen = strlen (name); if ( ( *dir = _devfs_make_parent_for_leaf (*dir, name, namelen, &leaf_pos) ) == NULL ) { 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): could not allocate entry\n", name); devfs_put (*dir); return NULL; } return de;} /* End Function _devfs_prepare_leaf */static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir, const char *name, int namelen, int traverse_symlink){ int next_pos = 0; if (dir == NULL) dir = _devfs_get_root_entry (); if (dir == NULL) return NULL; devfs_get (dir); for (; namelen > 0; name += next_pos, namelen -= next_pos) { struct devfs_entry *de, *link; if ( ( de = _devfs_descend (dir, name, namelen, &next_pos) ) == NULL ) { devfs_put (dir); return NULL; } if (S_ISLNK (de->mode) && traverse_symlink) { /* Need to follow the link: this is a stack chomper */ link = _devfs_walk_path (dir, de->u.symlink.linkname, de->u.symlink.length, TRUE); devfs_put (de); if (!link) { devfs_put (dir); return NULL; } de = link; } devfs_put (dir); dir = de; if (name[next_pos] == '/') ++next_pos; } return dir;} /* End Function _devfs_walk_path *//** * _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. An implicit * devfs_get() is performed. */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; devfs_get (dir); if (dir == NULL) return NULL; if ( !S_ISDIR (dir->mode) ) { PRINTK ("(%p): not a directory\n", dir); devfs_put (dir); return NULL; } /* First search files in this directory */ read_lock (&dir->u.dir.lock); 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) ) { devfs_get (entry); read_unlock (&dir->u.dir.lock); devfs_put (dir); 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 = _devfs_find_by_dev (entry, major, minor, type); if (de) { read_unlock (&dir->u.dir.lock); devfs_put (dir); return de; } } read_unlock (&dir->u.dir.lock); devfs_put (dir); return NULL;} /* End Function _devfs_find_by_dev *//** * _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 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. An implicit * devfs_get() is performed. */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) { unsigned int namelen = strlen (name); if (name[0] == '/') { /* Skip leading pathname component */ if (namelen < 2) { PRINTK ("(%s): too short\n", name); return NULL; } for (++name, --namelen; (*name != '/') && (namelen > 0); ++name, --namelen); if (namelen < 2) { PRINTK ("(%s): too short\n", name); return NULL; } ++name; --namelen; } entry = _devfs_walk_path (dir, name, namelen, traverse_symlink); if (entry != NULL) return entry; } /* Have to search by major and minor: slow */ if ( (major == 0) && (minor == 0) ) return NULL; 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 *//** * free_dentry - Free the dentry for a device entry and invalidate inode. * @de: The entry. * * This must only be called after the entry has been unhooked from it's * parent directory. */static void free_dentry (struct devfs_entry *de){ struct dentry *dentry = de->inode.dentry; if (!dentry) return; spin_lock (&dcache_lock); dget_locked (dentry); spin_unlock (&dcache_lock); /* Forcefully remove the inode */ if (dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; d_drop (dentry); dput (dentry);} /* End Function free_dentry *//** * 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; 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 *//** * 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_last_event) ? FALSE : TRUE;} /* 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_de - Notify the devfsd daemon of a change. * @de: The devfs entry that has changed. This and all parent entries will * have their reference counts incremented if the event was queued. * @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_de (struct devfs_entry *de, unsigned short type, umode_t mode, 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, atomic ? SLAB_ATOMIC : SLAB_KERNEL) ) == NULL ) { atomic_inc (&fs_info->devfsd_overrun_count); return (FALSE); } for (curr = de; curr != NULL; curr = curr->parent) devfs_get (curr); entry->de = de; entry->type = type; entry->mode = mode; entry->uid = uid; entry->gid = gid; entry->next = NULL; spin_lock (&fs_info->devfsd_buffer_lock); if (!fs_info->devfsd_first_event) fs_info->devfsd_first_event = entry; if (fs_info->devfsd_last_event) fs_info->devfsd_last_event->next = entry; fs_info->devfsd_last_event = entry; spin_unlock (&fs_info->devfsd_buffer_lock); wake_up_interruptible (&fs_info->devfsd_wait_queue); return (TRUE);} /* End Function devfsd_notify_de *//** * devfsd_notify - Notify the devfsd daemon of a change. * @de: The devfs entry that has changed. * @type: The type of change event. * @wait: If TRUE, the function waits for the daemon to finish processing * the event. */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, 0) && 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -