@@ -3224,6 +3224,18 @@ char *d_absolute_path(const struct path *path,
return res;
}
+static inline bool d_unhashed_safe(struct dentry *dentry)
+{
+ bool ret = d_unhashed(dentry);
+ if (unlikely(ret)) {
+ /* retry under d_lock */
+ spin_lock(&dentry->d_lock);
+ ret = d_unhashed(dentry);
+ spin_unlock(&dentry->d_lock);
+ }
+ return ret;
+}
+
/*
* same as __d_path but appends "(deleted)" for unlinked files.
*/
@@ -3232,7 +3244,7 @@ static int path_with_deleted(const struct path *path,
char **buf, int *buflen)
{
prepend(buf, buflen, "\0", 1);
- if (d_unlinked(path->dentry)) {
+ if (d_unhashed_safe(path->dentry)) {
int error = prepend(buf, buflen, " (deleted)", 10);
if (error)
return error;
@@ -3396,7 +3408,7 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
char *p = NULL;
char *retval;
- if (d_unlinked(dentry)) {
+ if (d_unhashed_safe(dentry)) {
p = buf + buflen;
if (prepend(&p, &buflen, "//deleted", 10) != 0)
goto Elong;
@@ -3453,7 +3465,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
error = -ENOENT;
- if (!d_unlinked(pwd.dentry)) {
+ if (!d_unhashed_safe(pwd.dentry)) {
unsigned long len;
char *cwd = page + PATH_MAX;
int buflen = PATH_MAX;