aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/sysfs/dir.c82
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
840static int sysfs_dir_release(struct inode *inode, struct file *filp)
841{
842 sysfs_put(filp->private_data);
843 return 0;
844}
845
846static 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
866static 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
840static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 875static 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)
888const struct file_operations sysfs_dir_operations = { 925const 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};