diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 132 |
1 files changed, 67 insertions, 65 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 699f371b9f12..590717861c7a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -93,7 +93,7 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) | |||
93 | * RETURNS: | 93 | * RETURNS: |
94 | * Pointer to @sd on success, NULL on failure. | 94 | * Pointer to @sd on success, NULL on failure. |
95 | */ | 95 | */ |
96 | static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | 96 | struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) |
97 | { | 97 | { |
98 | if (unlikely(!sd)) | 98 | if (unlikely(!sd)) |
99 | return NULL; | 99 | return NULL; |
@@ -124,7 +124,7 @@ static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) | |||
124 | * Put an active reference to @sd. This function is noop if @sd | 124 | * Put an active reference to @sd. This function is noop if @sd |
125 | * is NULL. | 125 | * is NULL. |
126 | */ | 126 | */ |
127 | static void sysfs_put_active(struct sysfs_dirent *sd) | 127 | void sysfs_put_active(struct sysfs_dirent *sd) |
128 | { | 128 | { |
129 | struct completion *cmpl; | 129 | struct completion *cmpl; |
130 | int v; | 130 | int v; |
@@ -145,45 +145,6 @@ static void sysfs_put_active(struct sysfs_dirent *sd) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | /** | 147 | /** |
148 | * sysfs_get_active_two - get active references to sysfs_dirent and parent | ||
149 | * @sd: sysfs_dirent of interest | ||
150 | * | ||
151 | * Get active reference to @sd and its parent. Parent's active | ||
152 | * reference is grabbed first. This function is noop if @sd is | ||
153 | * NULL. | ||
154 | * | ||
155 | * RETURNS: | ||
156 | * Pointer to @sd on success, NULL on failure. | ||
157 | */ | ||
158 | struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd) | ||
159 | { | ||
160 | if (sd) { | ||
161 | if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent))) | ||
162 | return NULL; | ||
163 | if (unlikely(!sysfs_get_active(sd))) { | ||
164 | sysfs_put_active(sd->s_parent); | ||
165 | return NULL; | ||
166 | } | ||
167 | } | ||
168 | return sd; | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * sysfs_put_active_two - put active references to sysfs_dirent and parent | ||
173 | * @sd: sysfs_dirent of interest | ||
174 | * | ||
175 | * Put active references to @sd and its parent. This function is | ||
176 | * noop if @sd is NULL. | ||
177 | */ | ||
178 | void sysfs_put_active_two(struct sysfs_dirent *sd) | ||
179 | { | ||
180 | if (sd) { | ||
181 | sysfs_put_active(sd); | ||
182 | sysfs_put_active(sd->s_parent); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * sysfs_deactivate - deactivate sysfs_dirent | 148 | * sysfs_deactivate - deactivate sysfs_dirent |
188 | * @sd: sysfs_dirent to deactivate | 149 | * @sd: sysfs_dirent to deactivate |
189 | * | 150 | * |
@@ -195,6 +156,10 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) | |||
195 | int v; | 156 | int v; |
196 | 157 | ||
197 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); | 158 | BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED)); |
159 | |||
160 | if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) | ||
161 | return; | ||
162 | |||
198 | sd->s_sibling = (void *)&wait; | 163 | sd->s_sibling = (void *)&wait; |
199 | 164 | ||
200 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); | 165 | rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); |
@@ -354,7 +319,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) | |||
354 | 319 | ||
355 | atomic_set(&sd->s_count, 1); | 320 | atomic_set(&sd->s_count, 1); |
356 | atomic_set(&sd->s_active, 0); | 321 | atomic_set(&sd->s_active, 0); |
357 | sysfs_dirent_init_lockdep(sd); | ||
358 | 322 | ||
359 | sd->s_name = name; | 323 | sd->s_name = name; |
360 | sd->s_mode = mode; | 324 | sd->s_mode = mode; |
@@ -681,7 +645,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
681 | } | 645 | } |
682 | 646 | ||
683 | /* attach dentry and inode */ | 647 | /* attach dentry and inode */ |
684 | inode = sysfs_get_inode(sd); | 648 | inode = sysfs_get_inode(dir->i_sb, sd); |
685 | if (!inode) { | 649 | if (!inode) { |
686 | ret = ERR_PTR(-ENOMEM); | 650 | ret = ERR_PTR(-ENOMEM); |
687 | goto out_unlock; | 651 | goto out_unlock; |
@@ -837,11 +801,46 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) | |||
837 | return (sd->s_mode >> 12) & 15; | 801 | return (sd->s_mode >> 12) & 15; |
838 | } | 802 | } |
839 | 803 | ||
804 | static int sysfs_dir_release(struct inode *inode, struct file *filp) | ||
805 | { | ||
806 | sysfs_put(filp->private_data); | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd, | ||
811 | ino_t ino, struct sysfs_dirent *pos) | ||
812 | { | ||
813 | if (pos) { | ||
814 | int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && | ||
815 | pos->s_parent == parent_sd && | ||
816 | ino == pos->s_ino; | ||
817 | sysfs_put(pos); | ||
818 | if (valid) | ||
819 | return pos; | ||
820 | } | ||
821 | pos = NULL; | ||
822 | if ((ino > 1) && (ino < INT_MAX)) { | ||
823 | pos = parent_sd->s_dir.children; | ||
824 | while (pos && (ino > pos->s_ino)) | ||
825 | pos = pos->s_sibling; | ||
826 | } | ||
827 | return pos; | ||
828 | } | ||
829 | |||
830 | static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd, | ||
831 | ino_t ino, struct sysfs_dirent *pos) | ||
832 | { | ||
833 | pos = sysfs_dir_pos(parent_sd, ino, pos); | ||
834 | if (pos) | ||
835 | pos = pos->s_sibling; | ||
836 | return pos; | ||
837 | } | ||
838 | |||
840 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | 839 | static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) |
841 | { | 840 | { |
842 | struct dentry *dentry = filp->f_path.dentry; | 841 | struct dentry *dentry = filp->f_path.dentry; |
843 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; | 842 | struct sysfs_dirent * parent_sd = dentry->d_fsdata; |
844 | struct sysfs_dirent *pos; | 843 | struct sysfs_dirent *pos = filp->private_data; |
845 | ino_t ino; | 844 | ino_t ino; |
846 | 845 | ||
847 | if (filp->f_pos == 0) { | 846 | if (filp->f_pos == 0) { |
@@ -857,29 +856,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) | 856 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0) |
858 | filp->f_pos++; | 857 | filp->f_pos++; |
859 | } | 858 | } |
860 | if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) { | 859 | mutex_lock(&sysfs_mutex); |
861 | mutex_lock(&sysfs_mutex); | 860 | for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos); |
862 | 861 | pos; | |
863 | /* Skip the dentries we have already reported */ | 862 | pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) { |
864 | pos = parent_sd->s_dir.children; | 863 | const char * name; |
865 | while (pos && (filp->f_pos > pos->s_ino)) | 864 | unsigned int type; |
866 | pos = pos->s_sibling; | 865 | int len, ret; |
867 | 866 | ||
868 | for ( ; pos; pos = pos->s_sibling) { | 867 | name = pos->s_name; |
869 | const char * name; | 868 | len = strlen(name); |
870 | int len; | 869 | ino = pos->s_ino; |
871 | 870 | type = dt_type(pos); | |
872 | name = pos->s_name; | 871 | filp->f_pos = ino; |
873 | len = strlen(name); | 872 | filp->private_data = sysfs_get(pos); |
874 | filp->f_pos = ino = pos->s_ino; | ||
875 | 873 | ||
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); | 874 | mutex_unlock(&sysfs_mutex); |
875 | ret = filldir(dirent, name, len, filp->f_pos, ino, type); | ||
876 | mutex_lock(&sysfs_mutex); | ||
877 | if (ret < 0) | ||
878 | break; | ||
879 | } | ||
880 | mutex_unlock(&sysfs_mutex); | ||
881 | if ((filp->f_pos > 1) && !pos) { /* EOF */ | ||
882 | filp->f_pos = INT_MAX; | ||
883 | filp->private_data = NULL; | ||
883 | } | 884 | } |
884 | return 0; | 885 | return 0; |
885 | } | 886 | } |
@@ -888,5 +889,6 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
888 | const struct file_operations sysfs_dir_operations = { | 889 | const struct file_operations sysfs_dir_operations = { |
889 | .read = generic_read_dir, | 890 | .read = generic_read_dir, |
890 | .readdir = sysfs_readdir, | 891 | .readdir = sysfs_readdir, |
892 | .release = sysfs_dir_release, | ||
891 | .llseek = generic_file_llseek, | 893 | .llseek = generic_file_llseek, |
892 | }; | 894 | }; |