diff options
Diffstat (limited to 'fs/sysfs/dir.c')
| -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 | }; |
