← Documents Documentation/userspace-api/unshare.rst GitHub 원문 ↗

Linux 6.18.37 · 사용자 공간 API

unshare 시스템 호출

실행 중인 프로세스가 공유 execution context 일부를 분리하는 unshare의 동기, interface, 설계와 시험을 설명합니다.

Source pathDocumentation/userspace-api/unshare.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

unshare.rst:1-332

이 문서는 unshare 초기 설계의 역사적 설명을 담고 있습니다. 구현의 핵심은 실패 가능한 모든 context 복제를 먼저 완료하고 current task pointer를 한 번에 교체해 부분 적용 rollback에서 사라진 공유 구조를 참조하지 않도록 하는 것입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 unshare system call
2 ===================
3
4 This document describes the new system call, unshare(). The document
5 provides an overview of the feature, why it is needed, how it can
6 be used, its interface specification, design, implementation and
7 how it can be tested.
8
9 Change Log
10 ----------
11 version 0.1 Initial document, Janak Desai ([email protected]), Jan 11, 2006
12
13 Contents
14 --------
15 1) Overview
16 2) Benefits
17 3) Cost
18 4) Requirements
19 5) Functional Specification
20 6) High Level Design
21 7) Low Level Design
22 8) Test Specification
23 9) Future Work
24
25 1) Overview
26 -----------
27
28 Most legacy operating system kernels support an abstraction of threads
29 as multiple execution contexts within a process. These kernels provide
30 special resources and mechanisms to maintain these "threads". The Linux
31 kernel, in a clever and simple manner, does not make distinction
32 between processes and "threads". The kernel allows processes to share
33 resources and thus they can achieve legacy "threads" behavior without
34 requiring additional data structures and mechanisms in the kernel. The
35 power of implementing threads in this manner comes not only from
36 its simplicity but also from allowing application programmers to work
37 outside the confinement of all-or-nothing shared resources of legacy
38 threads. On Linux, at the time of thread creation using the clone system
39 call, applications can selectively choose which resources to share
40 between threads.
41
42 unshare() system call adds a primitive to the Linux thread model that
43 allows threads to selectively 'unshare' any resources that were being
44 shared at the time of their creation. unshare() was conceptualized by
45 Al Viro in the August of 2000, on the Linux-Kernel mailing list, as part
46 of the discussion on POSIX threads on Linux. unshare() augments the
47 usefulness of Linux threads for applications that would like to control
48 shared resources without creating a new process. unshare() is a natural
49 addition to the set of available primitives on Linux that implement
50 the concept of process/thread as a virtual machine.
51
52 2) Benefits
53 -----------
54
55 unshare() would be useful to large application frameworks such as PAM
56 where creating a new process to control sharing/unsharing of process
57 resources is not possible. Since namespaces are shared by default
58 when creating a new process using fork or clone, unshare() can benefit
59 even non-threaded applications if they have a need to disassociate
60 from default shared namespace. The following lists two use-cases
61 where unshare() can be used.
62
63 2.1 Per-security context namespaces
64 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65
66 unshare() can be used to implement polyinstantiated directories using
67 the kernel's per-process namespace mechanism. Polyinstantiated directories,
68 such as per-user and/or per-security context instance of /tmp, /var/tmp or
69 per-security context instance of a user's home directory, isolate user
70 processes when working with these directories. Using unshare(), a PAM
71 module can easily setup a private namespace for a user at login.
72 Polyinstantiated directories are required for Common Criteria certification
73 with Labeled System Protection Profile, however, with the availability
74 of shared-tree feature in the Linux kernel, even regular Linux systems
75 can benefit from setting up private namespaces at login and
76 polyinstantiating /tmp, /var/tmp and other directories deemed
77 appropriate by system administrators.
78
79 2.2 unsharing of virtual memory and/or open files
80 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81
82 Consider a client/server application where the server is processing
83 client requests by creating processes that share resources such as
84 virtual memory and open files. Without unshare(), the server has to
85 decide what needs to be shared at the time of creating the process
86 which services the request. unshare() allows the server an ability to
87 disassociate parts of the context during the servicing of the
88 request. For large and complex middleware application frameworks, this
89 ability to unshare() after the process was created can be very
90 useful.
91
92 3) Cost
93 -------
94
95 In order to not duplicate code and to handle the fact that unshare()
96 works on an active task (as opposed to clone/fork working on a newly
97 allocated inactive task) unshare() had to make minor reorganizational
98 changes to copy_* functions utilized by clone/fork system call.
99 There is a cost associated with altering existing, well tested and
100 stable code to implement a new feature that may not get exercised
101 extensively in the beginning. However, with proper design and code
102 review of the changes and creation of an unshare() test for the LTP
103 the benefits of this new feature can exceed its cost.
104
105 4) Requirements
106 ---------------
107
108 unshare() reverses sharing that was done using clone(2) system call,
109 so unshare() should have a similar interface as clone(2). That is,
110 since flags in clone(int flags, void \*stack) specifies what should
111 be shared, similar flags in unshare(int flags) should specify
112 what should be unshared. Unfortunately, this may appear to invert
113 the meaning of the flags from the way they are used in clone(2).
114 However, there was no easy solution that was less confusing and that
115 allowed incremental context unsharing in future without an ABI change.
116
117 unshare() interface should accommodate possible future addition of
118 new context flags without requiring a rebuild of old applications.
119 If and when new context flags are added, unshare() design should allow
120 incremental unsharing of those resources on an as needed basis.
121
122 5) Functional Specification
123 ---------------------------
124
125 NAME
126 unshare - disassociate parts of the process execution context
127
128 SYNOPSIS
129 #include <sched.h>
130
131 int unshare(int flags);
132
133 DESCRIPTION
134 unshare() allows a process to disassociate parts of its execution
135 context that are currently being shared with other processes. Part
136 of execution context, such as the namespace, is shared by default
137 when a new process is created using fork(2), while other parts,
138 such as the virtual memory, open file descriptors, etc, may be
139 shared by explicit request to share them when creating a process
140 using clone(2).
141
142 The main use of unshare() is to allow a process to control its
143 shared execution context without creating a new process.
144
145 The flags argument specifies one or bitwise-or'ed of several of
146 the following constants.
147
148 CLONE_FS
149 If CLONE_FS is set, file system information of the caller
150 is disassociated from the shared file system information.
151
152 CLONE_FILES
153 If CLONE_FILES is set, the file descriptor table of the
154 caller is disassociated from the shared file descriptor
155 table.
156
157 CLONE_NEWNS
158 If CLONE_NEWNS is set, the namespace of the caller is
159 disassociated from the shared namespace.
160
161 CLONE_VM
162 If CLONE_VM is set, the virtual memory of the caller is
163 disassociated from the shared virtual memory.
164
165 RETURN VALUE
166 On success, zero returned. On failure, -1 is returned and errno is
167
168 ERRORS
169 EPERM CLONE_NEWNS was specified by a non-root process (process
170 without CAP_SYS_ADMIN).
171
172 ENOMEM Cannot allocate sufficient memory to copy parts of caller's
173 context that need to be unshared.
174
175 EINVAL Invalid flag was specified as an argument.
176
177 CONFORMING TO
178 The unshare() call is Linux-specific and should not be used
179 in programs intended to be portable.
180
181 SEE ALSO
182 clone(2), fork(2)
183
184 6) High Level Design
185 --------------------
186
187 Depending on the flags argument, the unshare() system call allocates
188 appropriate process context structures, populates it with values from
189 the current shared version, associates newly duplicated structures
190 with the current task structure and releases corresponding shared
191 versions. Helper functions of clone (copy_*) could not be used
192 directly by unshare() because of the following two reasons.
193
194 1) clone operates on a newly allocated not-yet-active task
195 structure, where as unshare() operates on the current active
196 task. Therefore unshare() has to take appropriate task_lock()
197 before associating newly duplicated context structures
198
199 2) unshare() has to allocate and duplicate all context structures
200 that are being unshared, before associating them with the
201 current task and releasing older shared structures. Failure
202 do so will create race conditions and/or oops when trying
203 to backout due to an error. Consider the case of unsharing
204 both virtual memory and namespace. After successfully unsharing
205 vm, if the system call encounters an error while allocating
206 new namespace structure, the error return code will have to
207 reverse the unsharing of vm. As part of the reversal the
208 system call will have to go back to older, shared, vm
209 structure, which may not exist anymore.
210
211 Therefore code from copy_* functions that allocated and duplicated
212 current context structure was moved into new dup_* functions. Now,
213 copy_* functions call dup_* functions to allocate and duplicate
214 appropriate context structures and then associate them with the
215 task structure that is being constructed. unshare() system call on
216 the other hand performs the following:
217
218 1) Check flags to force missing, but implied, flags
219
220 2) For each context structure, call the corresponding unshare()
221 helper function to allocate and duplicate a new context
222 structure, if the appropriate bit is set in the flags argument.
223
224 3) If there is no error in allocation and duplication and there
225 are new context structures then lock the current task structure,
226 associate new context structures with the current task structure,
227 and release the lock on the current task structure.
228
229 4) Appropriately release older, shared, context structures.
230
231 7) Low Level Design
232 -------------------
233
234 Implementation of unshare() can be grouped in the following 4 different
235 items:
236
237 a) Reorganization of existing copy_* functions
238
239 b) unshare() system call service function
240
241 c) unshare() helper functions for each different process context
242
243 d) Registration of system call number for different architectures
244
245 7.1) Reorganization of copy_* functions
246 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
247
248 Each copy function such as copy_mm, copy_namespace, copy_files,
249 etc, had roughly two components. The first component allocated
250 and duplicated the appropriate structure and the second component
251 linked it to the task structure passed in as an argument to the copy
252 function. The first component was split into its own function.
253 These dup_* functions allocated and duplicated the appropriate
254 context structure. The reorganized copy_* functions invoked
255 their corresponding dup_* functions and then linked the newly
256 duplicated structures to the task structure with which the
257 copy function was called.
258
259 7.2) unshare() system call service function
260 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
261
262 * Check flags
263 Force implied flags. If CLONE_THREAD is set force CLONE_VM.
264 If CLONE_VM is set, force CLONE_SIGHAND. If CLONE_SIGHAND is
265 set and signals are also being shared, force CLONE_THREAD. If
266 CLONE_NEWNS is set, force CLONE_FS.
267
268 * For each context flag, invoke the corresponding unshare_*
269 helper routine with flags passed into the system call and a
270 reference to pointer pointing the new unshared structure
271
272 * If any new structures are created by unshare_* helper
273 functions, take the task_lock() on the current task,
274 modify appropriate context pointers, and release the
275 task lock.
276
277 * For all newly unshared structures, release the corresponding
278 older, shared, structures.
279
280 7.3) unshare_* helper functions
281 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
282
283 For unshare_* helpers corresponding to CLONE_SYSVSEM, CLONE_SIGHAND,
284 and CLONE_THREAD, return -EINVAL since they are not implemented yet.
285 For others, check the flag value to see if the unsharing is
286 required for that structure. If it is, invoke the corresponding
287 dup_* function to allocate and duplicate the structure and return
288 a pointer to it.
289
290 7.4) Finally
291 ~~~~~~~~~~~~
292
293 Appropriately modify architecture specific code to register the
294 new system call.
295
296 8) Test Specification
297 ---------------------
298
299 The test for unshare() should test the following:
300
301 1) Valid flags: Test to check that clone flags for signal and
302 signal handlers, for which unsharing is not implemented
303 yet, return -EINVAL.
304
305 2) Missing/implied flags: Test to make sure that if unsharing
306 namespace without specifying unsharing of filesystem, correctly
307 unshares both namespace and filesystem information.
308
309 3) For each of the four (namespace, filesystem, files and vm)
310 supported unsharing, verify that the system call correctly
311 unshares the appropriate structure. Verify that unsharing
312 them individually as well as in combination with each
313 other works as expected.
314
315 4) Concurrent execution: Use shared memory segments and futex on
316 an address in the shm segment to synchronize execution of
317 about 10 threads. Have a couple of threads execute execve,
318 a couple _exit and the rest unshare with different combination
319 of flags. Verify that unsharing is performed as expected and
320 that there are no oops or hangs.
321
322 9) Future Work
323 --------------
324
325 The current implementation of unshare() does not allow unsharing of
326 signals and signal handlers. Signals are complex to begin with and
327 to unshare signals and/or signal handlers of a currently running
328 process is even more complex. If in the future there is a specific
329 need to allow unsharing of signals and/or signal handlers, it can
330 be incrementally added to unshare() without affecting legacy
331 applications using unshare().
332
333

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

