diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/sysfs/dir.c | 82 |
1 files changed, 60 insertions, 22 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 699f371b9f12..5c4703d751b5 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -837,11 +837,46 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) | |||
837 | return (sd->s_mode >> 12) & 15; | 837 | return (sd->s_mode >> 12) & 15; |
838 | } | 838 | } |
839 | 839 | ||
840 | static int sysfs_dir_release(struct inode *inode, struct file *filp) | ||
841 | { | ||
842 | sysfs_put(filp->private_data); | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd, | ||
847 | ino_t ino, struct sysfs_dirent *pos) | ||
848 | { | ||
849 | if (pos) { | ||
850 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | ||
851 | pos->s_parent == parent_sd && | ||
852 | ino == pos->s_ino; | ||
853 | sysfs_put(pos); | ||
854 | if (valid) | ||
855 | return pos; | ||
856 | } | ||
857 | pos = NULL; | ||
858 | if ((ino > 1) && (ino < INT_MAX)) { | ||
859 | pos = parent_sd->s_dir.children; | ||
860 | while (pos && (ino > pos->s_ino)) | ||
861 | pos = pos->s_sibling; | ||
862 | } | ||
863 | return pos; | ||
864 | } | ||
865 | |||
866 | static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd, | ||
867 | ino_t ino, struct sysfs_dirent *pos) | ||
868 | { | ||
869 | pos = sysfs_dir_pos(parent_sd, ino, pos); | ||
870 | if (pos) | ||
871 | pos = pos->s_sibling; | ||
872 | return pos; | ||
873 | } | ||
874 | |||
840 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | 875 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) |
841 | { | 876 | { |
842 | struct dentry *dentry = filp->f_path.dentry; | 877 | struct dentry *dentry = filp->f_path.dentry; |
843 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 878 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
844 | struct sysfs_dirent *pos; | 879 | struct sysfs_dirent *pos = filp->private_data; |
845 | ino_t ino; | 880 | ino_t ino; |
846 | 881 | ||
847 | if (filp->f_pos == 0) { | 882 | if (filp->f_pos == 0) { |
@@ -857,29 +892,31 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
857 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) | 892 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
858 | filp->f_pos++; | 893 | filp->f_pos++; |
859 | } | 894 | } |
860 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { | 895 | mutex_lock(&sysfs_mutex); |
861 | mutex_lock(&sysfs_mutex); | 896 | for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos); |
862 | 897 | pos; | |
863 | /* Skip the dentries we have already reported */ | 898 | pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) { |
864 | pos = parent_sd->s_dir.children; | 899 | const char * name; |
865 | while (pos && (filp->f_pos > pos->s_ino)) | 900 | unsigned int type; |
866 | pos = pos->s_sibling; | 901 | int len, ret; |
867 | 902 | ||
868 | for ( ; pos; pos = pos->s_sibling) { | 903 | name = pos->s_name; |
869 | const char * name; | 904 | len = strlen(name); |
870 | int len; | 905 | ino = pos->s_ino; |
871 | 906 | type = dt_type(pos); | |
872 | name = pos->s_name; | 907 | filp->f_pos = ino; |
873 | len = strlen(name); | 908 | filp->private_data = sysfs_get(pos); |
874 | filp->f_pos = ino = pos->s_ino; | ||
875 | 909 | ||
876 | if (filldir(dirent, name, len, filp->f_pos, ino, | ||
877 | dt_type(pos)) < 0) | ||
878 | break; | ||
879 | } | ||
880 | if (!pos) | ||
881 | filp->f_pos = INT_MAX; | ||
882 | mutex_unlock(&sysfs_mutex); | 910 | mutex_unlock(&sysfs_mutex); |
911 | ret = filldir(dirent, name, len, filp->f_pos, ino, type); | ||
912 | mutex_lock(&sysfs_mutex); | ||
913 | if (ret < 0) | ||
914 | break; | ||
915 | } | ||
916 | mutex_unlock(&sysfs_mutex); | ||
917 | if ((filp->f_pos > 1) && !pos) { /* EOF */ | ||
918 | filp->f_pos = INT_MAX; | ||
919 | filp->private_data = NULL; | ||
883 | } | 920 | } |
884 | return 0; | 921 | return 0; |
885 | } | 922 | } |
@@ -888,5 +925,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
888 | const struct file_operations sysfs_dir_operations = { | 925 | const struct file_operations sysfs_dir_operations = { |
889 | .read = generic_read_dir, | 926 | .read = generic_read_dir, |
890 | .readdir = sysfs_readdir, | 927 | .readdir = sysfs_readdir, |
928 | .release = sysfs_dir_release, | ||
891 | .llseek = generic_file_llseek, | 929 | .llseek = generic_file_llseek, |
892 | }; | 930 | }; |