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