lkml.org 
[lkml]   [2004]   [Jul]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 2/5] Use sysfs_dirent tree for ->readdir etc.


    o This patch implements the sysfs_dir_operations file_operations strucutre for
    sysfs directories. It uses the sysfs_dirent based tree for ->readdir() and
    ->lseek() methods instead of simple_dir_operations which use dentry based
    tree.

    o This also has the code for sysfs_get() and sysfs_put() which manipulates
    the reference counting for for sysfs_dirents.


    fs/sysfs/dir.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
    fs/sysfs/mount.c | 2
    fs/sysfs/sysfs.h | 27 ++++++++
    3 files changed, 200 insertions(+), 2 deletions(-)

    diff -puN fs/sysfs/dir.c~sysfs-backing-store-sysfs_readdir fs/sysfs/dir.c
    --- linux-2.6.8-rc2-mm1/fs/sysfs/dir.c~sysfs-backing-store-sysfs_readdir 2004-07-29 15:30:38.000000000 -0500
    +++ linux-2.6.8-rc2-mm1-maneesh/fs/sysfs/dir.c 2004-07-29 15:31:13.000000000 -0500
    @@ -15,7 +15,7 @@ DECLARE_RWSEM(sysfs_rename_sem);
    static int init_dir(struct inode * inode)
    {
    inode->i_op = &simple_dir_inode_operations;
    - inode->i_fop = &simple_dir_operations;
    + inode->i_fop = &sysfs_dir_operations;

    /* directory inodes start off with i_nlink == 2 (for "." entry) */
    inode->i_nlink++;
    @@ -210,6 +210,177 @@ int sysfs_rename_dir(struct kobject * ko
    return error;
    }

    +/* get the name for corresponding element represented by the given sysfs_dirent
    + */
    +const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
    +{
    + struct attribute * attr;
    + struct bin_attribute * bin_attr;
    + struct sysfs_symlink * sl;
    +
    + if (!sd || !sd->s_element)
    + BUG();
    +
    + switch (sd->s_type) {
    + case SYSFS_KOBJECT:
    + case SYSFS_KOBJ_ATTR_GROUP:
    + /* Always have a dentry so use that */
    + return sd->s_dentry->d_name.name;
    +
    + case SYSFS_KOBJ_ATTR:
    + attr = sd->s_element;
    + return attr->name;
    +
    + case SYSFS_KOBJ_BIN_ATTR:
    + bin_attr = sd->s_element;
    + return bin_attr->attr.name;
    +
    + case SYSFS_KOBJ_LINK:
    + sl = sd->s_element;
    + return sl->link_name;
    + }
    + return NULL;
    +}
    +
    +static int sysfs_dir_open(struct inode *inode, struct file *file)
    +{
    + struct dentry * dentry = file->f_dentry;
    + struct sysfs_dirent * parent_sd = dentry->d_fsdata;
    +
    + down(&dentry->d_inode->i_sem);
    + file->private_data = sysfs_new_dirent(parent_sd, NULL, 0);
    + up(&dentry->d_inode->i_sem);
    +
    + return file->private_data ? 0 : -ENOMEM;
    +
    +}
    +
    +static int sysfs_dir_close(struct inode *inode, struct file *file)
    +{
    + struct dentry * dentry = file->f_dentry;
    + struct sysfs_dirent * cursor = file->private_data;
    +
    + down(&dentry->d_inode->i_sem);
    + list_del_init(&cursor->s_sibling);
    + up(&dentry->d_inode->i_sem);
    + sysfs_put(file->private_data);
    +
    + return 0;
    +}
    +
    +/* Relationship between s_mode and the DT_xxx types */
    +static inline unsigned char dt_type(struct sysfs_dirent *sd)
    +{
    + return (sd->s_mode >> 12) & 15;
    +}
    +
    +static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
    +{
    + struct dentry *dentry = filp->f_dentry;
    + struct sysfs_dirent * parent_sd = dentry->d_fsdata;
    + struct sysfs_dirent *cursor = filp->private_data;
    + struct list_head *p, *q = &cursor->s_sibling;
    + ino_t ino;
    + int i = filp->f_pos;
    +
    + switch (i) {
    + case 0:
    + ino = dentry->d_inode->i_ino;
    + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
    + break;
    + filp->f_pos++;
    + i++;
    + /* fallthrough */
    + case 1:
    + ino = parent_ino(dentry);
    + if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
    + break;
    + filp->f_pos++;
    + i++;
    + /* fallthrough */
    + default:
    + if (filp->f_pos == 2) {
    + list_del(q);
    + list_add(q, &parent_sd->s_children);
    + }
    + for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
    + struct sysfs_dirent *next;
    + const char * name;
    + int len;
    +
    + next = list_entry(p, struct sysfs_dirent,
    + s_sibling);
    + if (!next->s_element)
    + continue;
    +
    + name = sysfs_get_name(next);
    + len = strlen(name);
    + if (next->s_dentry)
    + ino = next->s_dentry->d_inode->i_ino;
    + else
    + ino = iunique(sysfs_sb, 2);
    +
    + if (filldir(dirent, name, len, filp->f_pos, ino,
    + dt_type(next)) < 0)
    + return 0;
    +
    + list_del(q);
    + list_add(q, p);
    + p = q;
    + filp->f_pos++;
    + }
    + }
    + return 0;
    +}
    +
    +static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
    +{
    + struct dentry * dentry = file->f_dentry;
    +
    + down(&dentry->d_inode->i_sem);
    + switch (origin) {
    + case 1:
    + offset += file->f_pos;
    + case 0:
    + if (offset >= 0)
    + break;
    + default:
    + up(&file->f_dentry->d_inode->i_sem);
    + return -EINVAL;
    + }
    + if (offset != file->f_pos) {
    + file->f_pos = offset;
    + if (file->f_pos >= 2) {
    + struct sysfs_dirent *sd = dentry->d_fsdata;
    + struct sysfs_dirent *cursor = file->private_data;
    + struct list_head *p;
    + loff_t n = file->f_pos - 2;
    +
    + list_del(&cursor->s_sibling);
    + p = sd->s_children.next;
    + while (n && p != &sd->s_children) {
    + struct sysfs_dirent *next;
    + next = list_entry(p, struct sysfs_dirent,
    + s_sibling);
    + if (next->s_element)
    + n--;
    + p = p->next;
    + }
    + list_add_tail(&cursor->s_sibling, p);
    + }
    + }
    + up(&dentry->d_inode->i_sem);
    + return offset;
    +}
    +
    +struct file_operations sysfs_dir_operations = {
    + .open = sysfs_dir_open,
    + .release = sysfs_dir_close,
    + .llseek = sysfs_dir_lseek,
    + .read = generic_read_dir,
    + .readdir = sysfs_readdir,
    +};
    +
    EXPORT_SYMBOL(sysfs_create_dir);
    EXPORT_SYMBOL(sysfs_remove_dir);
    EXPORT_SYMBOL(sysfs_rename_dir);
    diff -puN fs/sysfs/sysfs.h~sysfs-backing-store-sysfs_readdir fs/sysfs/sysfs.h
    --- linux-2.6.8-rc2-mm1/fs/sysfs/sysfs.h~sysfs-backing-store-sysfs_readdir 2004-07-29 15:30:38.000000000 -0500
    +++ linux-2.6.8-rc2-mm1-maneesh/fs/sysfs/sysfs.h 2004-07-29 15:31:07.000000000 -0500
    @@ -4,6 +4,8 @@ extern struct vfsmount * sysfs_mount;
    extern struct inode * sysfs_new_inode(mode_t mode);
    extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));

    +
    +extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
    extern struct dentry * sysfs_get_dentry(struct dentry *, const char *);
    extern void sysfs_drop_dentry(struct sysfs_dirent *, struct dentry *);

    @@ -16,6 +18,8 @@ extern void sysfs_remove_subdir(struct d
    extern int sysfs_readlink(struct dentry *, char __user *, int );
    extern int sysfs_follow_link(struct dentry *, struct nameidata *);
    extern struct rw_semaphore sysfs_rename_sem;
    +extern struct super_block * sysfs_sb;
    +extern struct file_operations sysfs_dir_operations;

    struct sysfs_symlink {
    char * link_name;
    @@ -58,3 +62,26 @@ struct sysfs_dirent * sysfs_new_dirent(s

    return sd;
    }
    +
    +static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
    +{
    + if (sd) {
    + WARN_ON(!atomic_read(&sd->s_count));
    + atomic_inc(&sd->s_count);
    + }
    + return sd;
    +}
    +
    +static inline void sysfs_put(struct sysfs_dirent * sd)
    +{
    + if (atomic_dec_and_test(&sd->s_count)) {
    + if (sd->s_type & SYSFS_KOBJ_LINK) {
    + struct sysfs_symlink * sl = sd->s_element;
    + kfree(sl->link_name);
    + kobject_put(sl->target_kobj);
    + kfree(sl);
    + }
    + kfree(sd);
    + }
    +}
    +
    diff -puN fs/sysfs/mount.c~sysfs-backing-store-sysfs_readdir fs/sysfs/mount.c
    --- linux-2.6.8-rc2-mm1/fs/sysfs/mount.c~sysfs-backing-store-sysfs_readdir 2004-07-29 15:30:38.000000000 -0500
    +++ linux-2.6.8-rc2-mm1-maneesh/fs/sysfs/mount.c 2004-07-29 15:31:07.000000000 -0500
    @@ -43,7 +43,7 @@ static int sysfs_fill_super(struct super
    inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
    if (inode) {
    inode->i_op = &simple_dir_inode_operations;
    - inode->i_fop = &simple_dir_operations;
    + inode->i_fop = &sysfs_dir_operations;
    /* directory inodes start off with i_nlink == 2 (for "." entry) */
    inode->i_nlink++;
    } else {
    _
    --
    Maneesh Soni
    Linux Technology Center,
    IBM Austin
    email: maneesh@in.ibm.com
    Phone: 1-512-838-1896 Fax:
    T/L : 6781896
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:04    [W:0.034 / U:63.076 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site