문서 범위와 변경 이력

1-24

이 문서는 `unshare()` system call의 개요, 필요성, 사용법, interface 명세, 설계·구현과 시험 방법을 설명합니다.

문서 버전 0.1은 Janak Desai가 2006년 1월 11일 작성한 최초 문서입니다.

unshare 문서 구성
주제
1~4개요, 이점, 비용, 요구사항
5기능 명세
6~7상위·하위 수준 설계
8시험 명세
9향후 작업

기능 동기에서 구현과 시험, 향후 작업까지 이어집니다.

unshare system call
===================

This document describes the new system call, unshare(). The document
provides an overview of the feature, why it is needed, how it can
be used, its interface specification, design, implementation and
how it can be tested.

Change Log
----------
version 0.1  Initial document, Janak Desai ([email protected]), Jan 11, 2006

Contents
--------
	1) Overview
	2) Benefits
	3) Cost
	4) Requirements
	5) Functional Specification
	6) High Level Design
	7) Low Level Design
	8) Test Specification
	9) Future Work

1. 개요

25-51

전통적인 운영체제 커널은 프로세스 안의 여러 실행 context를 thread로 추상화하고 이를 유지할 별도 resource와 메커니즘을 둡니다. Linux는 프로세스와 thread를 구분하지 않고 프로세스가 resource를 공유하도록 해 추가 구조 없이 전통적인 thread 동작을 구현합니다.

