aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c132
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 */
96static struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) 96struct 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 */
127static void sysfs_put_active(struct sysfs_dirent *sd) 127void 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 */
158struct 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 */
178void 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
804static int sysfs_dir_release(struct inode *inode, struct file *filp)
805{
806 sysfs_put(filp->private_data);
807 return 0;
808}
809
810static 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
830static 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
840static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir) 839static 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)
888const struct file_operations sysfs_dir_operations = { 889const 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};