base.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,003 行 · 第 1/5 页
C
2,003 行
struct devfsd_buf_entry { struct devfs_entry *de; /* The name is generated with this */ unsigned short type; /* The type of event */ umode_t mode; uid_t uid; gid_t gid; struct devfsd_buf_entry *next;};struct fs_info { /* This structure is for the mounted devfs */ struct super_block *sb; spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */ struct devfsd_buf_entry *devfsd_first_event; struct devfsd_buf_entry *devfsd_last_event; volatile int devfsd_sleeping; volatile struct task_struct *devfsd_task; volatile pid_t devfsd_pgrp; volatile struct file *devfsd_file; struct devfsd_notify_struct *devfsd_info; volatile unsigned long devfsd_event_mask; atomic_t devfsd_overrun_count; wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */ wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */};static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED };static kmem_cache_t *devfsd_buf_cache;#ifdef CONFIG_DEVFS_DEBUGstatic unsigned int devfs_debug_init __initdata = DEBUG_NONE;static unsigned int devfs_debug = DEBUG_NONE;static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;static unsigned int stat_num_entries;static unsigned int stat_num_bytes;#endifstatic unsigned char poison_array[8] = { 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a };#ifdef CONFIG_DEVFS_MOUNTstatic unsigned int boot_options = OPTION_MOUNT;#elsestatic unsigned int boot_options = OPTION_NONE;#endif/* Forward function declarations */static devfs_handle_t _devfs_walk_path(struct devfs_entry *dir, const char *name, int namelen, int traverse_symlink);static ssize_t devfsd_read(struct file *file, char __user *buf, size_t len, loff_t * ppos);static int devfsd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int devfsd_close(struct inode *inode, struct file *file);#ifdef CONFIG_DEVFS_DEBUGstatic ssize_t stat_read(struct file *file, char __user *buf, size_t len, loff_t * ppos);static struct file_operations stat_fops = { .open = nonseekable_open, .read = stat_read,};#endif/* Devfs daemon file operations */static struct file_operations devfsd_fops = { .open = nonseekable_open, .read = devfsd_read, .ioctl = devfsd_ioctl, .release = devfsd_close,};/* Support functions follow *//** * devfs_get - Get a reference to a devfs entry. * @de: The devfs entry. */static struct devfs_entry *devfs_get(struct devfs_entry *de){ VERIFY_ENTRY(de); if (de) atomic_inc(&de->refcount); return de;} /* End Function devfs_get *//** * devfs_put - Put (release) a reference to a devfs entry. * @de: The handle to the devfs entry. */static void devfs_put(devfs_handle_t de){ if (!de) return; VERIFY_ENTRY(de); if (de->info == POISON_PTR) OOPS("(%p): poisoned pointer\n", de); if (!atomic_dec_and_test(&de->refcount)) return; if (de == root_entry) OOPS("(%p): root entry being freed\n", de); DPRINTK(DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", de->name, de, de->parent, de->parent ? de->parent->name : "no parent"); if (S_ISLNK(de->mode)) kfree(de->u.symlink.linkname); WRITE_ENTRY_MAGIC(de, 0);#ifdef CONFIG_DEVFS_DEBUG spin_lock(&stat_lock); --stat_num_entries; stat_num_bytes -= sizeof *de + de->namelen; if (S_ISLNK(de->mode)) stat_num_bytes -= de->u.symlink.length + 1; spin_unlock(&stat_lock);#endif de->info = POISON_PTR; kfree(de);} /* End Function devfs_put *//** * _devfs_search_dir - Search for a devfs entry in a directory. * @dir: The directory to search. * @name: The name of the entry to search for. * @namelen: The number of characters in @name. * * Search for a devfs entry in a directory and returns a pointer to the entry * on success, else %NULL. The directory must be locked already. * An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_search_dir(struct devfs_entry *dir, const char *name, unsigned int namelen){ struct devfs_entry *curr; if (!S_ISDIR(dir->mode)) { PRINTK("(%s): not a directory\n", dir->name); return NULL; } for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) { if (curr->namelen != namelen) continue; if (memcmp(curr->name, name, namelen) == 0) break; /* Not found: try the next one */ } return devfs_get(curr);} /* End Function _devfs_search_dir *//** * _devfs_alloc_entry - Allocate a devfs entry. * @name: the name of the entry * @namelen: the number of characters in @name * @mode: the mode for the entry * * Allocate a devfs entry and returns a pointer to the entry on success, else * %NULL. */static struct devfs_entry *_devfs_alloc_entry(const char *name, unsigned int namelen, umode_t mode){ struct devfs_entry *new; static unsigned long inode_counter = FIRST_INODE; static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; if (name && (namelen < 1)) namelen = strlen(name); if ((new = kmalloc(sizeof *new + namelen, GFP_KERNEL)) == NULL) return NULL; memset(new, 0, sizeof *new + namelen); /* Will set '\0' on name */ new->mode = mode; if (S_ISDIR(mode)) rwlock_init(&new->u.dir.lock); atomic_set(&new->refcount, 1); spin_lock(&counter_lock); new->inode.ino = inode_counter++; spin_unlock(&counter_lock); if (name) memcpy(new->name, name, namelen); new->namelen = namelen; WRITE_ENTRY_MAGIC(new, MAGIC_VALUE);#ifdef CONFIG_DEVFS_DEBUG spin_lock(&stat_lock); ++stat_num_entries; stat_num_bytes += sizeof *new + namelen; spin_unlock(&stat_lock);#endif return new;} /* End Function _devfs_alloc_entry *//** * _devfs_append_entry - Append a devfs entry to a directory's child list. * @dir: The directory to add to. * @de: The devfs entry to append. * @old_de: If an existing entry exists, it will be written here. This may * be %NULL. An implicit devfs_get() is performed on this entry. * * Append a devfs entry to a directory's list of children, checking first to * see if an entry of the same name exists. The directory will be locked. * The value 0 is returned on success, else a negative error code. * On failure, an implicit devfs_put() is performed on %de. */static int _devfs_append_entry(devfs_handle_t dir, devfs_handle_t de, devfs_handle_t * old_de){ int retval; if (old_de) *old_de = NULL; if (!S_ISDIR(dir->mode)) { PRINTK("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name); devfs_put(de); return -ENOTDIR; } write_lock(&dir->u.dir.lock); if (dir->u.dir.no_more_additions) retval = -ENOENT; else { struct devfs_entry *old; old = _devfs_search_dir(dir, de->name, de->namelen); if (old_de) *old_de = old; else devfs_put(old); if (old == NULL) { de->parent = dir; de->prev = dir->u.dir.last; /* Append to the directory's list of children */ if (dir->u.dir.first == NULL) dir->u.dir.first = de; else dir->u.dir.last->next = de; dir->u.dir.last = de; retval = 0; } else retval = -EEXIST; } write_unlock(&dir->u.dir.lock); if (retval) devfs_put(de); return retval;} /* End Function _devfs_append_entry *//** * _devfs_get_root_entry - Get the root devfs entry. * * Returns the root devfs entry on success, else %NULL. * * TODO it must be called asynchronously due to the fact * that devfs is initialized relatively late. Proper way * is to remove module_init from init_devfs_fs and manually * call it early enough during system init */static struct devfs_entry *_devfs_get_root_entry(void){ struct devfs_entry *new; static spinlock_t root_lock = SPIN_LOCK_UNLOCKED; if (root_entry) return root_entry; new = _devfs_alloc_entry(NULL, 0, MODE_DIR); if (new == NULL) return NULL; spin_lock(&root_lock); if (root_entry) { spin_unlock(&root_lock); devfs_put(new); return root_entry; } root_entry = new; spin_unlock(&root_lock); return root_entry;} /* End Function _devfs_get_root_entry *//** * _devfs_descend - Descend down a tree using the next component name. * @dir: The directory to search. * @name: The component name to search for. * @namelen: The length of %name. * @next_pos: The position of the next '/' or '\0' is written here. * * Descend into a directory, searching for a component. This function forms * the core of a tree-walking algorithm. The directory will be locked. * The devfs entry corresponding to the component is returned. If there is * no matching entry, %NULL is returned. * An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_descend(struct devfs_entry *dir, const char *name, int namelen, int *next_pos){ const char *stop, *ptr; struct devfs_entry *entry; if ((namelen >= 3) && (strncmp(name, "../", 3) == 0)) { /* Special-case going to parent directory */ *next_pos = 3; return devfs_get(dir->parent); } stop = name + namelen; /* Search for a possible '/' */ for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr) ; *next_pos = ptr - name; read_lock(&dir->u.dir.lock); entry = _devfs_search_dir(dir, name, *next_pos); read_unlock(&dir->u.dir.lock); return entry;} /* End Function _devfs_descend */static devfs_handle_t _devfs_make_parent_for_leaf(struct devfs_entry *dir, const char *name, int namelen, int *leaf_pos){ int next_pos = 0; if (dir == NULL) dir = _devfs_get_root_entry(); if (dir == NULL) return NULL; devfs_get(dir); /* Search for possible trailing component and ignore it */ for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen) ; *leaf_pos = (name[namelen] == '/') ? (namelen + 1) : 0; for (; namelen > 0; name += next_pos, namelen -= next_pos) { struct devfs_entry *de, *old = NULL; 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, &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 (!S_ISDIR(dir->mode)) { devfs_put(dir); return NULL;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?