이 방식은 단순할 뿐 아니라 애플리케이션이 전통적인 thread의 전부 공유 또는 전부 비공유 제약을 벗어나게 합니다. `clone`으로 thread를 만들 때 어떤 resource를 서로 공유할지 선택할 수 있습니다.

`unshare()`는 생성 시 공유했던 resource를 실행 중인 thread가 선택적으로 분리할 수 있게 Linux thread model에 추가된 primitive입니다. Al Viro가 2000년 8월 Linux-Kernel mailing list의 POSIX thread 논의에서 구상했습니다.

새 프로세스를 만들지 않고 공유 resource를 제어하려는 애플리케이션에 유용하며, process/thread를 virtual machine으로 보는 Linux primitive 집합을 자연스럽게 확장합니다.

1) Overview
-----------

Most legacy operating system kernels support an abstraction of threads
as multiple execution contexts within a process. These kernels provide
special resources and mechanisms to maintain these "threads". The Linux
kernel, in a clever and simple manner, does not make distinction
between processes and "threads". The kernel allows processes to share
resources and thus they can achieve legacy "threads" behavior without
requiring additional data structures and mechanisms in the kernel. The
power of implementing threads in this manner comes not only from
its simplicity but also from allowing application programmers to work
outside the confinement of all-or-nothing shared resources of legacy
threads. On Linux, at the time of thread creation using the clone system
call, applications can selectively choose which resources to share
between threads.

