qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/4] linux-user: Split out do_getdents, do_getdents64


From: Warner Losh
Subject: Re: [PATCH 1/4] linux-user: Split out do_getdents, do_getdents64
Date: Tue, 9 Nov 2021 09:45:34 -0700


> On Nov 7, 2021, at 5:48 AM, Richard Henderson <richard.henderson@linaro.org> 
> wrote:
> 
> Retain all 3 implementations of getdents for now.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/syscall.c | 325 +++++++++++++++++++++++--------------------
> 1 file changed, 172 insertions(+), 153 deletions(-)

Reviewed by: Warner Losh <imp@bsdimp.com>


> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 544f5b662f..a2f605dec4 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -8137,6 +8137,176 @@ static int host_to_target_cpu_mask(const unsigned 
> long *host_mask,
>     return 0;
> }
> 
> +#ifdef TARGET_NR_getdents
> +static int do_getdents(abi_long arg1, abi_long arg2, abi_long arg3)
> +{
> +    int ret;
> +
> +#ifdef EMULATE_GETDENTS_WITH_GETDENTS
> +# if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
> +    struct target_dirent *target_dirp;
> +    struct linux_dirent *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = g_try_malloc(count);
> +    if (!dirp) {
> +        return -TARGET_ENOMEM;
> +    }
> +
> +    ret = get_errno(sys_getdents(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent *de;
> +        struct target_dirent *tde;
> +        int len = ret;
> +        int reclen, treclen;
> +        int count1, tnamelen;
> +
> +        count1 = 0;
> +        de = dirp;
> +        target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +        if (!target_dirp) {
> +            return -TARGET_EFAULT;
> +        }
> +        tde = target_dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            tnamelen = reclen - offsetof(struct linux_dirent, d_name);
> +            assert(tnamelen >= 0);
> +            treclen = tnamelen + offsetof(struct target_dirent, d_name);
> +            assert(count1 + treclen <= count);
> +            tde->d_reclen = tswap16(treclen);
> +            tde->d_ino = tswapal(de->d_ino);
> +            tde->d_off = tswapal(de->d_off);
> +            memcpy(tde->d_name, de->d_name, tnamelen);
> +            de = (struct linux_dirent *)((char *)de + reclen);
> +            len -= reclen;
> +            tde = (struct target_dirent *)((char *)tde + treclen);
> +            count1 += treclen;
> +        }
> +        ret = count1;
> +        unlock_user(target_dirp, arg2, ret);
> +    }
> +    g_free(dirp);
> +# else
> +    struct linux_dirent *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent *de;
> +        int len = ret;
> +        int reclen;
> +        de = dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            if (reclen > len) {
> +                break;
> +            }
> +            de->d_reclen = tswap16(reclen);
> +            tswapls(&de->d_ino);
> +            tswapls(&de->d_off);
> +            de = (struct linux_dirent *)((char *)de + reclen);
> +            len -= reclen;
> +        }
> +    }
> +    unlock_user(dirp, arg2, ret);
> +# endif
> +#else
> +    /* Implement getdents in terms of getdents64 */
> +    struct linux_dirent64 *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents64(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        /*
> +         * Convert the dirent64 structs to target dirent.  We do this
> +         * in-place, since we can guarantee that a target_dirent is no
> +         * larger than a dirent64; however this means we have to be
> +         * careful to read everything before writing in the new format.
> +         */
> +        struct linux_dirent64 *de;
> +        struct target_dirent *tde;
> +        int len = ret;
> +        int tlen = 0;
> +
> +        de = dirp;
> +        tde = (struct target_dirent *)dirp;
> +        while (len > 0) {
> +            int namelen, treclen;
> +            int reclen = de->d_reclen;
> +            uint64_t ino = de->d_ino;
> +            int64_t off = de->d_off;
> +            uint8_t type = de->d_type;
> +
> +            namelen = strlen(de->d_name);
> +            treclen = offsetof(struct target_dirent, d_name) + namelen + 2;
> +            treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
> +
> +            memmove(tde->d_name, de->d_name, namelen + 1);
> +            tde->d_ino = tswapal(ino);
> +            tde->d_off = tswapal(off);
> +            tde->d_reclen = tswap16(treclen);
> +            /*
> +             * The target_dirent type is in what was formerly a padding
> +             * byte at the end of the structure:
> +             */
> +            *(((char *)tde) + treclen - 1) = type;
> +
> +            de = (struct linux_dirent64 *)((char *)de + reclen);
> +            tde = (struct target_dirent *)((char *)tde + treclen);
> +            len -= reclen;
> +            tlen += treclen;
> +        }
> +        ret = tlen;
> +    }
> +    unlock_user(dirp, arg2, ret);
> +#endif
> +    return ret;
> +}
> +#endif /* TARGET_NR_getdents */
> +
> +#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
> +static int do_getdents64(abi_long arg1, abi_long arg2, abi_long arg3)
> +{
> +    struct linux_dirent64 *dirp;
> +    abi_long count = arg3;
> +    int ret;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents64(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent64 *de;
> +        int len = ret;
> +        int reclen;
> +        de = dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            if (reclen > len) {
> +                break;
> +            }
> +            de->d_reclen = tswap16(reclen);
> +            tswap64s((uint64_t *)&de->d_ino);
> +            tswap64s((uint64_t *)&de->d_off);
> +            de = (struct linux_dirent64 *)((char *)de + reclen);
> +            len -= reclen;
> +        }
> +    }
> +    unlock_user(dirp, arg2, ret);
> +    return ret;
> +}
> +#endif /* TARGET_NR_getdents64 */
> +
> #if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
> _syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
> #endif
> @@ -10227,162 +10397,11 @@ static abi_long do_syscall1(void *cpu_env, int 
> num, abi_long arg1,
> #endif
> #ifdef TARGET_NR_getdents
>     case TARGET_NR_getdents:
> -#ifdef EMULATE_GETDENTS_WITH_GETDENTS
> -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
> -        {
> -            struct target_dirent *target_dirp;
> -            struct linux_dirent *dirp;
> -            abi_long count = arg3;
> -
> -            dirp = g_try_malloc(count);
> -            if (!dirp) {
> -                return -TARGET_ENOMEM;
> -            }
> -
> -            ret = get_errno(sys_getdents(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent *de;
> -             struct target_dirent *tde;
> -                int len = ret;
> -                int reclen, treclen;
> -             int count1, tnamelen;
> -
> -             count1 = 0;
> -                de = dirp;
> -                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                    return -TARGET_EFAULT;
> -             tde = target_dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    tnamelen = reclen - offsetof(struct linux_dirent, 
> d_name);
> -                    assert(tnamelen >= 0);
> -                    treclen = tnamelen + offsetof(struct target_dirent, 
> d_name);
> -                    assert(count1 + treclen <= count);
> -                    tde->d_reclen = tswap16(treclen);
> -                    tde->d_ino = tswapal(de->d_ino);
> -                    tde->d_off = tswapal(de->d_off);
> -                    memcpy(tde->d_name, de->d_name, tnamelen);
> -                    de = (struct linux_dirent *)((char *)de + reclen);
> -                    len -= reclen;
> -                    tde = (struct target_dirent *)((char *)tde + treclen);
> -                 count1 += treclen;
> -                }
> -             ret = count1;
> -                unlock_user(target_dirp, arg2, ret);
> -            }
> -            g_free(dirp);
> -        }
> -#else
> -        {
> -            struct linux_dirent *dirp;
> -            abi_long count = arg3;
> -
> -            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                return -TARGET_EFAULT;
> -            ret = get_errno(sys_getdents(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent *de;
> -                int len = ret;
> -                int reclen;
> -                de = dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    if (reclen > len)
> -                        break;
> -                    de->d_reclen = tswap16(reclen);
> -                    tswapls(&de->d_ino);
> -                    tswapls(&de->d_off);
> -                    de = (struct linux_dirent *)((char *)de + reclen);
> -                    len -= reclen;
> -                }
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -#endif
> -#else
> -        /* Implement getdents in terms of getdents64 */
> -        {
> -            struct linux_dirent64 *dirp;
> -            abi_long count = arg3;
> -
> -            dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> -            if (!dirp) {
> -                return -TARGET_EFAULT;
> -            }
> -            ret = get_errno(sys_getdents64(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                /* Convert the dirent64 structs to target dirent.  We do this
> -                 * in-place, since we can guarantee that a target_dirent is 
> no
> -                 * larger than a dirent64; however this means we have to be
> -                 * careful to read everything before writing in the new 
> format.
> -                 */
> -                struct linux_dirent64 *de;
> -                struct target_dirent *tde;
> -                int len = ret;
> -                int tlen = 0;
> -
> -                de = dirp;
> -                tde = (struct target_dirent *)dirp;
> -                while (len > 0) {
> -                    int namelen, treclen;
> -                    int reclen = de->d_reclen;
> -                    uint64_t ino = de->d_ino;
> -                    int64_t off = de->d_off;
> -                    uint8_t type = de->d_type;
> -
> -                    namelen = strlen(de->d_name);
> -                    treclen = offsetof(struct target_dirent, d_name)
> -                        + namelen + 2;
> -                    treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
> -
> -                    memmove(tde->d_name, de->d_name, namelen + 1);
> -                    tde->d_ino = tswapal(ino);
> -                    tde->d_off = tswapal(off);
> -                    tde->d_reclen = tswap16(treclen);
> -                    /* The target_dirent type is in what was formerly a 
> padding
> -                     * byte at the end of the structure:
> -                     */
> -                    *(((char *)tde) + treclen - 1) = type;
> -
> -                    de = (struct linux_dirent64 *)((char *)de + reclen);
> -                    tde = (struct target_dirent *)((char *)tde + treclen);
> -                    len -= reclen;
> -                    tlen += treclen;
> -                }
> -                ret = tlen;
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -#endif
> -        return ret;
> +        return do_getdents(arg1, arg2, arg3);
> #endif /* TARGET_NR_getdents */
> #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
>     case TARGET_NR_getdents64:
> -        {
> -            struct linux_dirent64 *dirp;
> -            abi_long count = arg3;
> -            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                return -TARGET_EFAULT;
> -            ret = get_errno(sys_getdents64(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent64 *de;
> -                int len = ret;
> -                int reclen;
> -                de = dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    if (reclen > len)
> -                        break;
> -                    de->d_reclen = tswap16(reclen);
> -                    tswap64s((uint64_t *)&de->d_ino);
> -                    tswap64s((uint64_t *)&de->d_off);
> -                    de = (struct linux_dirent64 *)((char *)de + reclen);
> -                    len -= reclen;
> -                }
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -        return ret;
> +        return do_getdents64(arg1, arg2, arg3);
> #endif /* TARGET_NR_getdents64 */
> #if defined(TARGET_NR__newselect)
>     case TARGET_NR__newselect:
> --
> 2.25.1
> 
> 

Attachment: signature.asc
Description: Message signed with OpenPGP


reply via email to

[Prev in Thread] Current Thread [Next in Thread]