base.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,003 行 · 第 1/5 页
C
2,003 行
} 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 */ /* FIXME what if it puts outside of mounted tree? */ 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_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. * @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, int traverse_symlink){ 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; } return _devfs_walk_path(dir, name, namelen, traverse_symlink);} /* 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 its * 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 = current; if (p == fs_info->devfsd_task) return (TRUE); if (process_group(p) == fs_info->devfsd_pgrp) return (TRUE); read_lock(&tasklist_lock); for (; p != &init_task; p = p->real_parent) { if (p == fs_info->devfsd_task) { read_unlock(&tasklist_lock); return (TRUE); } } read_unlock(&tasklist_lock); 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); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&fs_info->revalidate_wait_queue, &wait); 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); __set_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){ 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, 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){ devfsd_notify_de(de, type, de->mode, current->euid, current->egid, &fs_info);}static int devfs_mk_dev(dev_t dev, umode_t mode, const char *fmt, va_list args){ struct devfs_entry *dir = NULL, *de; char buf[64]; int error, n; n = vsnprintf(buf, sizeof(buf), fmt, args); if (n >= sizeof(buf) || !buf[0]) { printk(KERN_WARNING "%s: invalid format string %s\n", __FUNCTION__, fmt); return -EINVAL; } de = _devfs_prepare_leaf(&dir, buf, mode); if (!de) { printk(KERN_WARNING "%s: could not prepare leaf for %s\n", __FUNCTION__, buf); return -ENOMEM; /* could be more accurate... */ } de->u.dev = dev; error = _devfs_append_entry(dir, de, NULL); if (error) { printk(KERN_WARNING "%s: could not append to parent for %s\n", __FUNCTION__, buf); goto out; } devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); out: devfs_put(dir); return error;}int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...){ va_list args; if (!S_ISBLK(mode)) { printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", __FUNCTION__, mode, fmt); return -EINVAL; } va_start(args, fmt); return devfs_mk_dev(dev, mode, fmt, args);}EXPORT_SYMBOL(devfs_mk_bdev);int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...){ va_list args; if (!S_ISCHR(mode)) { printk(KERN_WARNING "%s: invalide mode (%u) for %s\n", __FUNCTION__, mode, fmt); return -EINVAL; } va_start(args, fmt); return devfs_mk_dev(dev, mode, fmt, args);}EXPORT_SYMBOL(devfs_mk_cdev);/** * _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> */ return TRUE;} /* End Function _devfs_unhook *//** * _devfs_unregister - Unregister a device entry from its 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); devfsd_notify(de, DEVFSD_NOTIFY_UNREGISTERED); 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 */static int devfs_do_symlink(devfs_handle_t dir, const char *name, const char *link, devfs_handle_t * handle){ 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 = NULL; de->u.symlink.linkname = newlink; de->u.symlink.length = linklength; if ((err = _devfs_append_entry(dir, de, 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 *//**
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?