unshare() system call adds a primitive to the Linux thread model that
allows threads to selectively 'unshare' any resources that were being
shared at the time of their creation. unshare() was conceptualized by
Al Viro in the August of 2000, on the Linux-Kernel mailing list, as part
of the discussion on POSIX threads on Linux.  unshare() augments the
usefulness of Linux threads for applications that would like to control
shared resources without creating a new process. unshare() is a natural
addition to the set of available primitives on Linux that implement
the concept of process/thread as a virtual machine.

2. 이점과 보안 context별 namespace

52-78

PAM 같은 큰 애플리케이션 framework는 process resource의 공유 상태를 바꾸기 위해 새 프로세스를 만들기 어려울 수 있어 `unshare()`가 유용합니다. fork나 clone으로 만든 프로세스는 기본적으로 namespace를 공유하므로 thread를 쓰지 않는 프로그램도 기본 namespace에서 분리할 필요가 있다면 이 기능을 활용할 수 있습니다.

`unshare()`와 per-process namespace로 polyinstantiated directory를 구현할 수 있습니다. 사용자별 또는 보안 context별 `/tmp`, `/var/tmp`, home directory 인스턴스가 해당 디렉터리에서 작업하는 사용자 프로세스를 격리합니다.

PAM module은 로그인 때 사용자의 private namespace를 쉽게 설정할 수 있습니다. 이 기능은 Labeled System Protection Profile을 적용한 Common Criteria 인증에 필요하며, shared-tree 기능을 이용하면 일반 Linux 시스템도 로그인 때 private namespace와 관리자 지정 directory의 개별 인스턴스를 구성할 수 있습니다.

2) Benefits
-----------

unshare() would be useful to large application frameworks such as PAM
where creating a new process to control sharing/unsharing of process
resources is not possible. Since namespaces are shared by default
when creating a new process using fork or clone, unshare() can benefit
even non-threaded applications if they have a need to disassociate
from default shared namespace. The following lists two use-cases
where unshare() can be used.

2.1 Per-security context namespaces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

