base.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,003 行 · 第 1/5 页
C
2,003 行
* devfs_mk_symlink Create a symbolic link in the devfs namespace. * @from: The name of the entry. * @to: Name of the destination * * Returns 0 on success, else a negative error code is returned. */int devfs_mk_symlink(const char *from, const char *to){ devfs_handle_t de; int err; err = devfs_do_symlink(NULL, from, to, &de); if (!err) { de->vfs = TRUE; devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); } return err;}/** * devfs_mk_dir - Create a directory in the devfs namespace. * new name is relative to the root of the devfs. * @fmt: The name of 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. * On failure %NULL is returned. */int devfs_mk_dir(const char *fmt, ...){ struct devfs_entry *dir = NULL, *de = NULL, *old; char buf[64]; va_list args; int error, n; va_start(args, fmt); n = vsnprintf(buf, 64, fmt, args); if (n >= 64 || !buf[0]) { printk(KERN_WARNING "%s: invalid argument.", __FUNCTION__); return -EINVAL; } de = _devfs_prepare_leaf(&dir, buf, MODE_DIR); if (!de) { PRINTK("(%s): could not prepare leaf\n", buf); return -EINVAL; } error = _devfs_append_entry(dir, de, &old); if (error == -EEXIST && S_ISDIR(old->mode)) { /* * devfs_mk_dir() of an already-existing directory will * return success. */ error = 0; goto out_put; } else if (error) { PRINTK("(%s): could not append to dir: %p \"%s\"\n", buf, dir, dir->name); devfs_put(old); goto out_put; } devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED); out_put: devfs_put(dir); return error;}void devfs_remove(const char *fmt, ...){ char buf[64]; va_list args; int n; va_start(args, fmt); n = vsnprintf(buf, sizeof(buf), fmt, args); if (n < sizeof(buf) && buf[0]) { devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); if (!de) { printk(KERN_ERR "%s: %s not found, cannot remove\n", __FUNCTION__, buf); dump_stack(); return; } write_lock(&de->parent->u.dir.lock); _devfs_unregister(de->parent, de); devfs_put(de); devfs_put(de); }}/** * devfs_generate_path - Generate a pathname for an entry, relative to the devfs root. * @de: The devfs entry. * @path: The buffer to write the pathname to. The pathname and '\0' * terminator will be written at the end of the buffer. * @buflen: The length of the buffer. * * Returns the offset in the buffer where the pathname starts on success, * else a negative error code. */static int devfs_generate_path(devfs_handle_t de, char *path, int buflen){ int pos;#define NAMEOF(de) ( (de)->mode ? (de)->name : (de)->u.name ) if (de == NULL) return -EINVAL; VERIFY_ENTRY(de); if (de->namelen >= buflen) return -ENAMETOOLONG; /* Must be first */ path[buflen - 1] = '\0'; if (de->parent == NULL) return buflen - 1; /* Don't prepend root */ pos = buflen - de->namelen - 1; memcpy(path + pos, NAMEOF(de), de->namelen); for (de = de->parent; de->parent != NULL; de = de->parent) { if (pos - de->namelen - 1 < 0) return -ENAMETOOLONG; path[--pos] = '/'; pos -= de->namelen; memcpy(path + pos, NAMEOF(de), de->namelen); } return pos;} /* End Function devfs_generate_path *//** * devfs_setup - Process kernel boot options. * @str: The boot options after the "devfs=". */static int __init devfs_setup(char *str){ static struct { char *name; unsigned int mask; unsigned int *opt; } devfs_options_tab[] __initdata = {#ifdef CONFIG_DEVFS_DEBUG { "dall", DEBUG_ALL, &devfs_debug_init}, { "dmod", DEBUG_MODULE_LOAD, &devfs_debug_init}, { "dreg", DEBUG_REGISTER, &devfs_debug_init}, { "dunreg", DEBUG_UNREGISTER, &devfs_debug_init}, { "dfree", DEBUG_FREE, &devfs_debug_init}, { "diget", DEBUG_I_GET, &devfs_debug_init}, { "dchange", DEBUG_SET_FLAGS, &devfs_debug_init}, { "dsread", DEBUG_S_READ, &devfs_debug_init}, { "dichange", DEBUG_I_CHANGE, &devfs_debug_init}, { "dimknod", DEBUG_I_MKNOD, &devfs_debug_init}, { "dilookup", DEBUG_I_LOOKUP, &devfs_debug_init}, { "diunlink", DEBUG_I_UNLINK, &devfs_debug_init},#endif /* CONFIG_DEVFS_DEBUG */ { "mount", OPTION_MOUNT, &boot_options}, { NULL, 0, NULL} }; while ((*str != '\0') && !isspace(*str)) { int i, found = 0, invert = 0; if (strncmp(str, "no", 2) == 0) { invert = 1; str += 2; } for (i = 0; devfs_options_tab[i].name != NULL; i++) { int len = strlen(devfs_options_tab[i].name); if (strncmp(str, devfs_options_tab[i].name, len) == 0) { if (invert) *devfs_options_tab[i].opt &= ~devfs_options_tab[i].mask; else *devfs_options_tab[i].opt |= devfs_options_tab[i].mask; str += len; found = 1; break; } } if (!found) return 0; /* No match */ if (*str != ',') return 0; /* No more options */ ++str; } return 1;} /* End Function devfs_setup */__setup("devfs=", devfs_setup);EXPORT_SYMBOL(devfs_mk_symlink);EXPORT_SYMBOL(devfs_mk_dir);EXPORT_SYMBOL(devfs_remove);/** * try_modload - Notify devfsd of an inode lookup by a non-devfsd process. * @parent: The parent devfs entry. * @fs_info: The filesystem info. * @name: The device name. * @namelen: The number of characters in @name. * @buf: A working area that will be used. This must not go out of scope * until devfsd is idle again. * * Returns 0 on success (event was queued), else a negative error code. */static int try_modload(struct devfs_entry *parent, struct fs_info *fs_info, const char *name, unsigned namelen, struct devfs_entry *buf){ if (!(fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP))) return -ENOENT; if (is_devfsd_or_child(fs_info)) return -ENOENT; memset(buf, 0, sizeof *buf); atomic_set(&buf->refcount, 1); buf->parent = parent; buf->namelen = namelen; buf->u.name = name; WRITE_ENTRY_MAGIC(buf, MAGIC_VALUE); if (!devfsd_notify_de(buf, DEVFSD_NOTIFY_LOOKUP, 0, current->euid, current->egid, fs_info)) return -ENOENT; /* Possible success: event has been queued */ return 0;} /* End Function try_modload *//* Superblock operations follow */static struct inode_operations devfs_iops;static struct inode_operations devfs_dir_iops;static struct file_operations devfs_fops;static struct file_operations devfs_dir_fops;static struct inode_operations devfs_symlink_iops;static int devfs_notify_change(struct dentry *dentry, struct iattr *iattr){ int retval; struct devfs_entry *de; struct inode *inode = dentry->d_inode; struct fs_info *fs_info = inode->i_sb->s_fs_info; de = get_devfs_entry_from_vfs_inode(inode); if (de == NULL) return -ENODEV; retval = inode_change_ok(inode, iattr); if (retval != 0) return retval; retval = inode_setattr(inode, iattr); if (retval != 0) return retval; DPRINTK(DEBUG_I_CHANGE, "(%d): VFS inode: %p devfs_entry: %p\n", (int)inode->i_ino, inode, de); DPRINTK(DEBUG_I_CHANGE, "(): mode: 0%o uid: %d gid: %d\n", (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); /* Inode is not on hash chains, thus must save permissions here rather than in a write_inode() method */ de->mode = inode->i_mode; de->inode.uid = inode->i_uid; de->inode.gid = inode->i_gid; de->inode.atime = inode->i_atime; de->inode.mtime = inode->i_mtime; de->inode.ctime = inode->i_ctime; if ((iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) && !is_devfsd_or_child(fs_info)) devfsd_notify_de(de, DEVFSD_NOTIFY_CHANGE, inode->i_mode, inode->i_uid, inode->i_gid, fs_info); return 0;} /* End Function devfs_notify_change */static struct super_operations devfs_sops = { .drop_inode = generic_delete_inode, .statfs = simple_statfs,};/** * _devfs_get_vfs_inode - Get a VFS inode. * @sb: The super block. * @de: The devfs inode. * @dentry: The dentry to register with the devfs inode. * * Returns the inode on success, else %NULL. An implicit devfs_get() is * performed if the inode is created. */static struct inode *_devfs_get_vfs_inode(struct super_block *sb, struct devfs_entry *de, struct dentry *dentry){ struct inode *inode; if (de->prev == de) return NULL; /* Quick check to see if unhooked */ if ((inode = new_inode(sb)) == NULL) { PRINTK("(%s): new_inode() failed, de: %p\n", de->name, de); return NULL; } if (de->parent) { read_lock(&de->parent->u.dir.lock); if (de->prev != de) de->inode.dentry = dentry; /* Not unhooked */ read_unlock(&de->parent->u.dir.lock); } else de->inode.dentry = dentry; /* Root: no locking needed */ if (de->inode.dentry != dentry) { /* Must have been unhooked */ iput(inode); return NULL; } /* FIXME where is devfs_put? */ inode->u.generic_ip = devfs_get(de); inode->i_ino = de->inode.ino; DPRINTK(DEBUG_I_GET, "(%d): VFS inode: %p devfs_entry: %p\n", (int)inode->i_ino, inode, de); inode->i_blocks = 0; inode->i_blksize = FAKE_BLOCK_SIZE; inode->i_op = &devfs_iops; inode->i_mode = de->mode; if (S_ISDIR(de->mode)) { inode->i_op = &devfs_dir_iops; inode->i_fop = &devfs_dir_fops; } else if (S_ISLNK(de->mode)) { inode->i_op = &devfs_symlink_iops; inode->i_size = de->u.symlink.length; } else if (S_ISCHR(de->mode) || S_ISBLK(de->mode)) { init_special_inode(inode, de->mode, de->u.dev); } else if (S_ISFIFO(de->mode) || S_ISSOCK(de->mode)) { init_special_inode(inode, de->mode, 0); } else { PRINTK("(%s): unknown mode %o de: %p\n", de->name, de->mode, de); iput(inode); devfs_put(de); return NULL; } inode->i_uid = de->inode.uid; inode->i_gid = de->inode.gid; inode->i_atime = de->inode.atime; inode->i_mtime = de->inode.mtime; inode->i_ctime = de->inode.ctime; DPRINTK(DEBUG_I_GET, "(): mode: 0%o uid: %d gid: %d\n", (int)inode->i_mode, (int)inode->i_uid, (int)inode->i_gid); return inode;} /* End Function _devfs_get_vfs_inode *//* File operations for device entries follow */static int devfs_readdir(struct file *file, void *dirent, filldir_t filldir){ int err, count; int stored = 0; struct fs_info *fs_info; struct devfs_entry *parent, *de, *next = NULL; struct inode *inode = file->f_dentry->d_inode; fs_info = inode->i_sb->s_fs_info; parent = get_devfs_entry_from_vfs_inode(file->f_dentry->d_inode); if ((long)file->f_pos < 0) return -EINVAL; DPRINTK(DEBUG_F_READDIR, "(%s): fs_info: %p pos: %ld\n", parent->name, fs_info, (long)file->f_pos); switch ((long)file->f_pos) { case 0: err = (*filldir) (dirent, "..", 2, file->f_pos, parent_ino(file->f_dentry), DT_DIR); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; ++stored; /* Fall through */ case 1: err = (*filldir) (dirent, ".", 1, file->f_pos, inode->i_ino, DT_DIR); if (err == -EINVAL) break; if (err < 0) return err; file->f_pos++; ++stored; /* Fall through */ default: /* Skip entries */ count = file->f_pos - 2; read_lock(&parent->u.dir.lock); for (de = parent->u.dir.first; de && (count > 0); de = de->next)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?