summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2016-01-09 15:37:10 +0000
committerdchagin <dchagin@FreeBSD.org>2016-01-09 15:37:10 +0000
commit027f6631c01acb6b110e8175335f323e7f8567fb (patch)
treeea70d441be85d0d76f0391ba8a7d2e6b9adde8ba /sys/compat
parenta82405c150fc94a53e9856d1deea507d806e12f3 (diff)
downloadFreeBSD-src-027f6631c01acb6b110e8175335f323e7f8567fb.zip
FreeBSD-src-027f6631c01acb6b110e8175335f323e7f8567fb.tar.gz
MFC r283401:
Implement prlimit64() system call.
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/linux/linux_misc.c73
-rw-r--r--sys/compat/linux/linux_misc.h1
2 files changed, 74 insertions, 0 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 17a153b..e128bb4 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -2032,6 +2032,79 @@ linux_sched_setaffinity(struct thread *td,
return (sys_cpuset_setaffinity(td, &csa));
}
+struct linux_rlimit64 {
+ uint64_t rlim_cur;
+ uint64_t rlim_max;
+};
+
+int
+linux_prlimit64(struct thread *td, struct linux_prlimit64_args *args)
+{
+ struct rlimit rlim, nrlim;
+ struct linux_rlimit64 lrlim;
+ struct proc *p;
+ u_int which;
+ int flags;
+ int error;
+
+#ifdef DEBUG
+ if (ldebug(prlimit64))
+ printf(ARGS(prlimit64, "%d, %d, %p, %p"), args->pid,
+ args->resource, (void *)args->new, (void *)args->old);
+#endif
+
+ if (args->resource >= LINUX_RLIM_NLIMITS)
+ return (EINVAL);
+
+ which = linux_to_bsd_resource[args->resource];
+ if (which == -1)
+ return (EINVAL);
+
+ if (args->new != NULL) {
+ /*
+ * Note. Unlike FreeBSD where rlim is signed 64-bit Linux
+ * rlim is unsigned 64-bit. FreeBSD treats negative limits
+ * as INFINITY so we do not need a conversion even.
+ */
+ error = copyin(args->new, &nrlim, sizeof(nrlim));
+ if (error != 0)
+ return (error);
+ }
+
+ flags = PGET_HOLD | PGET_NOTWEXIT;
+ if (args->new != NULL)
+ flags |= PGET_CANDEBUG;
+ else
+ flags |= PGET_CANSEE;
+ error = pget(args->pid, flags, &p);
+ if (error != 0)
+ return (error);
+
+ if (args->old != NULL) {
+ PROC_LOCK(p);
+ lim_rlimit(p, which, &rlim);
+ PROC_UNLOCK(p);
+ if (rlim.rlim_cur == RLIM_INFINITY)
+ lrlim.rlim_cur = LINUX_RLIM_INFINITY;
+ else
+ lrlim.rlim_cur = rlim.rlim_cur;
+ if (rlim.rlim_max == RLIM_INFINITY)
+ lrlim.rlim_max = LINUX_RLIM_INFINITY;
+ else
+ lrlim.rlim_max = rlim.rlim_max;
+ error = copyout(&lrlim, args->old, sizeof(lrlim));
+ if (error != 0)
+ goto out;
+ }
+
+ if (args->new != NULL)
+ error = kern_proc_setrlimit(td, p, which, &nrlim);
+
+ out:
+ PRELE(p);
+ return (error);
+}
+
int
linux_sched_rr_get_interval(struct thread *td,
struct linux_sched_rr_get_interval_args *uap)
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index ccbcd4d..454e92d 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -128,6 +128,7 @@ extern int stclohz;
#define LINUX_P_PID 1
#define LINUX_P_PGID 2
+#define LINUX_RLIM_INFINITY (~0UL)
int linux_common_wait(struct thread *td, int pid, int *status,
int options, struct rusage *ru);
OpenPOWER on IntegriCloud