unshare() can be used to implement polyinstantiated directories using
the kernel's per-process namespace mechanism. Polyinstantiated directories,
such as per-user and/or per-security context instance of /tmp, /var/tmp or
per-security context instance of a user's home directory, isolate user
processes when working with these directories. Using unshare(), a PAM
module can easily setup a private namespace for a user at login.
Polyinstantiated directories are required for Common Criteria certification
with Labeled System Protection Profile, however, with the availability
of shared-tree feature in the Linux kernel, even regular Linux systems
can benefit from setting up private namespaces at login and
polyinstantiating /tmp, /var/tmp and other directories deemed
appropriate by system administrators.

2.2 가상 메모리와 열린 파일 분리

79-91

server가 virtual memory와 open file 같은 resource를 공유하는 프로세스를 만들어 client 요청을 처리하는 애플리케이션을 생각할 수 있습니다. `unshare()`가 없으면 요청 처리 프로세스를 만들 때 무엇을 공유할지 미리 결정해야 합니다.

`unshare()`는 요청 처리 도중 context 일부를 분리할 수 있게 합니다. 생성 뒤에 공유 상태를 바꾸는 능력은 크고 복잡한 middleware framework에 특히 유용합니다.

2.2 unsharing of virtual memory and/or open files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Consider a client/server application where the server is processing
client requests by creating processes that share resources such as
virtual memory and open files. Without unshare(), the server has to
decide what needs to be shared at the time of creating the process
which services the request. unshare() allows the server an ability to
disassociate parts of the context during the servicing of the
request. For large and complex middleware application frameworks, this
ability to unshare() after the process was created can be very
useful.

3. 구현 비용

92-104

`unshare()`는 새로 할당되어 아직 활성화되지 않은 태스크를 다루는 clone/fork와 달리 현재 활성 태스크에 작동합니다. 코드를 중복하지 않으면서 이 차이를 처리하기 위해 clone/fork가 쓰는 `copy_*` 함수에 작은 구조 변경이 필요했습니다.

검증되고 안정적인 기존 코드를 초기 사용량이 적을 수 있는 새 기능 때문에 바꾸는 비용이 있지만, 적절한 설계·code review와 LTP용 `unshare()` 시험을 갖추면 이점이 비용을 넘을 수 있습니다.

3) Cost
-------

In order to not duplicate code and to handle the fact that unshare()
works on an active task (as opposed to clone/fork working on a newly
allocated inactive task) unshare() had to make minor reorganizational
changes to copy_* functions utilized by clone/fork system call.
There is a cost associated with altering existing, well tested and
stable code to implement a new feature that may not get exercised
extensively in the beginning. However, with proper design and code
review of the changes and creation of an unshare() test for the LTP
the benefits of this new feature can exceed its cost.

4. Interface 요구사항

105-121

`unshare()`는 `clone(2)`이 만든 공유를 되돌리므로 비슷한 interface를 가져야 합니다. `clone(int flags, void *stack)`의 flag가 공유할 항목을 지정하듯 `unshare(int flags)`의 같은 종류 flag는 분리할 항목을 지정합니다. clone과 비교하면 flag 의미가 뒤집힌 것처럼 보이지만, ABI 변경 없이 향후 context를 점진적으로 분리할 수 있는 덜 혼란스러운 대안이 없었습니다.

interface는 새 context flag가 추가돼도 기존 애플리케이션을 rebuild하지 않도록 해야 합니다. 새 resource도 필요할 때 점진적으로 분리할 수 있어야 합니다.

4) Requirements
---------------

unshare() reverses sharing that was done using clone(2) system call,
so unshare() should have a similar interface as clone(2). That is,
since flags in clone(int flags, void \*stack) specifies what should
be shared, similar flags in unshare(int flags) should specify
what should be unshared. Unfortunately, this may appear to invert
the meaning of the flags from the way they are used in clone(2).
However, there was no easy solution that was less confusing and that
allowed incremental context unsharing in future without an ABI change.

unshare() interface should accommodate possible future addition of
new context flags without requiring a rebuild of old applications.
If and when new context flags are added, unshare() design should allow
incremental unsharing of those resources on an as needed basis.

5. 기능 명세

122-183

이름은 `unshare`이며 프로세스 실행 context 일부의 연결을 끊습니다.

#include <sched.h>

int unshare(int flags);

`unshare()`는 현재 다른 프로세스와 공유하는 실행 context 일부를 분리합니다. namespace처럼 fork 시 기본 공유되는 부분도 있고, virtual memory나 open file descriptor처럼 clone 시 명시적으로 요청해야 공유되는 부분도 있습니다. 주된 용도는 새 프로세스를 만들지 않고 현재 프로세스가 공유 context를 제어하는 것입니다.

