aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c71
1 files changed, 44 insertions, 27 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 10ba92def3f6..89509b5a090e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2439,16 +2439,14 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
2439/** 2439/**
2440 * prepend_path - Prepend path string to a buffer 2440 * prepend_path - Prepend path string to a buffer
2441 * @path: the dentry/vfsmount to report 2441 * @path: the dentry/vfsmount to report
2442 * @root: root vfsmnt/dentry (may be modified by this function) 2442 * @root: root vfsmnt/dentry
2443 * @buffer: pointer to the end of the buffer 2443 * @buffer: pointer to the end of the buffer
2444 * @buflen: pointer to buffer length 2444 * @buflen: pointer to buffer length
2445 * 2445 *
2446 * Caller holds the rename_lock. 2446 * Caller holds the rename_lock.
2447 *
2448 * If path is not reachable from the supplied root, then the value of
2449 * root is changed (without modifying refcounts).
2450 */ 2447 */
2451static int prepend_path(const struct path *path, struct path *root, 2448static int prepend_path(const struct path *path,
2449 const struct path *root,
2452 char **buffer, int *buflen) 2450 char **buffer, int *buflen)
2453{ 2451{
2454 struct dentry *dentry = path->dentry; 2452 struct dentry *dentry = path->dentry;
@@ -2483,10 +2481,10 @@ static int prepend_path(const struct path *path, struct path *root,
2483 dentry = parent; 2481 dentry = parent;
2484 } 2482 }
2485 2483
2486out:
2487 if (!error && !slash) 2484 if (!error && !slash)
2488 error = prepend(buffer, buflen, "/", 1); 2485 error = prepend(buffer, buflen, "/", 1);
2489 2486
2487out:
2490 br_read_unlock(vfsmount_lock); 2488 br_read_unlock(vfsmount_lock);
2491 return error; 2489 return error;
2492 2490
@@ -2500,15 +2498,17 @@ global_root:
2500 WARN(1, "Root dentry has weird name <%.*s>\n", 2498 WARN(1, "Root dentry has weird name <%.*s>\n",
2501 (int) dentry->d_name.len, dentry->d_name.name); 2499 (int) dentry->d_name.len, dentry->d_name.name);
2502 } 2500 }
2503 root->mnt = vfsmnt; 2501 if (!slash)
2504 root->dentry = dentry; 2502 error = prepend(buffer, buflen, "/", 1);
2503 if (!error)
2504 error = vfsmnt->mnt_ns ? 1 : 2;
2505 goto out; 2505 goto out;
2506} 2506}
2507 2507
2508/** 2508/**
2509 * __d_path - return the path of a dentry 2509 * __d_path - return the path of a dentry
2510 * @path: the dentry/vfsmount to report 2510 * @path: the dentry/vfsmount to report
2511 * @root: root vfsmnt/dentry (may be modified by this function) 2511 * @root: root vfsmnt/dentry
2512 * @buf: buffer to return value in 2512 * @buf: buffer to return value in
2513 * @buflen: buffer length 2513 * @buflen: buffer length
2514 * 2514 *
@@ -2519,10 +2519,10 @@ global_root:
2519 * 2519 *
2520 * "buflen" should be positive. 2520 * "buflen" should be positive.
2521 * 2521 *
2522 * If path is not reachable from the supplied root, then the value of 2522 * If the path is not reachable from the supplied root, return %NULL.
2523 * root is changed (without modifying refcounts).
2524 */ 2523 */
2525char *__d_path(const struct path *path, struct path *root, 2524char *__d_path(const struct path *path,
2525 const struct path *root,
2526 char *buf, int buflen) 2526 char *buf, int buflen)
2527{ 2527{
2528 char *res = buf + buflen; 2528 char *res = buf + buflen;
@@ -2533,7 +2533,28 @@ char *__d_path(const struct path *path, struct path *root,
2533 error = prepend_path(path, root, &res, &buflen); 2533 error = prepend_path(path, root, &res, &buflen);
2534 write_sequnlock(&rename_lock); 2534 write_sequnlock(&rename_lock);
2535 2535
2536 if (error) 2536 if (error < 0)
2537 return ERR_PTR(error);
2538 if (error > 0)
2539 return NULL;
2540 return res;
2541}
2542
2543char *d_absolute_path(const struct path *path,
2544 char *buf, int buflen)
2545{
2546 struct path root = {};
2547 char *res = buf + buflen;
2548 int error;
2549
2550 prepend(&res, &buflen, "\0", 1);
2551 write_seqlock(&rename_lock);
2552 error = prepend_path(path, &root, &res, &buflen);
2553 write_sequnlock(&rename_lock);
2554
2555 if (error > 1)
2556 error = -EINVAL;
2557 if (error < 0)
2537 return ERR_PTR(error); 2558 return ERR_PTR(error);
2538 return res; 2559 return res;
2539} 2560}
@@ -2541,8 +2562,9 @@ char *__d_path(const struct path *path, struct path *root,
2541/* 2562/*
2542 * same as __d_path but appends "(deleted)" for unlinked files. 2563 * same as __d_path but appends "(deleted)" for unlinked files.
2543 */ 2564 */
2544static int path_with_deleted(const struct path *path, struct path *root, 2565static int path_with_deleted(const struct path *path,
2545 char **buf, int *buflen) 2566 const struct path *root,
2567 char **buf, int *buflen)
2546{ 2568{
2547 prepend(buf, buflen, "\0", 1); 2569 prepend(buf, buflen, "\0", 1);
2548 if (d_unlinked(path->dentry)) { 2570 if (d_unlinked(path->dentry)) {
@@ -2579,7 +2601,6 @@ char *d_path(const struct path *path, char *buf, int buflen)
2579{ 2601{
2580 char *res = buf + buflen; 2602 char *res = buf + buflen;
2581 struct path root; 2603 struct path root;
2582 struct path tmp;
2583 int error; 2604 int error;
2584 2605
2585 /* 2606 /*
@@ -2594,9 +2615,8 @@ char *d_path(const struct path *path, char *buf, int buflen)
2594 2615
2595 get_fs_root(current->fs, &root); 2616 get_fs_root(current->fs, &root);
2596 write_seqlock(&rename_lock); 2617 write_seqlock(&rename_lock);
2597 tmp = root; 2618 error = path_with_deleted(path, &root, &res, &buflen);
2598 error = path_with_deleted(path, &tmp, &res, &buflen); 2619 if (error < 0)
2599 if (error)
2600 res = ERR_PTR(error); 2620 res = ERR_PTR(error);
2601 write_sequnlock(&rename_lock); 2621 write_sequnlock(&rename_lock);
2602 path_put(&root); 2622 path_put(&root);
@@ -2617,7 +2637,6 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
2617{ 2637{
2618 char *res = buf + buflen; 2638 char *res = buf + buflen;
2619 struct path root; 2639 struct path root;
2620 struct path tmp;
2621 int error; 2640 int error;
2622 2641
2623 if (path->dentry->d_op && path->dentry->d_op->d_dname) 2642 if (path->dentry->d_op && path->dentry->d_op->d_dname)
@@ -2625,9 +2644,8 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen)
2625 2644
2626 get_fs_root(current->fs, &root); 2645 get_fs_root(current->fs, &root);
2627 write_seqlock(&rename_lock); 2646 write_seqlock(&rename_lock);
2628 tmp = root; 2647 error = path_with_deleted(path, &root, &res, &buflen);
2629 error = path_with_deleted(path, &tmp, &res, &buflen); 2648 if (error > 0)
2630 if (!error && !path_equal(&tmp, &root))
2631 error = prepend_unreachable(&res, &buflen); 2649 error = prepend_unreachable(&res, &buflen);
2632 write_sequnlock(&rename_lock); 2650 write_sequnlock(&rename_lock);
2633 path_put(&root); 2651 path_put(&root);
@@ -2758,19 +2776,18 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
2758 write_seqlock(&rename_lock); 2776 write_seqlock(&rename_lock);
2759 if (!d_unlinked(pwd.dentry)) { 2777 if (!d_unlinked(pwd.dentry)) {
2760 unsigned long len; 2778 unsigned long len;
2761 struct path tmp = root;
2762 char *cwd = page + PAGE_SIZE; 2779 char *cwd = page + PAGE_SIZE;
2763 int buflen = PAGE_SIZE; 2780 int buflen = PAGE_SIZE;
2764 2781
2765 prepend(&cwd, &buflen, "\0", 1); 2782 prepend(&cwd, &buflen, "\0", 1);
2766 error = prepend_path(&pwd, &tmp, &cwd, &buflen); 2783 error = prepend_path(&pwd, &root, &cwd, &buflen);
2767 write_sequnlock(&rename_lock); 2784 write_sequnlock(&rename_lock);
2768 2785
2769 if (error) 2786 if (error < 0)
2770 goto out; 2787 goto out;
2771 2788
2772 /* Unreachable from current root */ 2789 /* Unreachable from current root */
2773 if (!path_equal(&tmp, &root)) { 2790 if (error > 0) {
2774 error = prepend_unreachable(&cwd, &buflen); 2791 error = prepend_unreachable(&cwd, &buflen);
2775 if (error) 2792 if (error)
2776 goto out; 2793 goto out;