xref: /freebsd/sys/compat/linux/linux_stats.c (revision 3cf834d069d1dcdbe464ea74624930eaf916715d)
1c21dee17SSøren Schmidt /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
37f2d13d6SPedro F. Giffuni  *
49a14aa01SUlrich Spörlein  * Copyright (c) 1994-1995 Søren Schmidt
5c21dee17SSøren Schmidt  * All rights reserved.
6c21dee17SSøren Schmidt  *
7c21dee17SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
8c21dee17SSøren Schmidt  * modification, are permitted provided that the following conditions
9c21dee17SSøren Schmidt  * are met:
10c21dee17SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
110ba1b365SEd Maste  *    notice, this list of conditions and the following disclaimer.
12c21dee17SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
13c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
14c21dee17SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
15c21dee17SSøren Schmidt  *
160ba1b365SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
170ba1b365SEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180ba1b365SEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190ba1b365SEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200ba1b365SEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210ba1b365SEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220ba1b365SEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230ba1b365SEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240ba1b365SEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250ba1b365SEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260ba1b365SEd Maste  * SUCH DAMAGE.
27c21dee17SSøren Schmidt  */
28c21dee17SSøren Schmidt 
29cb858340SDmitry Chagin #include "opt_ktrace.h"
30cb858340SDmitry Chagin 
31c21dee17SSøren Schmidt #include <sys/param.h>
329802eb9eSDmitry Chagin #include <sys/capsicum.h>
33c21dee17SSøren Schmidt #include <sys/dirent.h>
34d8e53d94SDmitry Chagin #include <sys/lock.h>
3585422e62SBruce Evans #include <sys/malloc.h>
36d8e53d94SDmitry Chagin #include <sys/mutex.h>
37cb858340SDmitry Chagin #include <sys/namei.h>
38d8e53d94SDmitry Chagin #include <sys/proc.h>
39c21dee17SSøren Schmidt #include <sys/stat.h>
40f7a25872SJohn Baldwin #include <sys/syscallsubr.h>
41bc093719SEd Schouten #include <sys/tty.h>
42c21dee17SSøren Schmidt #include <sys/vnode.h>
43cb858340SDmitry Chagin #ifdef KTRACE
44cb858340SDmitry Chagin #include <sys/ktrace.h>
45cb858340SDmitry Chagin #endif
46c21dee17SSøren Schmidt 
47994ed958SDmitry Chagin #include <security/audit/audit.h>
48994ed958SDmitry Chagin 
491997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
504af27623STim J. Robbins #include <machine/../linux32/linux.h>
514af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
521997c537SDavid E. O'Brien #else
531997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
541997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
554af27623STim J. Robbins #endif
5685422e62SBruce Evans 
57166e2e5aSDmitry Chagin #include <compat/linux/linux.h>
5848b05c3fSKonstantin Belousov #include <compat/linux/linux_file.h>
592a38f51cSDmitry Chagin #include <compat/linux/linux_util.h>
60762e6b85SEivind Eklund 
610eee862aSEd Schouten 
620eee862aSEd Schouten static int
linux_kern_fstat(struct thread * td,int fd,struct stat * sbp)63994ed958SDmitry Chagin linux_kern_fstat(struct thread *td, int fd, struct stat *sbp)
64994ed958SDmitry Chagin {
65994ed958SDmitry Chagin 	struct vnode *vp;
66994ed958SDmitry Chagin 	struct file *fp;
67994ed958SDmitry Chagin 	int error;
68994ed958SDmitry Chagin 
69994ed958SDmitry Chagin 	AUDIT_ARG_FD(fd);
70994ed958SDmitry Chagin 
71994ed958SDmitry Chagin 	error = fget(td, fd, &cap_fstat_rights, &fp);
72994ed958SDmitry Chagin 	if (__predict_false(error != 0))
73994ed958SDmitry Chagin 		return (error);
74994ed958SDmitry Chagin 
75994ed958SDmitry Chagin 	AUDIT_ARG_FILE(td->td_proc, fp);
76994ed958SDmitry Chagin 
77994ed958SDmitry Chagin 	error = fo_stat(fp, sbp, td->td_ucred);
78994ed958SDmitry Chagin 	if (error == 0 && (vp = fp->f_vnode) != NULL)
79994ed958SDmitry Chagin 		translate_vnhook_major_minor(vp, sbp);
80994ed958SDmitry Chagin 	fdrop(fp, td);
81994ed958SDmitry Chagin #ifdef KTRACE
82994ed958SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
83994ed958SDmitry Chagin 		ktrstat_error(sbp, error);
84994ed958SDmitry Chagin #endif
85994ed958SDmitry Chagin 	return (error);
86994ed958SDmitry Chagin }
87994ed958SDmitry Chagin 
88994ed958SDmitry Chagin static int
linux_kern_statat(struct thread * td,int flag,int fd,const char * path,enum uio_seg pathseg,struct stat * sbp)89a125ed50SMateusz Guzik linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
900eee862aSEd Schouten     enum uio_seg pathseg, struct stat *sbp)
910eee862aSEd Schouten {
92cb858340SDmitry Chagin 	struct nameidata nd;
93cb858340SDmitry Chagin 	int error;
940eee862aSEd Schouten 
95cb858340SDmitry Chagin 	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
96cb858340SDmitry Chagin 	    AT_EMPTY_PATH)) != 0)
97cb858340SDmitry Chagin 		return (EINVAL);
98cb858340SDmitry Chagin 
99cb858340SDmitry Chagin 	NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH |
100cb858340SDmitry Chagin 	    AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF |
101cb858340SDmitry Chagin 	    AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights);
102cb858340SDmitry Chagin 
103cb858340SDmitry Chagin 	if ((error = namei(&nd)) != 0) {
104cb858340SDmitry Chagin 		if (error == ENOTDIR &&
105cb858340SDmitry Chagin 		    (nd.ni_resflags & NIRES_EMPTYPATH) != 0)
106994ed958SDmitry Chagin 			error = linux_kern_fstat(td, fd, sbp);
107cb858340SDmitry Chagin 		return (error);
108cb858340SDmitry Chagin 	}
109cb858340SDmitry Chagin 	error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED);
110cb858340SDmitry Chagin 	if (error == 0)
111cb858340SDmitry Chagin 		translate_vnhook_major_minor(nd.ni_vp, sbp);
112cb858340SDmitry Chagin 	NDFREE_PNBUF(&nd);
113cb858340SDmitry Chagin 	vput(nd.ni_vp);
114cb858340SDmitry Chagin #ifdef KTRACE
115cb858340SDmitry Chagin 	if (KTRPOINT(td, KTR_STRUCT))
116cb858340SDmitry Chagin 		ktrstat_error(sbp, error);
117cb858340SDmitry Chagin #endif
118cb858340SDmitry Chagin 	return (error);
1190eee862aSEd Schouten }
1200eee862aSEd Schouten 
121931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
1220eee862aSEd Schouten static int
linux_kern_stat(struct thread * td,const char * path,enum uio_seg pathseg,struct stat * sbp)123a125ed50SMateusz Guzik linux_kern_stat(struct thread *td, const char *path, enum uio_seg pathseg,
1240eee862aSEd Schouten     struct stat *sbp)
1250eee862aSEd Schouten {
1260eee862aSEd Schouten 
1270eee862aSEd Schouten 	return (linux_kern_statat(td, 0, AT_FDCWD, path, pathseg, sbp));
1280eee862aSEd Schouten }
1290eee862aSEd Schouten 
1300eee862aSEd Schouten static int
linux_kern_lstat(struct thread * td,const char * path,enum uio_seg pathseg,struct stat * sbp)131a125ed50SMateusz Guzik linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
1320eee862aSEd Schouten     struct stat *sbp)
1330eee862aSEd Schouten {
1340eee862aSEd Schouten 
1350eee862aSEd Schouten 	return (linux_kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, path,
1360eee862aSEd Schouten 	    pathseg, sbp));
1370eee862aSEd Schouten }
138931e2a1aSEd Maste #endif
1390eee862aSEd Schouten 
140bbbc2d96SPoul-Henning Kamp static int
newstat_copyout(struct stat * buf,void * ubuf)141bbbc2d96SPoul-Henning Kamp newstat_copyout(struct stat *buf, void *ubuf)
142bbbc2d96SPoul-Henning Kamp {
143bbbc2d96SPoul-Henning Kamp 	struct l_newstat tbuf;
144bbbc2d96SPoul-Henning Kamp 
145bbbc2d96SPoul-Henning Kamp 	bzero(&tbuf, sizeof(tbuf));
146166e2e5aSDmitry Chagin 	tbuf.st_dev = linux_new_encode_dev(buf->st_dev);
147bbbc2d96SPoul-Henning Kamp 	tbuf.st_ino = buf->st_ino;
148bbbc2d96SPoul-Henning Kamp 	tbuf.st_mode = buf->st_mode;
149bbbc2d96SPoul-Henning Kamp 	tbuf.st_nlink = buf->st_nlink;
150bbbc2d96SPoul-Henning Kamp 	tbuf.st_uid = buf->st_uid;
151bbbc2d96SPoul-Henning Kamp 	tbuf.st_gid = buf->st_gid;
152166e2e5aSDmitry Chagin 	tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
153bbbc2d96SPoul-Henning Kamp 	tbuf.st_size = buf->st_size;
154510ea843SEd Schouten 	tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
155510ea843SEd Schouten 	tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
156510ea843SEd Schouten 	tbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
157510ea843SEd Schouten 	tbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
158510ea843SEd Schouten 	tbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
159510ea843SEd Schouten 	tbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
160bbbc2d96SPoul-Henning Kamp 	tbuf.st_blksize = buf->st_blksize;
161bbbc2d96SPoul-Henning Kamp 	tbuf.st_blocks = buf->st_blocks;
162bbbc2d96SPoul-Henning Kamp 
1634e0eaf69SMarcel Moolenaar 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
164c21dee17SSøren Schmidt }
165c21dee17SSøren Schmidt 
1662362ad45SPhilippe Michaud-Boudreault 
167931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
168c21dee17SSøren Schmidt int
linux_newstat(struct thread * td,struct linux_newstat_args * args)169b40ce416SJulian Elischer linux_newstat(struct thread *td, struct linux_newstat_args *args)
170c21dee17SSøren Schmidt {
171c21dee17SSøren Schmidt 	struct stat buf;
172c21dee17SSøren Schmidt 	int error;
173d66a5066SPeter Wemm 
174a125ed50SMateusz Guzik 	error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
1754e0eaf69SMarcel Moolenaar 	if (error)
1764e0eaf69SMarcel Moolenaar 		return (error);
1774e0eaf69SMarcel Moolenaar 	return (newstat_copyout(&buf, args->buf));
178c21dee17SSøren Schmidt }
179c21dee17SSøren Schmidt 
180c21dee17SSøren Schmidt int
linux_newlstat(struct thread * td,struct linux_newlstat_args * args)181b40ce416SJulian Elischer linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
182c21dee17SSøren Schmidt {
1834e0eaf69SMarcel Moolenaar 	struct stat sb;
184f7a25872SJohn Baldwin 	int error;
185d66a5066SPeter Wemm 
186a125ed50SMateusz Guzik 	error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
187d66a5066SPeter Wemm 	if (error)
188d66a5066SPeter Wemm 		return (error);
1895002a60fSMarcel Moolenaar 	return (newstat_copyout(&sb, args->buf));
190d66a5066SPeter Wemm }
191931e2a1aSEd Maste #endif
192c21dee17SSøren Schmidt 
193c21dee17SSøren Schmidt int
linux_newfstat(struct thread * td,struct linux_newfstat_args * args)194b40ce416SJulian Elischer linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
195c21dee17SSøren Schmidt {
196c21dee17SSøren Schmidt 	struct stat buf;
197c21dee17SSøren Schmidt 	int error;
198c21dee17SSøren Schmidt 
199994ed958SDmitry Chagin 	error = linux_kern_fstat(td, args->fd, &buf);
200c21dee17SSøren Schmidt 	if (!error)
201c21dee17SSøren Schmidt 		error = newstat_copyout(&buf, args->buf);
2024e0eaf69SMarcel Moolenaar 
2034e0eaf69SMarcel Moolenaar 	return (error);
204c21dee17SSøren Schmidt }
205c21dee17SSøren Schmidt 
2067f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
207166e2e5aSDmitry Chagin 
208166e2e5aSDmitry Chagin static __inline uint16_t
linux_old_encode_dev(dev_t _dev)209166e2e5aSDmitry Chagin linux_old_encode_dev(dev_t _dev)
210166e2e5aSDmitry Chagin {
211166e2e5aSDmitry Chagin 
212166e2e5aSDmitry Chagin 	return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
213166e2e5aSDmitry Chagin }
214166e2e5aSDmitry Chagin 
2155c8919adSAlexander Leidinger static int
old_stat_copyout(struct stat * buf,void * ubuf)216a408fc09SDmitry Chagin old_stat_copyout(struct stat *buf, void *ubuf)
2175c8919adSAlexander Leidinger {
218a408fc09SDmitry Chagin 	struct l_old_stat lbuf;
2195c8919adSAlexander Leidinger 
2205c8919adSAlexander Leidinger 	bzero(&lbuf, sizeof(lbuf));
221166e2e5aSDmitry Chagin 	lbuf.st_dev = linux_old_encode_dev(buf->st_dev);
2225c8919adSAlexander Leidinger 	lbuf.st_ino = buf->st_ino;
2235c8919adSAlexander Leidinger 	lbuf.st_mode = buf->st_mode;
2245c8919adSAlexander Leidinger 	lbuf.st_nlink = buf->st_nlink;
2255c8919adSAlexander Leidinger 	lbuf.st_uid = buf->st_uid;
2265c8919adSAlexander Leidinger 	lbuf.st_gid = buf->st_gid;
227166e2e5aSDmitry Chagin 	lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev);
228372639f9SBruce Evans 	lbuf.st_size = MIN(buf->st_size, INT32_MAX);
229510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
230510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
231510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
232510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
233510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
234510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
2355c8919adSAlexander Leidinger 	lbuf.st_blksize = buf->st_blksize;
2365c8919adSAlexander Leidinger 	lbuf.st_blocks = buf->st_blocks;
2375c8919adSAlexander Leidinger 	lbuf.st_flags = buf->st_flags;
2385c8919adSAlexander Leidinger 	lbuf.st_gen = buf->st_gen;
2395c8919adSAlexander Leidinger 
2405c8919adSAlexander Leidinger 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
2415c8919adSAlexander Leidinger }
2425c8919adSAlexander Leidinger 
2435c8919adSAlexander Leidinger int
linux_stat(struct thread * td,struct linux_stat_args * args)2445c8919adSAlexander Leidinger linux_stat(struct thread *td, struct linux_stat_args *args)
2455c8919adSAlexander Leidinger {
2465c8919adSAlexander Leidinger 	struct stat buf;
2475c8919adSAlexander Leidinger 	int error;
24815b78ac5SKonstantin Belousov 
249a125ed50SMateusz Guzik 	error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
250a125ed50SMateusz Guzik 	if (error) {
2515c8919adSAlexander Leidinger 		return (error);
252d075105dSKonstantin Belousov 	}
253a408fc09SDmitry Chagin 	return (old_stat_copyout(&buf, args->up));
2545c8919adSAlexander Leidinger }
2555c8919adSAlexander Leidinger 
2565c8919adSAlexander Leidinger int
linux_lstat(struct thread * td,struct linux_lstat_args * args)2575c8919adSAlexander Leidinger linux_lstat(struct thread *td, struct linux_lstat_args *args)
2585c8919adSAlexander Leidinger {
2595c8919adSAlexander Leidinger 	struct stat buf;
2605c8919adSAlexander Leidinger 	int error;
2615c8919adSAlexander Leidinger 
262a125ed50SMateusz Guzik 	error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
263a125ed50SMateusz Guzik 	if (error) {
2645c8919adSAlexander Leidinger 		return (error);
265d075105dSKonstantin Belousov 	}
266a408fc09SDmitry Chagin 	return (old_stat_copyout(&buf, args->up));
2675c8919adSAlexander Leidinger }
2687f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
2695c8919adSAlexander Leidinger 
2705002a60fSMarcel Moolenaar struct l_statfs {
271297f61ccSDmitry Chagin 	l_long		f_type;
272297f61ccSDmitry Chagin 	l_long		f_bsize;
273297f61ccSDmitry Chagin 	l_long		f_blocks;
274297f61ccSDmitry Chagin 	l_long		f_bfree;
275297f61ccSDmitry Chagin 	l_long		f_bavail;
276297f61ccSDmitry Chagin 	l_long		f_files;
277297f61ccSDmitry Chagin 	l_long		f_ffree;
2785002a60fSMarcel Moolenaar 	l_fsid_t	f_fsid;
279297f61ccSDmitry Chagin 	l_long		f_namelen;
280e801ac78SEdward Tomasz Napierala 	l_long		f_frsize;
281e801ac78SEdward Tomasz Napierala 	l_long		f_flags;
282e801ac78SEdward Tomasz Napierala 	l_long		f_spare[4];
283c21dee17SSøren Schmidt };
284c21dee17SSøren Schmidt 
285dca60efcSMarcel Moolenaar #define	LINUX_CODA_SUPER_MAGIC	0x73757245L
286dca60efcSMarcel Moolenaar #define	LINUX_EXT2_SUPER_MAGIC	0xEF53L
287dca60efcSMarcel Moolenaar #define	LINUX_HPFS_SUPER_MAGIC	0xf995e849L
288dca60efcSMarcel Moolenaar #define	LINUX_ISOFS_SUPER_MAGIC	0x9660L
289dca60efcSMarcel Moolenaar #define	LINUX_MSDOS_SUPER_MAGIC	0x4d44L
290dca60efcSMarcel Moolenaar #define	LINUX_NCP_SUPER_MAGIC	0x564cL
291dca60efcSMarcel Moolenaar #define	LINUX_NFS_SUPER_MAGIC	0x6969L
292dca60efcSMarcel Moolenaar #define	LINUX_NTFS_SUPER_MAGIC	0x5346544EL
293dca60efcSMarcel Moolenaar #define	LINUX_PROC_SUPER_MAGIC	0x9fa0L
294dca60efcSMarcel Moolenaar #define	LINUX_UFS_SUPER_MAGIC	0x00011954L	/* XXX - UFS_MAGIC in Linux */
295dbaa9ebfSEd Maste #define	LINUX_ZFS_SUPER_MAGIC	0x2FC12FC1
296e83d253bSOlivier Houchard #define	LINUX_DEVFS_SUPER_MAGIC	0x1373L
2972166e4e0SDmitry Chagin #define	LINUX_SHMFS_MAGIC	0x01021994
298dca60efcSMarcel Moolenaar 
299dca60efcSMarcel Moolenaar static long
bsd_to_linux_ftype(const char * fstypename)300962cf420SMaxim Sobolev bsd_to_linux_ftype(const char *fstypename)
301dca60efcSMarcel Moolenaar {
302962cf420SMaxim Sobolev 	int i;
303962cf420SMaxim Sobolev 	static struct {const char *bsd_name; long linux_type;} b2l_tbl[] = {
304962cf420SMaxim Sobolev 		{"ufs",     LINUX_UFS_SUPER_MAGIC},
305dbaa9ebfSEd Maste 		{"zfs",     LINUX_ZFS_SUPER_MAGIC},
306962cf420SMaxim Sobolev 		{"cd9660",  LINUX_ISOFS_SUPER_MAGIC},
307962cf420SMaxim Sobolev 		{"nfs",     LINUX_NFS_SUPER_MAGIC},
308962cf420SMaxim Sobolev 		{"ext2fs",  LINUX_EXT2_SUPER_MAGIC},
309962cf420SMaxim Sobolev 		{"procfs",  LINUX_PROC_SUPER_MAGIC},
310962cf420SMaxim Sobolev 		{"msdosfs", LINUX_MSDOS_SUPER_MAGIC},
311962cf420SMaxim Sobolev 		{"ntfs",    LINUX_NTFS_SUPER_MAGIC},
312962cf420SMaxim Sobolev 		{"nwfs",    LINUX_NCP_SUPER_MAGIC},
313962cf420SMaxim Sobolev 		{"hpfs",    LINUX_HPFS_SUPER_MAGIC},
314962cf420SMaxim Sobolev 		{"coda",    LINUX_CODA_SUPER_MAGIC},
315e83d253bSOlivier Houchard 		{"devfs",   LINUX_DEVFS_SUPER_MAGIC},
3162166e4e0SDmitry Chagin 		{"tmpfs",   LINUX_SHMFS_MAGIC},
317962cf420SMaxim Sobolev 		{NULL,      0L}};
318dca60efcSMarcel Moolenaar 
319962cf420SMaxim Sobolev 	for (i = 0; b2l_tbl[i].bsd_name != NULL; i++)
320962cf420SMaxim Sobolev 		if (strcmp(b2l_tbl[i].bsd_name, fstypename) == 0)
321962cf420SMaxim Sobolev 			return (b2l_tbl[i].linux_type);
322dca60efcSMarcel Moolenaar 
323dca60efcSMarcel Moolenaar 	return (0L);
324dca60efcSMarcel Moolenaar }
325dca60efcSMarcel Moolenaar 
326525c9796SDmitry Chagin static int
bsd_to_linux_mnt_flags(int f_flags)3279922bccbSDmitry Chagin bsd_to_linux_mnt_flags(int f_flags)
3289922bccbSDmitry Chagin {
3299922bccbSDmitry Chagin 	int flags = LINUX_ST_VALID;
3309922bccbSDmitry Chagin 
3319922bccbSDmitry Chagin 	if (f_flags & MNT_RDONLY)
3329922bccbSDmitry Chagin 		flags |= LINUX_ST_RDONLY;
3339922bccbSDmitry Chagin 	if (f_flags & MNT_NOEXEC)
3349922bccbSDmitry Chagin 		flags |= LINUX_ST_NOEXEC;
3359922bccbSDmitry Chagin 	if (f_flags & MNT_NOSUID)
3369922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSUID;
3379922bccbSDmitry Chagin 	if (f_flags & MNT_NOATIME)
3389922bccbSDmitry Chagin 		flags |= LINUX_ST_NOATIME;
3399922bccbSDmitry Chagin 	if (f_flags & MNT_NOSYMFOLLOW)
3409922bccbSDmitry Chagin 		flags |= LINUX_ST_NOSYMFOLLOW;
3419922bccbSDmitry Chagin 	if (f_flags & MNT_SYNCHRONOUS)
3429922bccbSDmitry Chagin 		flags |= LINUX_ST_SYNCHRONOUS;
3439922bccbSDmitry Chagin 
3449922bccbSDmitry Chagin 	return (flags);
3459922bccbSDmitry Chagin }
3469922bccbSDmitry Chagin 
3479922bccbSDmitry Chagin static int
bsd_to_linux_statfs(struct statfs * bsd_statfs,struct l_statfs * linux_statfs)348d0cad55dSPawel Jakub Dawidek bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
349f7a25872SJohn Baldwin {
350953688e8SDmitry Chagin 
351525c9796SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
352953688e8SDmitry Chagin 	statfs_scale_blocks(bsd_statfs, INT32_MAX);
353525c9796SDmitry Chagin #endif
354f7a25872SJohn Baldwin 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
355f7a25872SJohn Baldwin 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
356f7a25872SJohn Baldwin 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
357f7a25872SJohn Baldwin 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
358f7a25872SJohn Baldwin 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
359953688e8SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
360953688e8SDmitry Chagin 	linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
361953688e8SDmitry Chagin 	linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
362953688e8SDmitry Chagin #else
363f7a25872SJohn Baldwin 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
364f7a25872SJohn Baldwin 	linux_statfs->f_files = bsd_statfs->f_files;
365953688e8SDmitry Chagin #endif
366f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
367f7a25872SJohn Baldwin 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
368f7a25872SJohn Baldwin 	linux_statfs->f_namelen = MAXNAMLEN;
369e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
3709922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
371e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
372525c9796SDmitry Chagin 
373525c9796SDmitry Chagin 	return (0);
374f7a25872SJohn Baldwin }
375f7a25872SJohn Baldwin 
376c21dee17SSøren Schmidt int
linux_statfs(struct thread * td,struct linux_statfs_args * args)377b40ce416SJulian Elischer linux_statfs(struct thread *td, struct linux_statfs_args *args)
378c21dee17SSøren Schmidt {
3795002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
3802f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
3812166e4e0SDmitry Chagin 	int error;
382d66a5066SPeter Wemm 
383a125ed50SMateusz Guzik 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
384a125ed50SMateusz Guzik 	error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
3852f304845SKonstantin Belousov 	if (error == 0)
3862f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
3872f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
3882f304845SKonstantin Belousov 	if (error != 0)
3892ad02313SDmitry Chagin 		return (error);
3907958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
391c21dee17SSøren Schmidt }
392c21dee17SSøren Schmidt 
3937f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
394835e5061SAlexander Leidinger static void
bsd_to_linux_statfs64(struct statfs * bsd_statfs,struct l_statfs64 * linux_statfs)395835e5061SAlexander Leidinger bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs)
396835e5061SAlexander Leidinger {
397835e5061SAlexander Leidinger 
398835e5061SAlexander Leidinger 	linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
399835e5061SAlexander Leidinger 	linux_statfs->f_bsize = bsd_statfs->f_bsize;
400835e5061SAlexander Leidinger 	linux_statfs->f_blocks = bsd_statfs->f_blocks;
401835e5061SAlexander Leidinger 	linux_statfs->f_bfree = bsd_statfs->f_bfree;
402835e5061SAlexander Leidinger 	linux_statfs->f_bavail = bsd_statfs->f_bavail;
403835e5061SAlexander Leidinger 	linux_statfs->f_ffree = bsd_statfs->f_ffree;
404835e5061SAlexander Leidinger 	linux_statfs->f_files = bsd_statfs->f_files;
405835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
406835e5061SAlexander Leidinger 	linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
407835e5061SAlexander Leidinger 	linux_statfs->f_namelen = MAXNAMLEN;
408e801ac78SEdward Tomasz Napierala 	linux_statfs->f_frsize = bsd_statfs->f_bsize;
4099922bccbSDmitry Chagin 	linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
410e801ac78SEdward Tomasz Napierala 	memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
411835e5061SAlexander Leidinger }
412835e5061SAlexander Leidinger 
413835e5061SAlexander Leidinger int
linux_statfs64(struct thread * td,struct linux_statfs64_args * args)414835e5061SAlexander Leidinger linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
415835e5061SAlexander Leidinger {
416835e5061SAlexander Leidinger 	struct l_statfs64 linux_statfs;
4172f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
418835e5061SAlexander Leidinger 	int error;
419835e5061SAlexander Leidinger 
4203ab85269SDavid Malone 	if (args->bufsize != sizeof(struct l_statfs64))
421340f4a8dSEd Maste 		return (EINVAL);
4223ab85269SDavid Malone 
423a125ed50SMateusz Guzik 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
424a125ed50SMateusz Guzik 	error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
4252f304845SKonstantin Belousov 	if (error == 0)
4262f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4272f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4282f304845SKonstantin Belousov 	if (error != 0)
429835e5061SAlexander Leidinger 		return (error);
4307958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
431835e5061SAlexander Leidinger }
43299546279SDmitry Chagin 
43399546279SDmitry Chagin int
linux_fstatfs64(struct thread * td,struct linux_fstatfs64_args * args)43499546279SDmitry Chagin linux_fstatfs64(struct thread *td, struct linux_fstatfs64_args *args)
43599546279SDmitry Chagin {
43699546279SDmitry Chagin 	struct l_statfs64 linux_statfs;
4372f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
43899546279SDmitry Chagin 	int error;
43999546279SDmitry Chagin 
44099546279SDmitry Chagin 	if (args->bufsize != sizeof(struct l_statfs64))
44199546279SDmitry Chagin 		return (EINVAL);
44299546279SDmitry Chagin 
4432f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4442f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
4452f304845SKonstantin Belousov 	if (error == 0)
4462f304845SKonstantin Belousov 		bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
4472f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4482f304845SKonstantin Belousov 	if (error != 0)
4492f304845SKonstantin Belousov 		return (error);
45099546279SDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
45199546279SDmitry Chagin }
4527f8f1d7fSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
453835e5061SAlexander Leidinger 
454c21dee17SSøren Schmidt int
linux_fstatfs(struct thread * td,struct linux_fstatfs_args * args)455b40ce416SJulian Elischer linux_fstatfs(struct thread *td, struct linux_fstatfs_args *args)
456c21dee17SSøren Schmidt {
4575002a60fSMarcel Moolenaar 	struct l_statfs linux_statfs;
4582f304845SKonstantin Belousov 	struct statfs *bsd_statfs;
459c21dee17SSøren Schmidt 	int error;
460c21dee17SSøren Schmidt 
4612f304845SKonstantin Belousov 	bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4622f304845SKonstantin Belousov 	error = kern_fstatfs(td, args->fd, bsd_statfs);
4632f304845SKonstantin Belousov 	if (error == 0)
4642f304845SKonstantin Belousov 		error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
4652f304845SKonstantin Belousov 	free(bsd_statfs, M_STATFS);
4662f304845SKonstantin Belousov 	if (error != 0)
4672ad02313SDmitry Chagin 		return (error);
4687958a34cSDmitry Chagin 	return (copyout(&linux_statfs, args->buf, sizeof(linux_statfs)));
469c21dee17SSøren Schmidt }
470408da119SMarcel Moolenaar 
4715002a60fSMarcel Moolenaar struct l_ustat
472408da119SMarcel Moolenaar {
4735002a60fSMarcel Moolenaar 	l_daddr_t	f_tfree;
4745002a60fSMarcel Moolenaar 	l_ino_t		f_tinode;
4755002a60fSMarcel Moolenaar 	char		f_fname[6];
4765002a60fSMarcel Moolenaar 	char		f_fpack[6];
4775002a60fSMarcel Moolenaar };
4785002a60fSMarcel Moolenaar 
479931e2a1aSEd Maste #ifdef LINUX_LEGACY_SYSCALLS
4805002a60fSMarcel Moolenaar int
linux_ustat(struct thread * td,struct linux_ustat_args * args)481b40ce416SJulian Elischer linux_ustat(struct thread *td, struct linux_ustat_args *args)
4825002a60fSMarcel Moolenaar {
4831e247cc2SPoul-Henning Kamp 
4841e247cc2SPoul-Henning Kamp 	return (EOPNOTSUPP);
485408da119SMarcel Moolenaar }
486931e2a1aSEd Maste #endif
4875002a60fSMarcel Moolenaar 
488*3cf834d0SEd Maste /*
489*3cf834d0SEd Maste  * Convert Linux stat flags to BSD flags.  Return value indicates successful
490*3cf834d0SEd Maste  * conversion (no unknown flags).
491*3cf834d0SEd Maste  */
492*3cf834d0SEd Maste static bool
linux_to_bsd_stat_flags(int linux_flags,int * out_flags)493*3cf834d0SEd Maste linux_to_bsd_stat_flags(int linux_flags, int *out_flags)
494*3cf834d0SEd Maste {
495*3cf834d0SEd Maste 	int flags, unsupported;
496*3cf834d0SEd Maste 
497*3cf834d0SEd Maste 	unsupported = linux_flags & ~(LINUX_AT_SYMLINK_NOFOLLOW |
498*3cf834d0SEd Maste 	    LINUX_AT_EMPTY_PATH | LINUX_AT_NO_AUTOMOUNT);
499*3cf834d0SEd Maste 	if (unsupported != 0) {
500*3cf834d0SEd Maste 		*out_flags = unsupported;
501*3cf834d0SEd Maste 		return (false);
502*3cf834d0SEd Maste 	}
503*3cf834d0SEd Maste 
504*3cf834d0SEd Maste 	flags = 0;
505*3cf834d0SEd Maste 	if (linux_flags & LINUX_AT_SYMLINK_NOFOLLOW)
506*3cf834d0SEd Maste 		flags |= AT_SYMLINK_NOFOLLOW;
507*3cf834d0SEd Maste 	if (linux_flags & LINUX_AT_EMPTY_PATH)
508*3cf834d0SEd Maste 		flags |= AT_EMPTY_PATH;
509*3cf834d0SEd Maste 	*out_flags = flags;
510*3cf834d0SEd Maste 	return (true);
511*3cf834d0SEd Maste }
512*3cf834d0SEd Maste 
5131997c537SDavid E. O'Brien #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
5145002a60fSMarcel Moolenaar 
5155002a60fSMarcel Moolenaar static int
stat64_copyout(struct stat * buf,void * ubuf)5165002a60fSMarcel Moolenaar stat64_copyout(struct stat *buf, void *ubuf)
5175002a60fSMarcel Moolenaar {
5185002a60fSMarcel Moolenaar 	struct l_stat64 lbuf;
5195002a60fSMarcel Moolenaar 
5205002a60fSMarcel Moolenaar 	bzero(&lbuf, sizeof(lbuf));
521166e2e5aSDmitry Chagin 	lbuf.st_dev = linux_new_encode_dev(buf->st_dev);
5225002a60fSMarcel Moolenaar 	lbuf.st_ino = buf->st_ino;
5235002a60fSMarcel Moolenaar 	lbuf.st_mode = buf->st_mode;
5245002a60fSMarcel Moolenaar 	lbuf.st_nlink = buf->st_nlink;
5255002a60fSMarcel Moolenaar 	lbuf.st_uid = buf->st_uid;
5265002a60fSMarcel Moolenaar 	lbuf.st_gid = buf->st_gid;
527166e2e5aSDmitry Chagin 	lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
5285002a60fSMarcel Moolenaar 	lbuf.st_size = buf->st_size;
529510ea843SEd Schouten 	lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
530510ea843SEd Schouten 	lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
531510ea843SEd Schouten 	lbuf.st_mtim.tv_sec = buf->st_mtim.tv_sec;
532510ea843SEd Schouten 	lbuf.st_mtim.tv_nsec = buf->st_mtim.tv_nsec;
533510ea843SEd Schouten 	lbuf.st_ctim.tv_sec = buf->st_ctim.tv_sec;
534510ea843SEd Schouten 	lbuf.st_ctim.tv_nsec = buf->st_ctim.tv_nsec;
5355002a60fSMarcel Moolenaar 	lbuf.st_blksize = buf->st_blksize;
5365002a60fSMarcel Moolenaar 	lbuf.st_blocks = buf->st_blocks;
5375002a60fSMarcel Moolenaar 
5385002a60fSMarcel Moolenaar 	/*
5395002a60fSMarcel Moolenaar 	 * The __st_ino field makes all the difference. In the Linux kernel
5405002a60fSMarcel Moolenaar 	 * it is conditionally compiled based on STAT64_HAS_BROKEN_ST_INO,
5415002a60fSMarcel Moolenaar 	 * but without the assignment to __st_ino the runtime linker refuses
5425002a60fSMarcel Moolenaar 	 * to mmap(2) any shared libraries. I guess it's broken alright :-)
5435002a60fSMarcel Moolenaar 	 */
5445002a60fSMarcel Moolenaar 	lbuf.__st_ino = buf->st_ino;
5455002a60fSMarcel Moolenaar 
5465002a60fSMarcel Moolenaar 	return (copyout(&lbuf, ubuf, sizeof(lbuf)));
5475002a60fSMarcel Moolenaar }
5485002a60fSMarcel Moolenaar 
5495002a60fSMarcel Moolenaar int
linux_stat64(struct thread * td,struct linux_stat64_args * args)550b40ce416SJulian Elischer linux_stat64(struct thread *td, struct linux_stat64_args *args)
5515002a60fSMarcel Moolenaar {
5525002a60fSMarcel Moolenaar 	struct stat buf;
553f7a25872SJohn Baldwin 	int error;
5545002a60fSMarcel Moolenaar 
555a125ed50SMateusz Guzik 	error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
5565002a60fSMarcel Moolenaar 	if (error)
5575002a60fSMarcel Moolenaar 		return (error);
5585002a60fSMarcel Moolenaar 	return (stat64_copyout(&buf, args->statbuf));
5595002a60fSMarcel Moolenaar }
5605002a60fSMarcel Moolenaar 
5615002a60fSMarcel Moolenaar int
linux_lstat64(struct thread * td,struct linux_lstat64_args * args)562b40ce416SJulian Elischer linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
5635002a60fSMarcel Moolenaar {
5645002a60fSMarcel Moolenaar 	struct stat sb;
565f7a25872SJohn Baldwin 	int error;
5665002a60fSMarcel Moolenaar 
567a125ed50SMateusz Guzik 	error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
5685002a60fSMarcel Moolenaar 	if (error)
5695002a60fSMarcel Moolenaar 		return (error);
5705002a60fSMarcel Moolenaar 	return (stat64_copyout(&sb, args->statbuf));
5715002a60fSMarcel Moolenaar }
5725002a60fSMarcel Moolenaar 
5735002a60fSMarcel Moolenaar int
linux_fstat64(struct thread * td,struct linux_fstat64_args * args)574b40ce416SJulian Elischer linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
5755002a60fSMarcel Moolenaar {
5765002a60fSMarcel Moolenaar 	struct stat buf;
5775002a60fSMarcel Moolenaar 	int error;
5785002a60fSMarcel Moolenaar 
579994ed958SDmitry Chagin 	error = linux_kern_fstat(td, args->fd, &buf);
5805002a60fSMarcel Moolenaar 	if (!error)
5815002a60fSMarcel Moolenaar 		error = stat64_copyout(&buf, args->statbuf);
5825002a60fSMarcel Moolenaar 
5835002a60fSMarcel Moolenaar 	return (error);
5845002a60fSMarcel Moolenaar }
5855002a60fSMarcel Moolenaar 
58648b05c3fSKonstantin Belousov int
linux_fstatat64(struct thread * td,struct linux_fstatat64_args * args)58748b05c3fSKonstantin Belousov linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
58848b05c3fSKonstantin Belousov {
589*3cf834d0SEd Maste 	int error, dfd, flags;
59048b05c3fSKonstantin Belousov 	struct stat buf;
59148b05c3fSKonstantin Belousov 
592*3cf834d0SEd Maste 	if (!linux_to_bsd_stat_flags(args->flag, &flags)) {
593*3cf834d0SEd Maste 		linux_msg(td, "fstatat64 unsupported flags 0x%x", flags);
59448b05c3fSKonstantin Belousov 		return (EINVAL);
5954b45c2bbSEdward Tomasz Napierala 	}
59648b05c3fSKonstantin Belousov 
59748b05c3fSKonstantin Belousov 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
598*3cf834d0SEd Maste 	error = linux_kern_statat(td, flags, dfd, args->pathname,
599a125ed50SMateusz Guzik 	    UIO_USERSPACE, &buf);
600a125ed50SMateusz Guzik 	if (error == 0)
601a125ed50SMateusz Guzik 		error = stat64_copyout(&buf, args->statbuf);
60248b05c3fSKonstantin Belousov 
60348b05c3fSKonstantin Belousov 	return (error);
60448b05c3fSKonstantin Belousov }
60548b05c3fSKonstantin Belousov 
606606bcc17SDmitry Chagin #else /* __amd64__ && !COMPAT_LINUX32 */
607606bcc17SDmitry Chagin 
608606bcc17SDmitry Chagin int
linux_newfstatat(struct thread * td,struct linux_newfstatat_args * args)609606bcc17SDmitry Chagin linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
610606bcc17SDmitry Chagin {
611*3cf834d0SEd Maste 	int error, dfd, flags;
612606bcc17SDmitry Chagin 	struct stat buf;
613606bcc17SDmitry Chagin 
614*3cf834d0SEd Maste 	if (!linux_to_bsd_stat_flags(args->flag, &flags)) {
615*3cf834d0SEd Maste 		linux_msg(td, "fstatat unsupported flags 0x%x", flags);
616606bcc17SDmitry Chagin 		return (EINVAL);
6174b45c2bbSEdward Tomasz Napierala 	}
6184b45c2bbSEdward Tomasz Napierala 
619606bcc17SDmitry Chagin 	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
620*3cf834d0SEd Maste 	error = linux_kern_statat(td, flags, dfd, args->pathname,
621a125ed50SMateusz Guzik 	    UIO_USERSPACE, &buf);
622606bcc17SDmitry Chagin 	if (error == 0)
623606bcc17SDmitry Chagin 		error = newstat_copyout(&buf, args->statbuf);
624606bcc17SDmitry Chagin 
625606bcc17SDmitry Chagin 	return (error);
626606bcc17SDmitry Chagin }
627606bcc17SDmitry Chagin 
6281997c537SDavid E. O'Brien #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
6299802eb9eSDmitry Chagin 
6309802eb9eSDmitry Chagin int
linux_syncfs(struct thread * td,struct linux_syncfs_args * args)6319802eb9eSDmitry Chagin linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
6329802eb9eSDmitry Chagin {
6339802eb9eSDmitry Chagin 	struct mount *mp;
6349802eb9eSDmitry Chagin 	struct vnode *vp;
6359802eb9eSDmitry Chagin 	int error, save;
6369802eb9eSDmitry Chagin 
637cbd92ce6SMatt Macy 	error = fgetvp(td, args->fd, &cap_fsync_rights, &vp);
6389802eb9eSDmitry Chagin 	if (error != 0)
6399802eb9eSDmitry Chagin 		/*
6409802eb9eSDmitry Chagin 		 * Linux syncfs() returns only EBADF, however fgetvp()
6419802eb9eSDmitry Chagin 		 * can return EINVAL in case of file descriptor does
6429802eb9eSDmitry Chagin 		 * not represent a vnode. XXX.
6439802eb9eSDmitry Chagin 		 */
6449802eb9eSDmitry Chagin 		return (error);
6459802eb9eSDmitry Chagin 
6469802eb9eSDmitry Chagin 	mp = vp->v_mount;
6479802eb9eSDmitry Chagin 	mtx_lock(&mountlist_mtx);
6489802eb9eSDmitry Chagin 	error = vfs_busy(mp, MBF_MNTLSTLOCK);
6499802eb9eSDmitry Chagin 	if (error != 0) {
6509802eb9eSDmitry Chagin 		/* See comment above. */
6519802eb9eSDmitry Chagin 		mtx_unlock(&mountlist_mtx);
6529802eb9eSDmitry Chagin 		goto out;
6539802eb9eSDmitry Chagin 	}
6549802eb9eSDmitry Chagin 	if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
6559802eb9eSDmitry Chagin 	    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
6569802eb9eSDmitry Chagin 		save = curthread_pflags_set(TDP_SYNCIO);
657c8b3463dSMateusz Guzik 		vfs_periodic(mp, MNT_NOWAIT);
6589802eb9eSDmitry Chagin 		VFS_SYNC(mp, MNT_NOWAIT);
6599802eb9eSDmitry Chagin 		curthread_pflags_restore(save);
6609802eb9eSDmitry Chagin 		vn_finished_write(mp);
6619802eb9eSDmitry Chagin 	}
6629802eb9eSDmitry Chagin 	vfs_unbusy(mp);
6639802eb9eSDmitry Chagin 
6649802eb9eSDmitry Chagin  out:
6659802eb9eSDmitry Chagin 	vrele(vp);
6669802eb9eSDmitry Chagin 	return (error);
6679802eb9eSDmitry Chagin }
6682362ad45SPhilippe Michaud-Boudreault 
669e9204c5cSDmitry Chagin static int
statx_copyout(struct stat * buf,void * ubuf)670e9204c5cSDmitry Chagin statx_copyout(struct stat *buf, void *ubuf)
671e9204c5cSDmitry Chagin {
672e9204c5cSDmitry Chagin 	struct l_statx tbuf;
673e9204c5cSDmitry Chagin 
674e9204c5cSDmitry Chagin 	bzero(&tbuf, sizeof(tbuf));
675e9204c5cSDmitry Chagin 	tbuf.stx_mask = STATX_ALL;
676e9204c5cSDmitry Chagin 	tbuf.stx_blksize = buf->st_blksize;
677e9204c5cSDmitry Chagin 	tbuf.stx_attributes = 0;
678e9204c5cSDmitry Chagin 	tbuf.stx_nlink = buf->st_nlink;
679e9204c5cSDmitry Chagin 	tbuf.stx_uid = buf->st_uid;
680e9204c5cSDmitry Chagin 	tbuf.stx_gid = buf->st_gid;
681e9204c5cSDmitry Chagin 	tbuf.stx_mode = buf->st_mode;
682e9204c5cSDmitry Chagin 	tbuf.stx_ino = buf->st_ino;
683e9204c5cSDmitry Chagin 	tbuf.stx_size = buf->st_size;
684e9204c5cSDmitry Chagin 	tbuf.stx_blocks = buf->st_blocks;
685e9204c5cSDmitry Chagin 
686e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
687e9204c5cSDmitry Chagin 	tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
688e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
689e9204c5cSDmitry Chagin 	tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
690e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
691e9204c5cSDmitry Chagin 	tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
692e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
693e9204c5cSDmitry Chagin 	tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
694166e2e5aSDmitry Chagin 	tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev);
695166e2e5aSDmitry Chagin 	tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev);
696166e2e5aSDmitry Chagin 	tbuf.stx_dev_major = linux_encode_major(buf->st_dev);
697166e2e5aSDmitry Chagin 	tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev);
698e9204c5cSDmitry Chagin 
699e9204c5cSDmitry Chagin 	return (copyout(&tbuf, ubuf, sizeof(tbuf)));
700e9204c5cSDmitry Chagin }
701e9204c5cSDmitry Chagin 
7022362ad45SPhilippe Michaud-Boudreault int
linux_statx(struct thread * td,struct linux_statx_args * args)7032362ad45SPhilippe Michaud-Boudreault linux_statx(struct thread *td, struct linux_statx_args *args)
7042362ad45SPhilippe Michaud-Boudreault {
705*3cf834d0SEd Maste 	int error, dirfd, flags;
7062362ad45SPhilippe Michaud-Boudreault 	struct stat buf;
7072362ad45SPhilippe Michaud-Boudreault 
708*3cf834d0SEd Maste 	if (!linux_to_bsd_stat_flags(args->flags, &flags)) {
709*3cf834d0SEd Maste 		linux_msg(td, "statx unsupported flags 0x%x", flags);
7102362ad45SPhilippe Michaud-Boudreault 		return (EINVAL);
7112362ad45SPhilippe Michaud-Boudreault 	}
7122362ad45SPhilippe Michaud-Boudreault 
7132362ad45SPhilippe Michaud-Boudreault 	dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
7142362ad45SPhilippe Michaud-Boudreault 	error = linux_kern_statat(td, flags, dirfd, args->pathname,
7152362ad45SPhilippe Michaud-Boudreault 	    UIO_USERSPACE, &buf);
7162362ad45SPhilippe Michaud-Boudreault 	if (error == 0)
7172362ad45SPhilippe Michaud-Boudreault 		error = statx_copyout(&buf, args->statxbuf);
7182362ad45SPhilippe Michaud-Boudreault 
7192362ad45SPhilippe Michaud-Boudreault 	return (error);
7202362ad45SPhilippe Michaud-Boudreault }
721