문서에 정의된 unshare flag
Flag분리 대상
`CLONE_FS`호출자의 filesystem 정보
`CLONE_FILES`호출자의 file descriptor table
`CLONE_NEWNS`호출자의 namespace
`CLONE_VM`호출자의 virtual memory

여러 flag를 bitwise OR로 결합할 수 있습니다.

성공하면 0, 실패하면 -1을 반환하고 errno를 설정합니다.

기능 명세의 오류
errno조건
`EPERM``CAP_SYS_ADMIN`이 없는 non-root 프로세스가 `CLONE_NEWNS` 지정
`ENOMEM`분리할 호출자 context를 복사할 메모리 부족
`EINVAL`잘못된 flag 지정

권한, 할당과 flag 검증 실패를 구분합니다.

`unshare()`는 Linux 전용이므로 portable 프로그램에 사용하면 안 됩니다. 관련 호출은 `clone(2)`과 `fork(2)`입니다.

5) Functional Specification
---------------------------

NAME
	unshare - disassociate parts of the process execution context

SYNOPSIS
	#include <sched.h>

	int unshare(int flags);

DESCRIPTION
	unshare() allows a process to disassociate parts of its execution
	context that are currently being shared with other processes. Part
	of execution context, such as the namespace, is shared by default
	when a new process is created using fork(2), while other parts,
	such as the virtual memory, open file descriptors, etc, may be
	shared by explicit request to share them when creating a process
	using clone(2).

	The main use of unshare() is to allow a process to control its
	shared execution context without creating a new process.

	The flags argument specifies one or bitwise-or'ed of several of
	the following constants.

	CLONE_FS
		If CLONE_FS is set, file system information of the caller
		is disassociated from the shared file system information.

	CLONE_FILES
		If CLONE_FILES is set, the file descriptor table of the
		caller is disassociated from the shared file descriptor
		table.

	CLONE_NEWNS
		If CLONE_NEWNS is set, the namespace of the caller is
		disassociated from the shared namespace.

	CLONE_VM
		If CLONE_VM is set, the virtual memory of the caller is
		disassociated from the shared virtual memory.

RETURN VALUE
	On success, zero returned. On failure, -1 is returned and errno is

ERRORS
	EPERM	CLONE_NEWNS was specified by a non-root process (process
		without CAP_SYS_ADMIN).

	ENOMEM	Cannot allocate sufficient memory to copy parts of caller's
		context that need to be unshared.

	EINVAL	Invalid flag was specified as an argument.

CONFORMING TO
	The unshare() call is Linux-specific and  should  not be used
	in programs intended to be portable.

SEE ALSO
	clone(2), fork(2)

6. 상위 수준 설계

184-230

flag에 따라 `unshare()`는 적절한 process context 구조를 할당하고 현재 공유 구조의 값으로 채운 뒤, 새 복제본을 current task에 연결하고 이전 공유 구조를 해제합니다.

clone의 `copy_*` helper를 직접 사용할 수 없는 첫 이유는 clone은 새로 할당된 비활성 태스크를 다루지만 unshare는 현재 활성 태스크에 작동한다는 점입니다. 새 context를 연결할 때 알맞은 `task_lock()`이 필요합니다.

둘째, 현재 태스크에 새 구조를 연결하고 이전 공유 구조를 해제하기 전에 분리 대상 context 전체를 먼저 할당·복제해야 합니다. 그렇지 않으면 오류 rollback에서 경쟁 조건이나 oops가 생깁니다.

예를 들어 virtual memory와 namespace를 함께 분리할 때 VM 분리 뒤 namespace 할당이 실패하면 VM 분리를 되돌려야 합니다. 그러나 돌아갈 이전 공유 VM 구조가 이미 사라졌을 수 있습니다.

따라서 `copy_*`의 할당·복제 부분을 새 `dup_*` 함수로 옮겼습니다. `copy_*`는 `dup_*`로 구조를 만든 뒤 새 태스크에 연결하고, `unshare()`는 모든 복제가 성공한 뒤 한꺼번에 현재 태스크에 연결합니다.

unshare의 원자적 전환 순서
Validate flags and add implied flagsAllocate and duplicate every requested context through unshare/dup helpersAbort without changing current task if any allocation failsLock current task and attach all new context structuresUnlock task and release all previous shared structures

