aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 14:45:17 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:07 -0400
commit8312a8d7c1d19d31027bd4ca127ce671962c23d4 (patch)
treeee28a44611ac2192b265f5f85a74f7da98d2fdef
parentfc9f54b9982e14e6dbe023425c87ffbfd6992c45 (diff)
sysfs: use iget_locked() instead of new_inode()
After dentry is reclaimed, sysfs always used to allocate new dentry and inode if the file is accessed again. This causes problem with operations which only pin the inode. For example, if inotify watch is added to a sysfs file and the dentry for the file is reclaimed, the next update event creates new dentry and new inode making the inotify watch miss all the events from there on. This patch fixes it by using iget_locked() instead of new_inode(). sysfs_new_inode() is renamed to sysfs_get_inode() and inode is initialized iff the inode is newly allocated. sysfs_instantiate() is responsible for unlocking new inodes. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/sysfs/dir.c37
-rw-r--r--fs/sysfs/inode.c24
-rw-r--r--fs/sysfs/sysfs.h2
3 files changed, 37 insertions, 26 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index bbf3525fd222..06dff2c30c9b 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -219,14 +219,16 @@ static int create_dir(struct kobject *kobj, struct dentry *parent,
219 goto out_drop; 219 goto out_drop;
220 sd->s_elem.dir.kobj = kobj; 220 sd->s_elem.dir.kobj = kobj;
221 221
222 inode = sysfs_new_inode(sd); 222 inode = sysfs_get_inode(sd);
223 if (!inode) 223 if (!inode)
224 goto out_sput; 224 goto out_sput;
225 225
226 inode->i_op = &sysfs_dir_inode_operations; 226 if (inode->i_state & I_NEW) {
227 inode->i_fop = &sysfs_dir_operations; 227 inode->i_op = &sysfs_dir_inode_operations;
228 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 228 inode->i_fop = &sysfs_dir_operations;
229 inc_nlink(inode); 229 /* directory inodes start off with i_nlink == 2 (for ".") */
230 inc_nlink(inode);
231 }
230 232
231 /* link in */ 233 /* link in */
232 error = -EEXIST; 234 error = -EEXIST;
@@ -310,20 +312,23 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
310 return NULL; 312 return NULL;
311 313
312 /* attach dentry and inode */ 314 /* attach dentry and inode */
313 inode = sysfs_new_inode(sd); 315 inode = sysfs_get_inode(sd);
314 if (!inode) 316 if (!inode)
315 return ERR_PTR(-ENOMEM); 317 return ERR_PTR(-ENOMEM);
316 318
317 /* initialize inode according to type */ 319 if (inode->i_state & I_NEW) {
318 if (sd->s_type & SYSFS_KOBJ_ATTR) { 320 /* initialize inode according to type */
319 inode->i_size = PAGE_SIZE; 321 if (sd->s_type & SYSFS_KOBJ_ATTR) {
320 inode->i_fop = &sysfs_file_operations; 322 inode->i_size = PAGE_SIZE;
321 } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) { 323 inode->i_fop = &sysfs_file_operations;
322 struct bin_attribute *bin_attr = sd->s_elem.bin_attr.bin_attr; 324 } else if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) {
323 inode->i_size = bin_attr->size; 325 struct bin_attribute *bin_attr =
324 inode->i_fop = &bin_fops; 326 sd->s_elem.bin_attr.bin_attr;
325 } else if (sd->s_type & SYSFS_KOBJ_LINK) 327 inode->i_size = bin_attr->size;
326 inode->i_op = &sysfs_symlink_inode_operations; 328 inode->i_fop = &bin_fops;
329 } else if (sd->s_type & SYSFS_KOBJ_LINK)
330 inode->i_op = &sysfs_symlink_inode_operations;
331 }
327 332
328 sysfs_instantiate(dentry, inode); 333 sysfs_instantiate(dentry, inode);
329 sysfs_attach_dentry(sd, dentry); 334 sysfs_attach_dentry(sd, dentry);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 26d8503c8997..3eab9c46a71b 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -153,10 +153,12 @@ void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
153} 153}
154 154
155/** 155/**
156 * sysfs_new_inode - allocate new inode for sysfs_dirent 156 * sysfs_get_inode - get inode for sysfs_dirent
157 * @sd: sysfs_dirent to allocate inode for 157 * @sd: sysfs_dirent to allocate inode for
158 * 158 *
159 * Allocate inode for @sd and initialize basics. 159 * Get inode for @sd. If such inode doesn't exist, a new inode
160 * is allocated and basics are initialized. New inode is
161 * returned locked.
160 * 162 *
161 * LOCKING: 163 * LOCKING:
162 * Kernel thread context (may sleep). 164 * Kernel thread context (may sleep).
@@ -164,12 +166,12 @@ void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
164 * RETURNS: 166 * RETURNS:
165 * Pointer to allocated inode on success, NULL on failure. 167 * Pointer to allocated inode on success, NULL on failure.
166 */ 168 */
167struct inode * sysfs_new_inode(struct sysfs_dirent *sd) 169struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
168{ 170{
169 struct inode *inode; 171 struct inode *inode;
170 172
171 inode = new_inode(sysfs_sb); 173 inode = iget_locked(sysfs_sb, sd->s_ino);
172 if (inode) 174 if (inode && (inode->i_state & I_NEW))
173 sysfs_init_inode(sd, inode); 175 sysfs_init_inode(sd, inode);
174 176
175 return inode; 177 return inode;
@@ -180,7 +182,7 @@ struct inode * sysfs_new_inode(struct sysfs_dirent *sd)
180 * @dentry: dentry to be instantiated 182 * @dentry: dentry to be instantiated
181 * @inode: inode associated with @sd 183 * @inode: inode associated with @sd
182 * 184 *
183 * Instantiate @dentry with @inode. 185 * Unlock @inode if locked and instantiate @dentry with @inode.
184 * 186 *
185 * LOCKING: 187 * LOCKING:
186 * None. 188 * None.
@@ -189,9 +191,13 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
189{ 191{
190 BUG_ON(!dentry || dentry->d_inode); 192 BUG_ON(!dentry || dentry->d_inode);
191 193
192 if (dentry->d_parent && dentry->d_parent->d_inode) { 194 if (inode->i_state & I_NEW) {
193 struct inode *p_inode = dentry->d_parent->d_inode; 195 unlock_new_inode(inode);
194 p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; 196
197 if (dentry->d_parent && dentry->d_parent->d_inode) {
198 struct inode *p_inode = dentry->d_parent->d_inode;
199 p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
200 }
195 } 201 }
196 202
197 d_instantiate(dentry, inode); 203 d_instantiate(dentry, inode);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 143fdbe56c14..627bf3940dfa 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -58,7 +58,7 @@ extern struct kmem_cache *sysfs_dir_cachep;
58 58
59extern void sysfs_delete_inode(struct inode *inode); 59extern void sysfs_delete_inode(struct inode *inode);
60extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode); 60extern void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode);
61extern struct inode * sysfs_new_inode(struct sysfs_dirent *sd); 61extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
62extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode); 62extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
63 63
64extern void release_sysfs_dirent(struct sysfs_dirent * sd); 64extern void release_sysfs_dirent(struct sysfs_dirent * sd);