18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
38c2ecf20Sopenharmony_ci#include <linux/export.h>
48c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
58c2ecf20Sopenharmony_ci#include <linux/fs_struct.h>
68c2ecf20Sopenharmony_ci#include <linux/fs.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <linux/prefetch.h>
98c2ecf20Sopenharmony_ci#include "mount.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic int prepend(char **buffer, int *buflen, const char *str, int namelen)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	*buflen -= namelen;
148c2ecf20Sopenharmony_ci	if (*buflen < 0)
158c2ecf20Sopenharmony_ci		return -ENAMETOOLONG;
168c2ecf20Sopenharmony_ci	*buffer -= namelen;
178c2ecf20Sopenharmony_ci	memcpy(*buffer, str, namelen);
188c2ecf20Sopenharmony_ci	return 0;
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/**
228c2ecf20Sopenharmony_ci * prepend_name - prepend a pathname in front of current buffer pointer
238c2ecf20Sopenharmony_ci * @buffer: buffer pointer
248c2ecf20Sopenharmony_ci * @buflen: allocated length of the buffer
258c2ecf20Sopenharmony_ci * @name:   name string and length qstr structure
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to
288c2ecf20Sopenharmony_ci * make sure that either the old or the new name pointer and length are
298c2ecf20Sopenharmony_ci * fetched. However, there may be mismatch between length and pointer.
308c2ecf20Sopenharmony_ci * The length cannot be trusted, we need to copy it byte-by-byte until
318c2ecf20Sopenharmony_ci * the length is reached or a null byte is found. It also prepends "/" at
328c2ecf20Sopenharmony_ci * the beginning of the name. The sequence number check at the caller will
338c2ecf20Sopenharmony_ci * retry it again when a d_move() does happen. So any garbage in the buffer
348c2ecf20Sopenharmony_ci * due to mismatched pointer and length will be discarded.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * Load acquire is needed to make sure that we see that terminating NUL.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_cistatic int prepend_name(char **buffer, int *buflen, const struct qstr *name)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	const char *dname = smp_load_acquire(&name->name); /* ^^^ */
418c2ecf20Sopenharmony_ci	u32 dlen = READ_ONCE(name->len);
428c2ecf20Sopenharmony_ci	char *p;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	*buflen -= dlen + 1;
458c2ecf20Sopenharmony_ci	if (*buflen < 0)
468c2ecf20Sopenharmony_ci		return -ENAMETOOLONG;
478c2ecf20Sopenharmony_ci	p = *buffer -= dlen + 1;
488c2ecf20Sopenharmony_ci	*p++ = '/';
498c2ecf20Sopenharmony_ci	while (dlen--) {
508c2ecf20Sopenharmony_ci		char c = *dname++;
518c2ecf20Sopenharmony_ci		if (!c)
528c2ecf20Sopenharmony_ci			break;
538c2ecf20Sopenharmony_ci		*p++ = c;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * prepend_path - Prepend path string to a buffer
608c2ecf20Sopenharmony_ci * @path: the dentry/vfsmount to report
618c2ecf20Sopenharmony_ci * @root: root vfsmnt/dentry
628c2ecf20Sopenharmony_ci * @buffer: pointer to the end of the buffer
638c2ecf20Sopenharmony_ci * @buflen: pointer to buffer length
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * The function will first try to write out the pathname without taking any
668c2ecf20Sopenharmony_ci * lock other than the RCU read lock to make sure that dentries won't go away.
678c2ecf20Sopenharmony_ci * It only checks the sequence number of the global rename_lock as any change
688c2ecf20Sopenharmony_ci * in the dentry's d_seq will be preceded by changes in the rename_lock
698c2ecf20Sopenharmony_ci * sequence number. If the sequence number had been changed, it will restart
708c2ecf20Sopenharmony_ci * the whole pathname back-tracing sequence again by taking the rename_lock.
718c2ecf20Sopenharmony_ci * In this case, there is no need to take the RCU read lock as the recursive
728c2ecf20Sopenharmony_ci * parent pointer references will keep the dentry chain alive as long as no
738c2ecf20Sopenharmony_ci * rename operation is performed.
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic int prepend_path(const struct path *path,
768c2ecf20Sopenharmony_ci			const struct path *root,
778c2ecf20Sopenharmony_ci			char **buffer, int *buflen)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct dentry *dentry;
808c2ecf20Sopenharmony_ci	struct vfsmount *vfsmnt;
818c2ecf20Sopenharmony_ci	struct mount *mnt;
828c2ecf20Sopenharmony_ci	int error = 0;
838c2ecf20Sopenharmony_ci	unsigned seq, m_seq = 0;
848c2ecf20Sopenharmony_ci	char *bptr;
858c2ecf20Sopenharmony_ci	int blen;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	rcu_read_lock();
888c2ecf20Sopenharmony_cirestart_mnt:
898c2ecf20Sopenharmony_ci	read_seqbegin_or_lock(&mount_lock, &m_seq);
908c2ecf20Sopenharmony_ci	seq = 0;
918c2ecf20Sopenharmony_ci	rcu_read_lock();
928c2ecf20Sopenharmony_cirestart:
938c2ecf20Sopenharmony_ci	bptr = *buffer;
948c2ecf20Sopenharmony_ci	blen = *buflen;
958c2ecf20Sopenharmony_ci	error = 0;
968c2ecf20Sopenharmony_ci	dentry = path->dentry;
978c2ecf20Sopenharmony_ci	vfsmnt = path->mnt;
988c2ecf20Sopenharmony_ci	mnt = real_mount(vfsmnt);
998c2ecf20Sopenharmony_ci	read_seqbegin_or_lock(&rename_lock, &seq);
1008c2ecf20Sopenharmony_ci	while (dentry != root->dentry || vfsmnt != root->mnt) {
1018c2ecf20Sopenharmony_ci		struct dentry * parent;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1048c2ecf20Sopenharmony_ci			struct mount *parent = READ_ONCE(mnt->mnt_parent);
1058c2ecf20Sopenharmony_ci			struct mnt_namespace *mnt_ns;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci			/* Escaped? */
1088c2ecf20Sopenharmony_ci			if (dentry != vfsmnt->mnt_root) {
1098c2ecf20Sopenharmony_ci				bptr = *buffer;
1108c2ecf20Sopenharmony_ci				blen = *buflen;
1118c2ecf20Sopenharmony_ci				error = 3;
1128c2ecf20Sopenharmony_ci				break;
1138c2ecf20Sopenharmony_ci			}
1148c2ecf20Sopenharmony_ci			/* Global root? */
1158c2ecf20Sopenharmony_ci			if (mnt != parent) {
1168c2ecf20Sopenharmony_ci				dentry = READ_ONCE(mnt->mnt_mountpoint);
1178c2ecf20Sopenharmony_ci				mnt = parent;
1188c2ecf20Sopenharmony_ci				vfsmnt = &mnt->mnt;
1198c2ecf20Sopenharmony_ci				continue;
1208c2ecf20Sopenharmony_ci			}
1218c2ecf20Sopenharmony_ci			mnt_ns = READ_ONCE(mnt->mnt_ns);
1228c2ecf20Sopenharmony_ci			/* open-coded is_mounted() to use local mnt_ns */
1238c2ecf20Sopenharmony_ci			if (!IS_ERR_OR_NULL(mnt_ns) && !is_anon_ns(mnt_ns))
1248c2ecf20Sopenharmony_ci				error = 1;	// absolute root
1258c2ecf20Sopenharmony_ci			else
1268c2ecf20Sopenharmony_ci				error = 2;	// detached or not attached yet
1278c2ecf20Sopenharmony_ci			break;
1288c2ecf20Sopenharmony_ci		}
1298c2ecf20Sopenharmony_ci		parent = dentry->d_parent;
1308c2ecf20Sopenharmony_ci		prefetch(parent);
1318c2ecf20Sopenharmony_ci		error = prepend_name(&bptr, &blen, &dentry->d_name);
1328c2ecf20Sopenharmony_ci		if (error)
1338c2ecf20Sopenharmony_ci			break;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		dentry = parent;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	if (!(seq & 1))
1388c2ecf20Sopenharmony_ci		rcu_read_unlock();
1398c2ecf20Sopenharmony_ci	if (need_seqretry(&rename_lock, seq)) {
1408c2ecf20Sopenharmony_ci		seq = 1;
1418c2ecf20Sopenharmony_ci		goto restart;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	done_seqretry(&rename_lock, seq);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (!(m_seq & 1))
1468c2ecf20Sopenharmony_ci		rcu_read_unlock();
1478c2ecf20Sopenharmony_ci	if (need_seqretry(&mount_lock, m_seq)) {
1488c2ecf20Sopenharmony_ci		m_seq = 1;
1498c2ecf20Sopenharmony_ci		goto restart_mnt;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	done_seqretry(&mount_lock, m_seq);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (error >= 0 && bptr == *buffer) {
1548c2ecf20Sopenharmony_ci		if (--blen < 0)
1558c2ecf20Sopenharmony_ci			error = -ENAMETOOLONG;
1568c2ecf20Sopenharmony_ci		else
1578c2ecf20Sopenharmony_ci			*--bptr = '/';
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	*buffer = bptr;
1608c2ecf20Sopenharmony_ci	*buflen = blen;
1618c2ecf20Sopenharmony_ci	return error;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/**
1658c2ecf20Sopenharmony_ci * __d_path - return the path of a dentry
1668c2ecf20Sopenharmony_ci * @path: the dentry/vfsmount to report
1678c2ecf20Sopenharmony_ci * @root: root vfsmnt/dentry
1688c2ecf20Sopenharmony_ci * @buf: buffer to return value in
1698c2ecf20Sopenharmony_ci * @buflen: buffer length
1708c2ecf20Sopenharmony_ci *
1718c2ecf20Sopenharmony_ci * Convert a dentry into an ASCII path name.
1728c2ecf20Sopenharmony_ci *
1738c2ecf20Sopenharmony_ci * Returns a pointer into the buffer or an error code if the
1748c2ecf20Sopenharmony_ci * path was too long.
1758c2ecf20Sopenharmony_ci *
1768c2ecf20Sopenharmony_ci * "buflen" should be positive.
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * If the path is not reachable from the supplied root, return %NULL.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_cichar *__d_path(const struct path *path,
1818c2ecf20Sopenharmony_ci	       const struct path *root,
1828c2ecf20Sopenharmony_ci	       char *buf, int buflen)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	char *res = buf + buflen;
1858c2ecf20Sopenharmony_ci	int error;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	prepend(&res, &buflen, "\0", 1);
1888c2ecf20Sopenharmony_ci	error = prepend_path(path, root, &res, &buflen);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (error < 0)
1918c2ecf20Sopenharmony_ci		return ERR_PTR(error);
1928c2ecf20Sopenharmony_ci	if (error > 0)
1938c2ecf20Sopenharmony_ci		return NULL;
1948c2ecf20Sopenharmony_ci	return res;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cichar *d_absolute_path(const struct path *path,
1988c2ecf20Sopenharmony_ci	       char *buf, int buflen)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct path root = {};
2018c2ecf20Sopenharmony_ci	char *res = buf + buflen;
2028c2ecf20Sopenharmony_ci	int error;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	prepend(&res, &buflen, "\0", 1);
2058c2ecf20Sopenharmony_ci	error = prepend_path(path, &root, &res, &buflen);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (error > 1)
2088c2ecf20Sopenharmony_ci		error = -EINVAL;
2098c2ecf20Sopenharmony_ci	if (error < 0)
2108c2ecf20Sopenharmony_ci		return ERR_PTR(error);
2118c2ecf20Sopenharmony_ci	return res;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/*
2158c2ecf20Sopenharmony_ci * same as __d_path but appends "(deleted)" for unlinked files.
2168c2ecf20Sopenharmony_ci */
2178c2ecf20Sopenharmony_cistatic int path_with_deleted(const struct path *path,
2188c2ecf20Sopenharmony_ci			     const struct path *root,
2198c2ecf20Sopenharmony_ci			     char **buf, int *buflen)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	prepend(buf, buflen, "\0", 1);
2228c2ecf20Sopenharmony_ci	if (d_unlinked(path->dentry)) {
2238c2ecf20Sopenharmony_ci		int error = prepend(buf, buflen, " (deleted)", 10);
2248c2ecf20Sopenharmony_ci		if (error)
2258c2ecf20Sopenharmony_ci			return error;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return prepend_path(path, root, buf, buflen);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int prepend_unreachable(char **buffer, int *buflen)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	return prepend(buffer, buflen, "(unreachable)", 13);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	unsigned seq;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	do {
2418c2ecf20Sopenharmony_ci		seq = read_seqcount_begin(&fs->seq);
2428c2ecf20Sopenharmony_ci		*root = fs->root;
2438c2ecf20Sopenharmony_ci	} while (read_seqcount_retry(&fs->seq, seq));
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci/**
2478c2ecf20Sopenharmony_ci * d_path - return the path of a dentry
2488c2ecf20Sopenharmony_ci * @path: path to report
2498c2ecf20Sopenharmony_ci * @buf: buffer to return value in
2508c2ecf20Sopenharmony_ci * @buflen: buffer length
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * Convert a dentry into an ASCII path name. If the entry has been deleted
2538c2ecf20Sopenharmony_ci * the string " (deleted)" is appended. Note that this is ambiguous.
2548c2ecf20Sopenharmony_ci *
2558c2ecf20Sopenharmony_ci * Returns a pointer into the buffer or an error code if the path was
2568c2ecf20Sopenharmony_ci * too long. Note: Callers should use the returned pointer, not the passed
2578c2ecf20Sopenharmony_ci * in buffer, to use the name! The implementation often starts at an offset
2588c2ecf20Sopenharmony_ci * into the buffer, and may leave 0 bytes at the start.
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * "buflen" should be positive.
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_cichar *d_path(const struct path *path, char *buf, int buflen)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	char *res = buf + buflen;
2658c2ecf20Sopenharmony_ci	struct path root;
2668c2ecf20Sopenharmony_ci	int error;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/*
2698c2ecf20Sopenharmony_ci	 * We have various synthetic filesystems that never get mounted.  On
2708c2ecf20Sopenharmony_ci	 * these filesystems dentries are never used for lookup purposes, and
2718c2ecf20Sopenharmony_ci	 * thus don't need to be hashed.  They also don't need a name until a
2728c2ecf20Sopenharmony_ci	 * user wants to identify the object in /proc/pid/fd/.  The little hack
2738c2ecf20Sopenharmony_ci	 * below allows us to generate a name for these objects on demand:
2748c2ecf20Sopenharmony_ci	 *
2758c2ecf20Sopenharmony_ci	 * Some pseudo inodes are mountable.  When they are mounted
2768c2ecf20Sopenharmony_ci	 * path->dentry == path->mnt->mnt_root.  In that case don't call d_dname
2778c2ecf20Sopenharmony_ci	 * and instead have d_path return the mounted path.
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	if (path->dentry->d_op && path->dentry->d_op->d_dname &&
2808c2ecf20Sopenharmony_ci	    (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
2818c2ecf20Sopenharmony_ci		return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	rcu_read_lock();
2848c2ecf20Sopenharmony_ci	get_fs_root_rcu(current->fs, &root);
2858c2ecf20Sopenharmony_ci	error = path_with_deleted(path, &root, &res, &buflen);
2868c2ecf20Sopenharmony_ci	rcu_read_unlock();
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (error < 0)
2898c2ecf20Sopenharmony_ci		res = ERR_PTR(error);
2908c2ecf20Sopenharmony_ci	return res;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(d_path);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci/*
2958c2ecf20Sopenharmony_ci * Helper function for dentry_operations.d_dname() members
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_cichar *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
2988c2ecf20Sopenharmony_ci			const char *fmt, ...)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	va_list args;
3018c2ecf20Sopenharmony_ci	char temp[64];
3028c2ecf20Sopenharmony_ci	int sz;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	va_start(args, fmt);
3058c2ecf20Sopenharmony_ci	sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
3068c2ecf20Sopenharmony_ci	va_end(args);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (sz > sizeof(temp) || sz > buflen)
3098c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	buffer += buflen - sz;
3128c2ecf20Sopenharmony_ci	return memcpy(buffer, temp, sz);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cichar *simple_dname(struct dentry *dentry, char *buffer, int buflen)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	char *end = buffer + buflen;
3188c2ecf20Sopenharmony_ci	/* these dentries are never renamed, so d_lock is not needed */
3198c2ecf20Sopenharmony_ci	if (prepend(&end, &buflen, " (deleted)", 11) ||
3208c2ecf20Sopenharmony_ci	    prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
3218c2ecf20Sopenharmony_ci	    prepend(&end, &buflen, "/", 1))
3228c2ecf20Sopenharmony_ci		end = ERR_PTR(-ENAMETOOLONG);
3238c2ecf20Sopenharmony_ci	return end;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/*
3278c2ecf20Sopenharmony_ci * Write full pathname from the root of the filesystem into the buffer.
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_cistatic char *__dentry_path(struct dentry *d, char *buf, int buflen)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct dentry *dentry;
3328c2ecf20Sopenharmony_ci	char *end, *retval;
3338c2ecf20Sopenharmony_ci	int len, seq = 0;
3348c2ecf20Sopenharmony_ci	int error = 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (buflen < 2)
3378c2ecf20Sopenharmony_ci		goto Elong;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	rcu_read_lock();
3408c2ecf20Sopenharmony_cirestart:
3418c2ecf20Sopenharmony_ci	dentry = d;
3428c2ecf20Sopenharmony_ci	end = buf + buflen;
3438c2ecf20Sopenharmony_ci	len = buflen;
3448c2ecf20Sopenharmony_ci	prepend(&end, &len, "\0", 1);
3458c2ecf20Sopenharmony_ci	/* Get '/' right */
3468c2ecf20Sopenharmony_ci	retval = end-1;
3478c2ecf20Sopenharmony_ci	*retval = '/';
3488c2ecf20Sopenharmony_ci	read_seqbegin_or_lock(&rename_lock, &seq);
3498c2ecf20Sopenharmony_ci	while (!IS_ROOT(dentry)) {
3508c2ecf20Sopenharmony_ci		struct dentry *parent = dentry->d_parent;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		prefetch(parent);
3538c2ecf20Sopenharmony_ci		error = prepend_name(&end, &len, &dentry->d_name);
3548c2ecf20Sopenharmony_ci		if (error)
3558c2ecf20Sopenharmony_ci			break;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		retval = end;
3588c2ecf20Sopenharmony_ci		dentry = parent;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci	if (!(seq & 1))
3618c2ecf20Sopenharmony_ci		rcu_read_unlock();
3628c2ecf20Sopenharmony_ci	if (need_seqretry(&rename_lock, seq)) {
3638c2ecf20Sopenharmony_ci		seq = 1;
3648c2ecf20Sopenharmony_ci		goto restart;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci	done_seqretry(&rename_lock, seq);
3678c2ecf20Sopenharmony_ci	if (error)
3688c2ecf20Sopenharmony_ci		goto Elong;
3698c2ecf20Sopenharmony_ci	return retval;
3708c2ecf20Sopenharmony_ciElong:
3718c2ecf20Sopenharmony_ci	return ERR_PTR(-ENAMETOOLONG);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cichar *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	return __dentry_path(dentry, buf, buflen);
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dentry_path_raw);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cichar *dentry_path(struct dentry *dentry, char *buf, int buflen)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	char *p = NULL;
3838c2ecf20Sopenharmony_ci	char *retval;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (d_unlinked(dentry)) {
3868c2ecf20Sopenharmony_ci		p = buf + buflen;
3878c2ecf20Sopenharmony_ci		if (prepend(&p, &buflen, "//deleted", 10) != 0)
3888c2ecf20Sopenharmony_ci			goto Elong;
3898c2ecf20Sopenharmony_ci		buflen++;
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci	retval = __dentry_path(dentry, buf, buflen);
3928c2ecf20Sopenharmony_ci	if (!IS_ERR(retval) && p)
3938c2ecf20Sopenharmony_ci		*p = '/';	/* restore '/' overriden with '\0' */
3948c2ecf20Sopenharmony_ci	return retval;
3958c2ecf20Sopenharmony_ciElong:
3968c2ecf20Sopenharmony_ci	return ERR_PTR(-ENAMETOOLONG);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
4008c2ecf20Sopenharmony_ci				    struct path *pwd)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	unsigned seq;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	do {
4058c2ecf20Sopenharmony_ci		seq = read_seqcount_begin(&fs->seq);
4068c2ecf20Sopenharmony_ci		*root = fs->root;
4078c2ecf20Sopenharmony_ci		*pwd = fs->pwd;
4088c2ecf20Sopenharmony_ci	} while (read_seqcount_retry(&fs->seq, seq));
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/*
4128c2ecf20Sopenharmony_ci * NOTE! The user-level library version returns a
4138c2ecf20Sopenharmony_ci * character pointer. The kernel system call just
4148c2ecf20Sopenharmony_ci * returns the length of the buffer filled (which
4158c2ecf20Sopenharmony_ci * includes the ending '\0' character), or a negative
4168c2ecf20Sopenharmony_ci * error value. So libc would do something like
4178c2ecf20Sopenharmony_ci *
4188c2ecf20Sopenharmony_ci *	char *getcwd(char * buf, size_t size)
4198c2ecf20Sopenharmony_ci *	{
4208c2ecf20Sopenharmony_ci *		int retval;
4218c2ecf20Sopenharmony_ci *
4228c2ecf20Sopenharmony_ci *		retval = sys_getcwd(buf, size);
4238c2ecf20Sopenharmony_ci *		if (retval >= 0)
4248c2ecf20Sopenharmony_ci *			return buf;
4258c2ecf20Sopenharmony_ci *		errno = -retval;
4268c2ecf20Sopenharmony_ci *		return NULL;
4278c2ecf20Sopenharmony_ci *	}
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_ciSYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	int error;
4328c2ecf20Sopenharmony_ci	struct path pwd, root;
4338c2ecf20Sopenharmony_ci	char *page = __getname();
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	if (!page)
4368c2ecf20Sopenharmony_ci		return -ENOMEM;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	rcu_read_lock();
4398c2ecf20Sopenharmony_ci	get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	error = -ENOENT;
4428c2ecf20Sopenharmony_ci	if (!d_unlinked(pwd.dentry)) {
4438c2ecf20Sopenharmony_ci		unsigned long len;
4448c2ecf20Sopenharmony_ci		char *cwd = page + PATH_MAX;
4458c2ecf20Sopenharmony_ci		int buflen = PATH_MAX;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		prepend(&cwd, &buflen, "\0", 1);
4488c2ecf20Sopenharmony_ci		error = prepend_path(&pwd, &root, &cwd, &buflen);
4498c2ecf20Sopenharmony_ci		rcu_read_unlock();
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci		if (error < 0)
4528c2ecf20Sopenharmony_ci			goto out;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		/* Unreachable from current root */
4558c2ecf20Sopenharmony_ci		if (error > 0) {
4568c2ecf20Sopenharmony_ci			error = prepend_unreachable(&cwd, &buflen);
4578c2ecf20Sopenharmony_ci			if (error)
4588c2ecf20Sopenharmony_ci				goto out;
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		error = -ERANGE;
4628c2ecf20Sopenharmony_ci		len = PATH_MAX + page - cwd;
4638c2ecf20Sopenharmony_ci		if (len <= size) {
4648c2ecf20Sopenharmony_ci			error = len;
4658c2ecf20Sopenharmony_ci			if (copy_to_user(buf, cwd, len))
4668c2ecf20Sopenharmony_ci				error = -EFAULT;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci	} else {
4698c2ecf20Sopenharmony_ci		rcu_read_unlock();
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciout:
4738c2ecf20Sopenharmony_ci	__putname(page);
4748c2ecf20Sopenharmony_ci	return error;
4758c2ecf20Sopenharmony_ci}
476