aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/inode.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-06-13 15:27:24 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-11 19:09:09 -0400
commitfb6896da37f19be4b75154c14d1cd79231255b17 (patch)
treed1480206694a0642067dc7dc5b40bd63b038cac0 /fs/sysfs/inode.c
parent3007e997de91ec59af39a3f9c91595b31ae6e08b (diff)
sysfs: restructure add/remove paths and fix inode update
The original add/remove code had the following problems. * parent's timestamps are updated on dentry instantiation. this is incorrect with reclaimable files. * updating parent's timestamps isn't synchronized. * parent nlink update assumes the inode is accessible which won't be true once directory dentries are made reclaimable. This patch restructures add/remove paths to resolve the above problems. Add/removal are done in the following steps. 1. sysfs_addrm_start() : acquire locks including sysfs_mutex and other resources. 2-a. sysfs_add_one() : add new sd. linking the new sd into the children list is caller's responsibility. 2-b. sysfs_remove_one() : remove a sd. unlinking the sd from the children list is caller's responsibility. 3. sysfs_addrm_finish() : release all resources and clean up. Steps 2-a and/or 2-b can be repeated multiple times. Parent's inode is looked up during sysfs_addrm_start(). If available (always at the moment), it's pinned and nlink is updated as sd's are added and removed. Timestamps are updated during finish if any sd has been added or removed. If parent's inode is not available during start, sysfs_mutex ensures that parent inode is not created till add/remove is complete. All the complexity is contained inside the helper functions. Especially, dentry/inode handling is properly hidden from the rest of sysfs which now mostly operate on sysfs_dirents. As an added bonus, codes which use these helpers to add and remove sysfs_dirents are now more structured and simpler. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/sysfs/inode.c')
-rw-r--r--fs/sysfs/inode.c46
1 files changed, 8 insertions, 38 deletions
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index d439c0b4bfce..f95966847a81 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -191,15 +191,9 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
191{ 191{
192 BUG_ON(!dentry || dentry->d_inode); 192 BUG_ON(!dentry || dentry->d_inode);
193 193
194 if (inode->i_state & I_NEW) { 194 if (inode->i_state & I_NEW)
195 unlock_new_inode(inode); 195 unlock_new_inode(inode);
196 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 }
201 }
202
203 d_instantiate(dentry, inode); 197 d_instantiate(dentry, inode);
204} 198}
205 199
@@ -220,7 +214,6 @@ void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
220void sysfs_drop_dentry(struct sysfs_dirent *sd) 214void sysfs_drop_dentry(struct sysfs_dirent *sd)
221{ 215{
222 struct dentry *dentry = NULL; 216 struct dentry *dentry = NULL;
223 struct timespec curtime;
224 struct inode *inode; 217 struct inode *inode;
225 218
226 /* We're not holding a reference to ->s_dentry dentry but the 219 /* We're not holding a reference to ->s_dentry dentry but the
@@ -246,13 +239,11 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)
246 dput(dentry); 239 dput(dentry);
247 240
248 /* adjust nlink and update timestamp */ 241 /* adjust nlink and update timestamp */
249 curtime = CURRENT_TIME;
250
251 inode = ilookup(sysfs_sb, sd->s_ino); 242 inode = ilookup(sysfs_sb, sd->s_ino);
252 if (inode) { 243 if (inode) {
253 mutex_lock(&inode->i_mutex); 244 mutex_lock(&inode->i_mutex);
254 245
255 inode->i_ctime = curtime; 246 inode->i_ctime = CURRENT_TIME;
256 drop_nlink(inode); 247 drop_nlink(inode);
257 if (sysfs_type(sd) == SYSFS_DIR) 248 if (sysfs_type(sd) == SYSFS_DIR)
258 drop_nlink(inode); 249 drop_nlink(inode);
@@ -260,30 +251,17 @@ void sysfs_drop_dentry(struct sysfs_dirent *sd)
260 mutex_unlock(&inode->i_mutex); 251 mutex_unlock(&inode->i_mutex);
261 iput(inode); 252 iput(inode);
262 } 253 }
263
264 /* adjust nlink and udpate timestamp of the parent */
265 inode = ilookup(sysfs_sb, sd->s_parent->s_ino);
266 if (inode) {
267 mutex_lock(&inode->i_mutex);
268
269 inode->i_ctime = inode->i_mtime = curtime;
270 if (sysfs_type(sd) == SYSFS_DIR)
271 drop_nlink(inode);
272
273 mutex_unlock(&inode->i_mutex);
274 iput(inode);
275 }
276} 254}
277 255
278int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) 256int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
279{ 257{
258 struct sysfs_addrm_cxt acxt;
280 struct sysfs_dirent **pos, *sd; 259 struct sysfs_dirent **pos, *sd;
281 int found = 0;
282 260
283 if (!dir_sd) 261 if (!dir_sd)
284 return -ENOENT; 262 return -ENOENT;
285 263
286 mutex_lock(&sysfs_mutex); 264 sysfs_addrm_start(&acxt, dir_sd);
287 265
288 for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) { 266 for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
289 sd = *pos; 267 sd = *pos;
@@ -291,22 +269,14 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
291 if (!sysfs_type(sd)) 269 if (!sysfs_type(sd))
292 continue; 270 continue;
293 if (!strcmp(sd->s_name, name)) { 271 if (!strcmp(sd->s_name, name)) {
294 sd->s_flags |= SYSFS_FLAG_REMOVED;
295 *pos = sd->s_sibling; 272 *pos = sd->s_sibling;
296 sd->s_sibling = NULL; 273 sd->s_sibling = NULL;
297 found = 1; 274 sysfs_remove_one(&acxt, sd);
298 break; 275 break;
299 } 276 }
300 } 277 }
301 278
302 mutex_unlock(&sysfs_mutex); 279 if (sysfs_addrm_finish(&acxt))
303 280 return 0;
304 if (!found) 281 return -ENOENT;
305 return -ENOENT;
306
307 sysfs_drop_dentry(sd);
308 sysfs_deactivate(sd);
309 sysfs_put(sd);
310
311 return 0;
312} 282}