diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 108 |
1 files changed, 48 insertions, 60 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d9ca1e5ceb9..43455776711 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -89,12 +89,20 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); /* if dentry was never inserted into hash, immediate free is OK */ - if (dentry->d_hash.pprev == NULL) + if (hlist_unhashed(&dentry->d_hash)) __d_free(dentry); else call_rcu(&dentry->d_u.d_rcu, d_callback); } +static void dentry_lru_remove(struct dentry *dentry) +{ + if (!list_empty(&dentry->d_lru)) { + list_del_init(&dentry->d_lru); + dentry_stat.nr_unused--; + } +} + /* * Release the dentry's inode, using the filesystem * d_iput() operation if defined. @@ -211,13 +219,7 @@ repeat: unhash_it: __d_drop(dentry); kill_it: - /* If dentry was on d_lru list - * delete it from there - */ - if (!list_empty(&dentry->d_lru)) { - list_del(&dentry->d_lru); - dentry_stat.nr_unused--; - } + dentry_lru_remove(dentry); dentry = d_kill(dentry); if (dentry) goto repeat; @@ -285,10 +287,7 @@ int d_invalidate(struct dentry * dentry) static inline struct dentry * __dget_locked(struct dentry *dentry) { atomic_inc(&dentry->d_count); - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); return dentry; } @@ -404,10 +403,7 @@ static void prune_one_dentry(struct dentry * dentry) if (dentry->d_op && dentry->d_op->d_delete) dentry->d_op->d_delete(dentry); - if (!list_empty(&dentry->d_lru)) { - list_del(&dentry->d_lru); - dentry_stat.nr_unused--; - } + dentry_lru_remove(dentry); __d_drop(dentry); dentry = d_kill(dentry); spin_lock(&dcache_lock); @@ -596,10 +592,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) /* detach this root from the system */ spin_lock(&dcache_lock); - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); __d_drop(dentry); spin_unlock(&dcache_lock); @@ -613,11 +606,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) spin_lock(&dcache_lock); list_for_each_entry(loop, &dentry->d_subdirs, d_u.d_child) { - if (!list_empty(&loop->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&loop->d_lru); - } - + dentry_lru_remove(loop); __d_drop(loop); cond_resched_lock(&dcache_lock); } @@ -799,10 +788,7 @@ resume: struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); /* * move only zero ref count dentries to the end * of the unused list for prune_dcache @@ -1408,9 +1394,6 @@ void d_delete(struct dentry * dentry) if (atomic_read(&dentry->d_count) == 1) { dentry_iput(dentry); fsnotify_nameremove(dentry, isdir); - - /* remove this and other inotify debug checks after 2.6.18 */ - dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; return; } @@ -1779,9 +1762,8 @@ shouldnt_be_hashed: * * "buflen" should be positive. Caller holds the dcache_lock. */ -static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, - struct dentry *root, struct vfsmount *rootmnt, - char *buffer, int buflen) +static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, + struct path *root, char *buffer, int buflen) { char * end = buffer+buflen; char * retval; @@ -1806,7 +1788,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, for (;;) { struct dentry * parent; - if (dentry == root && vfsmnt == rootmnt) + if (dentry == root->dentry && vfsmnt == root->mnt) break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { /* Global root? */ @@ -1847,13 +1829,23 @@ Elong: return ERR_PTR(-ENAMETOOLONG); } -/* write full pathname into buffer and return start of pathname */ -char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, - char *buf, int buflen) +/** + * d_path - return the path of a dentry + * @path: path to report + * @buf: buffer to return value in + * @buflen: buffer length + * + * Convert a dentry into an ASCII path name. If the entry has been deleted + * the string " (deleted)" is appended. Note that this is ambiguous. + * + * Returns the buffer or an error code if the path was too long. + * + * "buflen" should be positive. Caller holds the dcache_lock. + */ +char *d_path(struct path *path, char *buf, int buflen) { char *res; - struct vfsmount *rootmnt; - struct dentry *root; + struct path root; /* * We have various synthetic filesystems that never get mounted. On @@ -1862,18 +1854,17 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, * user wants to identify the object in /proc/pid/fd/. The little hack * below allows us to generate a name for these objects on demand: */ - if (dentry->d_op && dentry->d_op->d_dname) - return dentry->d_op->d_dname(dentry, buf, buflen); + if (path->dentry->d_op && path->dentry->d_op->d_dname) + return path->dentry->d_op->d_dname(path->dentry, buf, buflen); read_lock(¤t->fs->lock); - rootmnt = mntget(current->fs->rootmnt); - root = dget(current->fs->root); + root = current->fs->root; + path_get(¤t->fs->root); read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); - res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); + res = __d_path(path->dentry, path->mnt, &root, buf, buflen); spin_unlock(&dcache_lock); - dput(root); - mntput(rootmnt); + path_put(&root); return res; } @@ -1919,28 +1910,27 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, asmlinkage long sys_getcwd(char __user *buf, unsigned long size) { int error; - struct vfsmount *pwdmnt, *rootmnt; - struct dentry *pwd, *root; + struct path pwd, root; char *page = (char *) __get_free_page(GFP_USER); if (!page) return -ENOMEM; read_lock(¤t->fs->lock); - pwdmnt = mntget(current->fs->pwdmnt); - pwd = dget(current->fs->pwd); - rootmnt = mntget(current->fs->rootmnt); - root = dget(current->fs->root); + pwd = current->fs->pwd; + path_get(¤t->fs->pwd); + root = current->fs->root; + path_get(¤t->fs->root); read_unlock(¤t->fs->lock); error = -ENOENT; /* Has the current directory has been unlinked? */ spin_lock(&dcache_lock); - if (pwd->d_parent == pwd || !d_unhashed(pwd)) { + if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { unsigned long len; char * cwd; - cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); + cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); spin_unlock(&dcache_lock); error = PTR_ERR(cwd); @@ -1958,10 +1948,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) spin_unlock(&dcache_lock); out: - dput(pwd); - mntput(pwdmnt); - dput(root); - mntput(rootmnt); + path_put(&pwd); + path_put(&root); free_page((unsigned long) page); return error; } |