Date: Sat, 31 Jan 2015 02:59:34 -0600 From: "Andrew Wilcox" <AWilcox@Wilcox-Tech.com> To: "'Jilles Tjoelker'" <jilles@stack.nl>, <freebsd-arch@FreeBSD.org> Subject: RFC: Added utimensat(2) to Linuxulator (was RE: Current status of utimensat(2)) Message-ID: <004f01d03d34$3caed970$b60c8c50$@Wilcox-Tech.com>
index | next in thread | raw e-mail
[-- Attachment #1 --] Jilles Tjoelker sent 29 January 2015 17:06: > I committed utimensat/futimens to head. I also made a start at Linuxulator > utimensat, see attached patch. Please complete it and test it. > > -- > Jilles Tjoelker I have merged some of the things Jilles' patch does into the patch I was already working on. I have tested a number of corner cases with it, and compared the results to a running Linux system. I have also run software which all use utimensat(2) on Linux, such as recent tar(1), touch(1), and Python 3.3's shutil library, inside the Linuxulator with this patch applied. I have found this patch's behaviour to be correct in these tests. Please let me know of any comments or issues. I will be additionally trying to merge this into dchagin's lemul branch, but that discussion will take place on Phabricator (and will involve testing on amd64-native Linuxulator, which I have not yet done). Regards, Andrew -- Andrew Wilcox, C/C++/Python developer, kernel hacker Blog: http://blog.foxkit.us/ WWW: http://foxkit.us/ GitHub: https://github.com/awilfox [-- Attachment #2 --] Index: sys/amd64/linux32/linux32_dummy.c =================================================================== --- sys/amd64/linux32/linux32_dummy.c (revision 277871) +++ sys/amd64/linux32/linux32_dummy.c (working copy) @@ -111,7 +111,6 @@ DUMMY(getcpu); DUMMY(epoll_pwait); /* linux 2.6.22: */ -DUMMY(utimensat); DUMMY(signalfd); DUMMY(timerfd_create); DUMMY(eventfd); Index: sys/amd64/linux32/linux32_proto.h =================================================================== --- sys/amd64/linux32/linux32_proto.h (revision 277871) +++ sys/amd64/linux32/linux32_proto.h (working copy) @@ -1017,7 +1017,10 @@ register_t dummy; }; struct linux_utimensat_args { - register_t dummy; + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_signalfd_args { register_t dummy; @@ -1652,7 +1655,7 @@ #define LINUX_SYS_AUE_linux_move_pages AUE_NULL #define LINUX_SYS_AUE_linux_getcpu AUE_NULL #define LINUX_SYS_AUE_linux_epoll_pwait AUE_NULL -#define LINUX_SYS_AUE_linux_utimensat AUE_NULL +#define LINUX_SYS_AUE_linux_utimensat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_signalfd AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_create AUE_NULL #define LINUX_SYS_AUE_linux_eventfd AUE_NULL Index: sys/amd64/linux32/linux32_sysent.c =================================================================== --- sys/amd64/linux32/linux32_sysent.c (revision 277871) +++ sys/amd64/linux32/linux32_sysent.c (working copy) @@ -339,7 +339,7 @@ { 0, (sy_call_t *)linux_move_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 317 = linux_move_pages */ { 0, (sy_call_t *)linux_getcpu, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 318 = linux_getcpu */ { 0, (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 319 = linux_epoll_pwait */ - { 0, (sy_call_t *)linux_utimensat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ + { AS(linux_utimensat_args), (sy_call_t *)linux_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ { 0, (sy_call_t *)linux_signalfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = linux_signalfd */ { 0, (sy_call_t *)linux_timerfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 322 = linux_timerfd_create */ { 0, (sy_call_t *)linux_eventfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 323 = linux_eventfd */ Index: sys/amd64/linux32/linux32_systrace_args.c =================================================================== --- sys/amd64/linux32/linux32_systrace_args.c (revision 277871) +++ sys/amd64/linux32/linux32_systrace_args.c (working copy) @@ -2130,7 +2130,12 @@ } /* linux_utimensat */ case 320: { - *n_args = 0; + struct linux_utimensat_args *p = params; + iarg[0] = p->dfd; /* l_int */ + uarg[1] = (intptr_t) p->pathname; /* const char * */ + uarg[2] = (intptr_t) p->times; /* const struct l_timespec * */ + iarg[3] = p->flags; /* l_int */ + *n_args = 4; break; } /* linux_signalfd */ @@ -5395,6 +5400,22 @@ break; /* linux_utimensat */ case 320: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "const char *"; + break; + case 2: + p = "const struct l_timespec *"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; break; /* linux_signalfd */ case 321: @@ -6684,6 +6705,9 @@ case 319: /* linux_utimensat */ case 320: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_signalfd */ case 321: /* linux_timerfd_create */ Index: sys/amd64/linux32/syscalls.master =================================================================== --- sys/amd64/linux32/syscalls.master (revision 277871) +++ sys/amd64/linux32/syscalls.master (working copy) @@ -524,7 +524,8 @@ 318 AUE_NULL STD { int linux_getcpu(void); } 319 AUE_NULL STD { int linux_epoll_pwait(void); } ; linux 2.6.22: -320 AUE_NULL STD { int linux_utimensat(void); } +320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \ + const struct l_timespec *times, l_int flags); } 321 AUE_NULL STD { int linux_signalfd(void); } 322 AUE_NULL STD { int linux_timerfd_create(void); } 323 AUE_NULL STD { int linux_eventfd(void); } Index: sys/compat/linux/linux_misc.c =================================================================== --- sys/compat/linux/linux_misc.c (revision 277871) +++ sys/compat/linux/linux_misc.c (working copy) @@ -816,6 +816,89 @@ return (error); } +int +linux_utimensat(struct thread *td, struct linux_utimensat_args *args) +{ + struct l_timespec l_times[2]; + struct timespec times[2], *timesp = NULL; + char *path = NULL; + int error, dfd, flags = 0; + + dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd; + +#ifdef DEBUG + if (ldebug(utimensat)) + printf(ARGS(utimensat, "%d, *"), dfd); +#endif + + if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW) + return (EINVAL); + + if (args->times != NULL) { + if ((error = copyin(args->times, l_times, sizeof l_times))) + return (error); + + if (l_times[0].tv_nsec > 999999999 || + l_times[1].tv_nsec > 999999999) + return (EINVAL); + + times[0].tv_sec = l_times[0].tv_sec; + switch (l_times[0].tv_nsec) + { + case LINUX_UTIME_OMIT: + times[0].tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times[0].tv_nsec = UTIME_NOW; + break; + default: + times[0].tv_nsec = l_times[0].tv_nsec; + } + + times[1].tv_sec = l_times[1].tv_sec; + switch (l_times[1].tv_nsec) + { + case LINUX_UTIME_OMIT: + times[1].tv_nsec = UTIME_OMIT; + break; + case LINUX_UTIME_NOW: + times[1].tv_nsec = UTIME_NOW; + break; + default: + times[1].tv_nsec = l_times[1].tv_nsec; + } + timesp = times; + } + + if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) { + /* This breaks POSIX, but is what the Linux kernel does + * _on purpose_ (documented in the man page for utimensat(2)), + * so we must follow that behaviour. */ + return (0); + } + + if (args->pathname != NULL) + LCONVPATHEXIST_AT(td, args->pathname, &path, dfd); + else { + if (args->flags != 0) + return (EINVAL); + } + + if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW) + flags |= AT_SYMLINK_NOFOLLOW; + + if (path == NULL) + error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE); + else + { + error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp, + UIO_SYSSPACE, flags); + LFREEPATH(path); + } + + return (error); +} + int linux_futimesat(struct thread *td, struct linux_futimesat_args *args) { Index: sys/compat/linux/linux_misc.h =================================================================== --- sys/compat/linux/linux_misc.h (revision 277871) +++ sys/compat/linux/linux_misc.h (working copy) @@ -113,6 +113,9 @@ #define LINUX_CLOCK_REALTIME_HR 4 #define LINUX_CLOCK_MONOTONIC_HR 5 +#define LINUX_UTIME_NOW 0x3FFFFFFF +#define LINUX_UTIME_OMIT 0x3FFFFFFE + extern int stclohz; #define __WCLONE 0x80000000 Index: sys/i386/linux/linux_dummy.c =================================================================== --- sys/i386/linux/linux_dummy.c (revision 277871) +++ sys/i386/linux/linux_dummy.c (working copy) @@ -107,7 +107,6 @@ DUMMY(getcpu); DUMMY(epoll_pwait); /* linux 2.6.22: */ -DUMMY(utimensat); DUMMY(signalfd); DUMMY(timerfd_create); DUMMY(eventfd); Index: sys/i386/linux/linux_proto.h =================================================================== --- sys/i386/linux/linux_proto.h (revision 277871) +++ sys/i386/linux/linux_proto.h (working copy) @@ -1031,7 +1031,10 @@ register_t dummy; }; struct linux_utimensat_args { - register_t dummy; + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(const char *)]; const char * pathname; char pathname_r_[PADR_(const char *)]; + char times_l_[PADL_(const struct l_timespec *)]; const struct l_timespec * times; char times_r_[PADR_(const struct l_timespec *)]; + char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)]; }; struct linux_signalfd_args { register_t dummy; @@ -1668,7 +1671,7 @@ #define LINUX_SYS_AUE_linux_move_pages AUE_NULL #define LINUX_SYS_AUE_linux_getcpu AUE_NULL #define LINUX_SYS_AUE_linux_epoll_pwait AUE_NULL -#define LINUX_SYS_AUE_linux_utimensat AUE_NULL +#define LINUX_SYS_AUE_linux_utimensat AUE_FUTIMESAT #define LINUX_SYS_AUE_linux_signalfd AUE_NULL #define LINUX_SYS_AUE_linux_timerfd_create AUE_NULL #define LINUX_SYS_AUE_linux_eventfd AUE_NULL Index: sys/i386/linux/linux_sysent.c =================================================================== --- sys/i386/linux/linux_sysent.c (revision 277871) +++ sys/i386/linux/linux_sysent.c (working copy) @@ -338,7 +338,7 @@ { 0, (sy_call_t *)linux_move_pages, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 317 = linux_move_pages */ { 0, (sy_call_t *)linux_getcpu, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 318 = linux_getcpu */ { 0, (sy_call_t *)linux_epoll_pwait, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 319 = linux_epoll_pwait */ - { 0, (sy_call_t *)linux_utimensat, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ + { AS(linux_utimensat_args), (sy_call_t *)linux_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 320 = linux_utimensat */ { 0, (sy_call_t *)linux_signalfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 321 = linux_signalfd */ { 0, (sy_call_t *)linux_timerfd_create, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 322 = linux_timerfd_create */ { 0, (sy_call_t *)linux_eventfd, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 323 = linux_eventfd */ Index: sys/i386/linux/linux_systrace_args.c =================================================================== --- sys/i386/linux/linux_systrace_args.c (revision 277871) +++ sys/i386/linux/linux_systrace_args.c (working copy) @@ -2206,7 +2206,12 @@ } /* linux_utimensat */ case 320: { - *n_args = 0; + struct linux_utimensat_args *p = params; + iarg[0] = p->dfd; /* l_int */ + uarg[1] = (intptr_t) p->pathname; /* const char * */ + uarg[2] = (intptr_t) p->times; /* const struct l_timespec * */ + iarg[3] = p->flags; /* l_int */ + *n_args = 4; break; } /* linux_signalfd */ @@ -5626,6 +5631,22 @@ break; /* linux_utimensat */ case 320: + switch(ndx) { + case 0: + p = "l_int"; + break; + case 1: + p = "const char *"; + break; + case 2: + p = "const struct l_timespec *"; + break; + case 3: + p = "l_int"; + break; + default: + break; + }; break; /* linux_signalfd */ case 321: @@ -6962,6 +6983,9 @@ case 319: /* linux_utimensat */ case 320: + if (ndx == 0 || ndx == 1) + p = "int"; + break; /* linux_signalfd */ case 321: /* linux_timerfd_create */ Index: sys/i386/linux/syscalls.master =================================================================== --- sys/i386/linux/syscalls.master (revision 277871) +++ sys/i386/linux/syscalls.master (working copy) @@ -532,7 +532,8 @@ 318 AUE_NULL STD { int linux_getcpu(void); } 319 AUE_NULL STD { int linux_epoll_pwait(void); } ; linux 2.6.22: -320 AUE_NULL STD { int linux_utimensat(void); } +320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \ + const struct l_timespec *times, l_int flags); } 321 AUE_NULL STD { int linux_signalfd(void); } 322 AUE_NULL STD { int linux_timerfd_create(void); } 323 AUE_NULL STD { int linux_eventfd(void); }home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?004f01d03d34$3caed970$b60c8c50$>