오류가 날 수 있는 할당을 연결 변경보다 먼저 끝냅니다.

6) High Level Design
--------------------

Depending on the flags argument, the unshare() system call allocates
appropriate process context structures, populates it with values from
the current shared version, associates newly duplicated structures
with the current task structure and releases corresponding shared
versions. Helper functions of clone (copy_*) could not be used
directly by unshare() because of the following two reasons.

  1) clone operates on a newly allocated not-yet-active task
     structure, where as unshare() operates on the current active
     task. Therefore unshare() has to take appropriate task_lock()
     before associating newly duplicated context structures

  2) unshare() has to allocate and duplicate all context structures
     that are being unshared, before associating them with the
     current task and releasing older shared structures. Failure
     do so will create race conditions and/or oops when trying
     to backout due to an error. Consider the case of unsharing
     both virtual memory and namespace. After successfully unsharing
     vm, if the system call encounters an error while allocating
     new namespace structure, the error return code will have to
     reverse the unsharing of vm. As part of the reversal the
     system call will have to go back to older, shared, vm
     structure, which may not exist anymore.

Therefore code from copy_* functions that allocated and duplicated
current context structure was moved into new dup_* functions. Now,
copy_* functions call dup_* functions to allocate and duplicate
appropriate context structures and then associate them with the
task structure that is being constructed. unshare() system call on
the other hand performs the following:

  1) Check flags to force missing, but implied, flags

  2) For each context structure, call the corresponding unshare()
     helper function to allocate and duplicate a new context
     structure, if the appropriate bit is set in the flags argument.

  3) If there is no error in allocation and duplication and there
     are new context structures then lock the current task structure,
     associate new context structures with the current task structure,
     and release the lock on the current task structure.

  4) Appropriately release older, shared, context structures.

7. 하위 수준 설계 개요

231-244

구현 작업은 기존 `copy_*` 함수 재구성, `unshare()` system call service, process context별 `unshare_*` helper, 아키텍처별 system call 번호 등록의 네 항목으로 나뉩니다.

하위 수준 구현 영역
영역역할
`copy_*` 재구성할당·복제를 `dup_*`로 분리
service functionflag와 전체 전환 순서 관리
`unshare_*` helperscontext별 필요 여부 확인과 복제
architecture registration새 system call 번호 등록

공통 복제 로직과 현재 태스크 교체 로직을 분리합니다.

7) Low Level Design
-------------------

Implementation of unshare() can be grouped in the following 4 different
items:

  a) Reorganization of existing copy_* functions

  b) unshare() system call service function

  c) unshare() helper functions for each different process context

  d) Registration of system call number for different architectures

7.1 copy_* 함수 재구성

245-258

`copy_mm`, `copy_namespace`, `copy_files` 같은 기존 copy 함수는 적절한 구조를 할당·복제하는 부분과 인자로 받은 task 구조에 연결하는 부분으로 이루어졌습니다.

첫 부분을 독립 `dup_*` 함수로 분리했습니다. 재구성된 `copy_*`는 대응 `dup_*`를 호출한 뒤 새 복제 구조를 자신이 받은 task에 연결합니다.

7.1) Reorganization of copy_* functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Each copy function such as copy_mm, copy_namespace, copy_files,
etc, had roughly two components. The first component allocated
and duplicated the appropriate structure and the second component
linked it to the task structure passed in as an argument to the copy
function. The first component was split into its own function.
These dup_* functions allocated and duplicated the appropriate
context structure. The reorganized copy_* functions invoked
their corresponding dup_* functions and then linked the newly
duplicated structures to the task structure with which the
copy function was called.

7.2 unshare service function

259-279

service는 먼저 flag를 검사하고 암시된 flag를 강제합니다. `CLONE_THREAD`이면 `CLONE_VM`, `CLONE_VM`이면 `CLONE_SIGHAND`, signal도 공유 중인 상태에서 `CLONE_SIGHAND`이면 `CLONE_THREAD`, `CLONE_NEWNS`이면 `CLONE_FS`를 함께 적용합니다.

각 context flag에 대해 system call flag와 새 구조 포인터를 받을 위치를 대응 `unshare_*` helper에 전달합니다.

helper가 새 구조를 만들었으면 current task에 `task_lock()`을 걸고 적절한 context pointer를 바꾼 뒤 lock을 풉니다. 마지막으로 새로 분리된 모든 항목의 이전 공유 구조를 해제합니다.

