diff options
author | jh <jh@FreeBSD.org> | 2010-09-27 17:47:09 +0000 |
---|---|---|
committer | jh <jh@FreeBSD.org> | 2010-09-27 17:47:09 +0000 |
commit | b6e78e30f23dbed7263727af46739f94ef85fd86 (patch) | |
tree | aac5e5193fff6dc7e4ad901a2ea6b4bab1a82a25 /sys/fs/devfs/devfs_devs.c | |
parent | 0901947e8d8500bb8120febd32587bc1eeabca98 (diff) | |
download | FreeBSD-src-b6e78e30f23dbed7263727af46739f94ef85fd86.zip FreeBSD-src-b6e78e30f23dbed7263727af46739f94ef85fd86.tar.gz |
Add reference counting for devfs paths containing user created symbolic
links. The reference counting is needed to be able to determine if a
specific devfs path exists. For true device file paths we can traverse
the cdevp_list but a separate directory list is needed for user created
symbolic links.
Add a new directory entry flag DE_USER to mark entries which should
unreference their parent directory on deletion.
A new function to traverse cdevp_list and the directory list will be
introduced in a separate commit.
Idea from: kib
Reviewed by: kib
Diffstat (limited to 'sys/fs/devfs/devfs_devs.c')
-rw-r--r-- | sys/fs/devfs/devfs_devs.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c index 60c296b..99b33ec 100644 --- a/sys/fs/devfs/devfs_devs.c +++ b/sys/fs/devfs/devfs_devs.c @@ -338,6 +338,10 @@ devfs_delete(struct devfs_mount *dm, struct devfs_dirent *de, int flags) dd = devfs_parent_dirent(de); if (dd != NULL) DEVFS_DE_HOLD(dd); + if (de->de_flags & DE_USER) { + KASSERT(dd != NULL, ("devfs_delete: NULL dd")); + devfs_dir_unref_de(dm, dd); + } } else dd = NULL; @@ -396,10 +400,17 @@ devfs_purge(struct devfs_mount *dm, struct devfs_dirent *dd) DEVFS_DE_HOLD(dd); for (;;) { - de = TAILQ_FIRST(&dd->de_dlist); + /* + * Use TAILQ_LAST() to remove "." and ".." last. + * We might need ".." to resolve a path in + * devfs_dir_unref_de(). + */ + de = TAILQ_LAST(&dd->de_dlist, devfs_dlist_head); if (de == NULL) break; TAILQ_REMOVE(&dd->de_dlist, de, de_list); + if (de->de_flags & DE_USER) + devfs_dir_unref_de(dm, dd); if (de->de_flags & (DE_DOT | DE_DOTDOT)) devfs_delete(dm, de, DEVFS_DEL_NORECURSE); else if (de->de_dirent->d_type == DT_DIR) |