암시 flag 관계
CLONE_THREAD implies CLONE_VMCLONE_VM implies CLONE_SIGHANDCLONE_SIGHAND with shared signals implies CLONE_THREADCLONE_NEWNS implies CLONE_FS

의존 context가 함께 분리되도록 flag를 보완합니다.

7.2) unshare() system call service function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       * Check flags
	 Force implied flags. If CLONE_THREAD is set force CLONE_VM.
	 If CLONE_VM is set, force CLONE_SIGHAND. If CLONE_SIGHAND is
	 set and signals are also being shared, force CLONE_THREAD. If
	 CLONE_NEWNS is set, force CLONE_FS.

       * For each context flag, invoke the corresponding unshare_*
	 helper routine with flags passed into the system call and a
	 reference to pointer pointing the new unshared structure

       * If any new structures are created by unshare_* helper
	 functions, take the task_lock() on the current task,
	 modify appropriate context pointers, and release the
         task lock.

       * For all newly unshared structures, release the corresponding
         older, shared, structures.

7.3 helper와 아키텍처 등록

280-295

문서 작성 시점에 `CLONE_SYSVSEM`, `CLONE_SIGHAND`, `CLONE_THREAD`에 대응하는 `unshare_*` helper는 구현되지 않아 `-EINVAL`을 반환합니다.

다른 helper는 해당 구조를 분리해야 하는지 flag를 검사하고, 필요하면 대응 `dup_*` 함수로 구조를 할당·복제해 pointer를 반환합니다.

마지막으로 새 system call을 등록하도록 아키텍처별 코드를 적절히 수정합니다.

7.3) unshare_* helper functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For unshare_* helpers corresponding to CLONE_SYSVSEM, CLONE_SIGHAND,
and CLONE_THREAD, return -EINVAL since they are not implemented yet.
For others, check the flag value to see if the unsharing is
required for that structure. If it is, invoke the corresponding
dup_* function to allocate and duplicate the structure and return
a pointer to it.

7.4) Finally
~~~~~~~~~~~~

Appropriately modify architecture specific code to register the
new system call.

8. 시험 명세

296-321
unshare 시험 항목
항목검증 내용
유효 flag아직 signal·handler 분리를 구현하지 않은 clone flag가 `-EINVAL`인지 확인
누락·암시 flagfilesystem flag 없이 namespace를 분리해도 namespace와 filesystem이 모두 분리되는지 확인
네 지원 contextnamespace, filesystem, files, VM을 개별 및 모든 조합으로 올바르게 분리하는지 확인
동시 실행shared memory와 shm 주소의 futex로 약 10개 thread를 동기화하고 일부는 execve, 일부는 `_exit`, 나머지는 여러 flag 조합의 unshare를 수행해 oops나 hang 없이 동작하는지 확인

오류 처리, 암시 flag, 기능과 경쟁 상황을 모두 검증합니다.

8) Test Specification
---------------------

The test for unshare() should test the following:

  1) Valid flags: Test to check that clone flags for signal and
     signal handlers, for which unsharing is not implemented
     yet, return -EINVAL.

  2) Missing/implied flags: Test to make sure that if unsharing
     namespace without specifying unsharing of filesystem, correctly
     unshares both namespace and filesystem information.

  3) For each of the four (namespace, filesystem, files and vm)
     supported unsharing, verify that the system call correctly
     unshares the appropriate structure. Verify that unsharing
     them individually as well as in combination with each
     other works as expected.

  4) Concurrent execution: Use shared memory segments and futex on
     an address in the shm segment to synchronize execution of
     about 10 threads. Have a couple of threads execute execve,
     a couple _exit and the rest unshare with different combination
     of flags. Verify that unsharing is performed as expected and
     that there are no oops or hangs.

9. 향후 작업

322-332

현재 구현은 signal과 signal handler 분리를 허용하지 않습니다. signal 자체도 복잡하고 실행 중인 프로세스의 signal 상태를 분리하는 일은 더 복잡합니다.

향후 구체적인 필요가 생기면 기존 `unshare()` 애플리케이션에 영향을 주지 않고 이 기능을 점진적으로 추가할 수 있습니다.

9) Future Work
--------------

The current implementation of unshare() does not allow unsharing of
signals and signal handlers. Signals are complex to begin with and
to unshare signals and/or signal handlers of a currently running
process is even more complex. If in the future there is a specific
need to allow unsharing of signals and/or signal handlers, it can
be incrementally added to unshare() without affecting legacy
applications using unshare().