← Documents Documentation/filesystems/sharedsubtree.rst GitHub 원문 ↗

Linux 6.18.37 · Filesystems

Shared Subtrees

mount propagation 상태, 연산별 전이, namespace 사용 사례와 구현을 다루는 전문 번역입니다.

Source pathDocumentation/filesystems/sharedsubtree.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약·해설

sharedsubtree.rst:1-994

Shared subtree는 mount namespace 사이에서 mount·umount 이벤트가 흐르는 방향을 shared, slave, private, unbindable 상태로 제어한다. shared peer는 양방향으로 동기화되고, slave는 master의 이벤트만 받으며, private은 단절되고, unbindable은 재귀 bind의 원본에서도 제외된다.

bind·rbind·move·mount·umount·namespace clone의 결과는 원본과 목적지의 전파 상태에 따라 달라진다. 특히 shared 목적지에는 clone propagation tree가 만들어지고, rbind는 unbindable subtree를 잘라 내며, move는 필요할 때 원본을 shared 또는 shared and slave로 바꾼다.

구현은 `mnt_share`, `mnt_slave_list`, `mnt_slave`, `mnt_master`로 mount tree와 직교하는 propagation tree를 표현한다. 재귀 연산은 `attach_recursive_mnt()`와 `propagate_mnt()`에서 prepare·commit·abort 단계로 처리해 일부만 공개되는 상태를 피한다.

Shared subtree를 읽는 순서
shared·slave·private·unbindable 상태 파악peer group과 master-slave 방향 확인bind·rbind·move 결과표 적용namespace와 unmount 전파 검토`struct vfsmount` 연결과 3단계 알고리즘 확인

상태에서 연산 의미를 거쳐 구현 자료구조로 내려간다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===============
4 Shared Subtrees
5 ===============
6
7 .. Contents:
8 1) Overview
9 2) Features
10 3) Setting mount states
11 4) Use-case
12 5) Detailed semantics
13 6) Quiz
14 7) FAQ
15 8) Implementation
16
17
18 1) Overview
19 -----------
20
21 Consider the following situation:
22
23 A process wants to clone its own namespace, but still wants to access the CD
24 that got mounted recently. Shared subtree semantics provide the necessary
25 mechanism to accomplish the above.
26
27 It provides the necessary building blocks for features like per-user-namespace
28 and versioned filesystem.
29
30 2) Features
31 -----------
32
33 Shared subtree provides four different flavors of mounts; struct vfsmount to be
34 precise:
35
36
37 a) A **shared mount** can be replicated to as many mountpoints and all the
38 replicas continue to be exactly same.
39
40 Here is an example:
41
42 Let's say /mnt has a mount that is shared::
43
44 # mount --make-shared /mnt
45
46 .. note::
47 mount(8) command now supports the --make-shared flag,
48 so the sample 'smount' program is no longer needed and has been
49 removed.
50
51 ::
52
53 # mount --bind /mnt /tmp
54
55 The above command replicates the mount at /mnt to the mountpoint /tmp
56 and the contents of both the mounts remain identical.
57
58 ::
59
60 #ls /mnt
61 a b c
62
63 #ls /tmp
64 a b c
65
66 Now let's say we mount a device at /tmp/a::
67
68 # mount /dev/sd0 /tmp/a
69
70 # ls /tmp/a
71 t1 t2 t3
72
73 # ls /mnt/a
74 t1 t2 t3
75
76 Note that the mount has propagated to the mount at /mnt as well.
77
78 And the same is true even when /dev/sd0 is mounted on /mnt/a. The
79 contents will be visible under /tmp/a too.
80
81
82 b) A **slave mount** is like a shared mount except that mount and umount events
83 only propagate towards it.
84
85 All slave mounts have a master mount which is a shared.
86
87 Here is an example:
88
89 Let's say /mnt has a mount which is shared::
90
91 # mount --make-shared /mnt
92
93 Let's bind mount /mnt to /tmp::
94
95 # mount --bind /mnt /tmp
96
97 the new mount at /tmp becomes a shared mount and it is a replica of
98 the mount at /mnt.
99
100 Now let's make the mount at /tmp; a slave of /mnt::
101
102 # mount --make-slave /tmp
103
104 let's mount /dev/sd0 on /mnt/a::
105
106 # mount /dev/sd0 /mnt/a
107
108 # ls /mnt/a
109 t1 t2 t3
110
111 # ls /tmp/a
112 t1 t2 t3
113
114 Note the mount event has propagated to the mount at /tmp
115
116 However let's see what happens if we mount something on the mount at
117 /tmp::
118
119 # mount /dev/sd1 /tmp/b
120
121 # ls /tmp/b
122 s1 s2 s3
123
124 # ls /mnt/b
125
126 Note how the mount event has not propagated to the mount at
127 /mnt
128
129
130 c) A **private mount** does not forward or receive propagation.
131
132 This is the mount we are familiar with. Its the default type.
133
134
135 d) An **unbindable mount** is, as the name suggests, an unbindable private
136 mount.
137
138 let's say we have a mount at /mnt and we make it unbindable::
139
140 # mount --make-unbindable /mnt
141
142 Let's try to bind mount this mount somewhere else::
143
144 # mount --bind /mnt /tmp mount: wrong fs type, bad option, bad
145 superblock on /mnt, or too many mounted file systems
146
147 Binding a unbindable mount is a invalid operation.
148
149
150 3) Setting mount states
151 -----------------------
152
153 The mount command (util-linux package) can be used to set mount
154 states::
155
156 mount --make-shared mountpoint
157 mount --make-slave mountpoint
158 mount --make-private mountpoint
159 mount --make-unbindable mountpoint
160
161
162 4) Use cases
163 ------------
164
165 A) A process wants to clone its own namespace, but still wants to
166 access the CD that got mounted recently.
167
168 Solution:
169
170 The system administrator can make the mount at /cdrom shared::
171
172 mount --bind /cdrom /cdrom
173 mount --make-shared /cdrom
174
175 Now any process that clones off a new namespace will have a
176 mount at /cdrom which is a replica of the same mount in the
177 parent namespace.
178
179 So when a CD is inserted and mounted at /cdrom that mount gets
180 propagated to the other mount at /cdrom in all the other clone
181 namespaces.
182
183 B) A process wants its mounts invisible to any other process, but
184 still be able to see the other system mounts.
185
186 Solution:
187
188 To begin with, the administrator can mark the entire mount tree
189 as shareable::
190
191 mount --make-rshared /
192
193 A new process can clone off a new namespace. And mark some part
194 of its namespace as slave::
195
196 mount --make-rslave /myprivatetree
197
198 Hence forth any mounts within the /myprivatetree done by the
199 process will not show up in any other namespace. However mounts
200 done in the parent namespace under /myprivatetree still shows
201 up in the process's namespace.
202
203
204 Apart from the above semantics this feature provides the
205 building blocks to solve the following problems:
206
207 C) Per-user namespace
208
209 The above semantics allows a way to share mounts across
210 namespaces. But namespaces are associated with processes. If
211 namespaces are made first class objects with user API to
212 associate/disassociate a namespace with userid, then each user
213 could have his/her own namespace and tailor it to his/her
214 requirements. This needs to be supported in PAM.
215
216 D) Versioned files
217
218 If the entire mount tree is visible at multiple locations, then
219 an underlying versioning file system can return different
220 versions of the file depending on the path used to access that
221 file.
222
223 An example is::
224
225 mount --make-shared /
226 mount --rbind / /view/v1
227 mount --rbind / /view/v2
228 mount --rbind / /view/v3
229 mount --rbind / /view/v4
230
231 and if /usr has a versioning filesystem mounted, then that
232 mount appears at /view/v1/usr, /view/v2/usr, /view/v3/usr and
233 /view/v4/usr too
234
235 A user can request v3 version of the file /usr/fs/namespace.c
236 by accessing /view/v3/usr/fs/namespace.c . The underlying
237 versioning filesystem can then decipher that v3 version of the
238 filesystem is being requested and return the corresponding
239 inode.
240
241 5) Detailed semantics
242 ---------------------
243 The section below explains the detailed semantics of
244 bind, rbind, move, mount, umount and clone-namespace operations.
245
246 .. Note::
247 the word 'vfsmount' and the noun 'mount' have been used
248 to mean the same thing, throughout this document.
249
250 a) Mount states
251
252 A **propagation event** is defined as event generated on a vfsmount
253 that leads to mount or unmount actions in other vfsmounts.
254
255 A **peer group** is defined as a group of vfsmounts that propagate
256 events to each other.
257
258 A given mount can be in one of the following states:
259
260 (1) Shared mounts
261
262 A **shared mount** is defined as a vfsmount that belongs to a
263 peer group.
264
265 For example::
266
267 mount --make-shared /mnt
268 mount --bind /mnt /tmp
269
270 The mount at /mnt and that at /tmp are both shared and belong
271 to the same peer group. Anything mounted or unmounted under
272 /mnt or /tmp reflect in all the other mounts of its peer
273 group.
274
275
276 (2) Slave mounts
277
278 A **slave mount** is defined as a vfsmount that receives
279 propagation events and does not forward propagation events.
280
281 A slave mount as the name implies has a master mount from which
282 mount/unmount events are received. Events do not propagate from
283 the slave mount to the master. Only a shared mount can be made
284 a slave by executing the following command::
285
286 mount --make-slave mount
287
288 A shared mount that is made as a slave is no more shared unless
289 modified to become shared.
290
291 (3) Shared and Slave
292
293 A vfsmount can be both **shared** as well as **slave**. This state
294 indicates that the mount is a slave of some vfsmount, and
295 has its own peer group too. This vfsmount receives propagation
296 events from its master vfsmount, and also forwards propagation
297 events to its 'peer group' and to its slave vfsmounts.
298
299 Strictly speaking, the vfsmount is shared having its own
300 peer group, and this peer-group is a slave of some other
301 peer group.
302
303 Only a slave vfsmount can be made as 'shared and slave' by
304 either executing the following command::
305
306 mount --make-shared mount
307
308 or by moving the slave vfsmount under a shared vfsmount.
309
310 (4) Private mount
311
312 A **private mount** is defined as vfsmount that does not
313 receive or forward any propagation events.
314
315 (5) Unbindable mount
316
317 A **unbindable mount** is defined as vfsmount that does not
318 receive or forward any propagation events and cannot
319 be bind mounted.
320
321
322 State diagram:
323
324 The state diagram below explains the state transition of a mount,
325 in response to various commands::
326
327 -----------------------------------------------------------------------
328 | |make-shared | make-slave | make-private |make-unbindab|
329 --------------|------------|--------------|--------------|-------------|
330 |shared |shared |*slave/private| private | unbindable |
331 | | | | | |
332 |-------------|------------|--------------|--------------|-------------|
333 |slave |shared | **slave | private | unbindable |
334 | |and slave | | | |
335 |-------------|------------|--------------|--------------|-------------|
336 |shared |shared | slave | private | unbindable |
337 |and slave |and slave | | | |
338 |-------------|------------|--------------|--------------|-------------|
339 |private |shared | **private | private | unbindable |
340 |-------------|------------|--------------|--------------|-------------|
341 |unbindable |shared |**unbindable | private | unbindable |
342 ------------------------------------------------------------------------
343
344 * if the shared mount is the only mount in its peer group, making it
345 slave, makes it private automatically. Note that there is no master to
346 which it can be slaved to.
347
348 ** slaving a non-shared mount has no effect on the mount.
349
350 Apart from the commands listed below, the 'move' operation also changes
351 the state of a mount depending on type of the destination mount. Its
352 explained in section 5d.
353
354 b) Bind semantics
355
356 Consider the following command::
357
358 mount --bind A/a B/b
359
360 where 'A' is the source mount, 'a' is the dentry in the mount 'A', 'B'
361 is the destination mount and 'b' is the dentry in the destination mount.
362
363 The outcome depends on the type of mount of 'A' and 'B'. The table
364 below contains quick reference::
365
366 --------------------------------------------------------------------------
367 | BIND MOUNT OPERATION |
368 |************************************************************************|
369 |source(A)->| shared | private | slave | unbindable |
370 | dest(B) | | | | |
371 | | | | | | |
372 | v | | | | |
373 |************************************************************************|
374 | shared | shared | shared | shared & slave | invalid |
375 | | | | | |
376 |non-shared| shared | private | slave | invalid |
377 **************************************************************************
378
379 Details:
380
381 1. 'A' is a shared mount and 'B' is a shared mount. A new mount 'C'
382 which is clone of 'A', is created. Its root dentry is 'a' . 'C' is
383 mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
384 are created and mounted at the dentry 'b' on all mounts where 'B'
385 propagates to. A new propagation tree containing 'C1',..,'Cn' is
386 created. This propagation tree is identical to the propagation tree of
387 'B'. And finally the peer-group of 'C' is merged with the peer group
388 of 'A'.
389
390 2. 'A' is a private mount and 'B' is a shared mount. A new mount 'C'
391 which is clone of 'A', is created. Its root dentry is 'a'. 'C' is
392 mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
393 are created and mounted at the dentry 'b' on all mounts where 'B'
394 propagates to. A new propagation tree is set containing all new mounts
395 'C', 'C1', .., 'Cn' with exactly the same configuration as the
396 propagation tree for 'B'.
397
398 3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. A new
399 mount 'C' which is clone of 'A', is created. Its root dentry is 'a' .
400 'C' is mounted on mount 'B' at dentry 'b'. Also new mounts 'C1', 'C2',
401 'C3' ... are created and mounted at the dentry 'b' on all mounts where
402 'B' propagates to. A new propagation tree containing the new mounts
403 'C','C1',.. 'Cn' is created. This propagation tree is identical to the
404 propagation tree for 'B'. And finally the mount 'C' and its peer group
405 is made the slave of mount 'Z'. In other words, mount 'C' is in the
406 state 'slave and shared'.
407
408 4. 'A' is a unbindable mount and 'B' is a shared mount. This is a
409 invalid operation.
410
411 5. 'A' is a private mount and 'B' is a non-shared(private or slave or
412 unbindable) mount. A new mount 'C' which is clone of 'A', is created.
413 Its root dentry is 'a'. 'C' is mounted on mount 'B' at dentry 'b'.
414
415 6. 'A' is a shared mount and 'B' is a non-shared mount. A new mount 'C'
416 which is a clone of 'A' is created. Its root dentry is 'a'. 'C' is
417 mounted on mount 'B' at dentry 'b'. 'C' is made a member of the
418 peer-group of 'A'.
419
420 7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. A
421 new mount 'C' which is a clone of 'A' is created. Its root dentry is
422 'a'. 'C' is mounted on mount 'B' at dentry 'b'. Also 'C' is set as a
423 slave mount of 'Z'. In other words 'A' and 'C' are both slave mounts of
424 'Z'. All mount/unmount events on 'Z' propagates to 'A' and 'C'. But
425 mount/unmount on 'A' do not propagate anywhere else. Similarly
426 mount/unmount on 'C' do not propagate anywhere else.
427
428 8. 'A' is a unbindable mount and 'B' is a non-shared mount. This is a
429 invalid operation. A unbindable mount cannot be bind mounted.
430
431 c) Rbind semantics
432
433 rbind is same as bind. Bind replicates the specified mount. Rbind
434 replicates all the mounts in the tree belonging to the specified mount.
435 Rbind mount is bind mount applied to all the mounts in the tree.
436
437 If the source tree that is rbind has some unbindable mounts,
438 then the subtree under the unbindable mount is pruned in the new
439 location.
440
441 eg:
442
443 let's say we have the following mount tree::
444
445 A
446 / \
447 B C
448 / \ / \
449 D E F G
450
451 Let's say all the mount except the mount C in the tree are
452 of a type other than unbindable.
453
454 If this tree is rbound to say Z
455
456 We will have the following tree at the new location::
457
458 Z
459 |
460 A'
461 /
462 B' Note how the tree under C is pruned
463 / \ in the new location.
464 D' E'
465
466
467
468 d) Move semantics
469
470 Consider the following command::
471
472 mount --move A B/b
473
474 where 'A' is the source mount, 'B' is the destination mount and 'b' is
475 the dentry in the destination mount.
476
477 The outcome depends on the type of the mount of 'A' and 'B'. The table
478 below is a quick reference::
479
480 ---------------------------------------------------------------------------
481 | MOVE MOUNT OPERATION |
482 |**************************************************************************
483 | source(A)->| shared | private | slave | unbindable |
484 | dest(B) | | | | |
485 | | | | | | |
486 | v | | | | |
487 |**************************************************************************
488 | shared | shared | shared |shared and slave| invalid |
489 | | | | | |
490 |non-shared| shared | private | slave | unbindable |
491 ***************************************************************************
492
493 .. Note:: moving a mount residing under a shared mount is invalid.
494
495 Details follow:
496
497 1. 'A' is a shared mount and 'B' is a shared mount. The mount 'A' is
498 mounted on mount 'B' at dentry 'b'. Also new mounts 'A1', 'A2'...'An'
499 are created and mounted at dentry 'b' on all mounts that receive
500 propagation from mount 'B'. A new propagation tree is created in the
501 exact same configuration as that of 'B'. This new propagation tree
502 contains all the new mounts 'A1', 'A2'... 'An'. And this new
503 propagation tree is appended to the already existing propagation tree
504 of 'A'.
505
506 2. 'A' is a private mount and 'B' is a shared mount. The mount 'A' is
507 mounted on mount 'B' at dentry 'b'. Also new mount 'A1', 'A2'... 'An'
508 are created and mounted at dentry 'b' on all mounts that receive
509 propagation from mount 'B'. The mount 'A' becomes a shared mount and a
510 propagation tree is created which is identical to that of
511 'B'. This new propagation tree contains all the new mounts 'A1',
512 'A2'... 'An'.
513
514 3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. The
515 mount 'A' is mounted on mount 'B' at dentry 'b'. Also new mounts 'A1',
516 'A2'... 'An' are created and mounted at dentry 'b' on all mounts that
517 receive propagation from mount 'B'. A new propagation tree is created
518 in the exact same configuration as that of 'B'. This new propagation
519 tree contains all the new mounts 'A1', 'A2'... 'An'. And this new
520 propagation tree is appended to the already existing propagation tree of
521 'A'. Mount 'A' continues to be the slave mount of 'Z' but it also
522 becomes 'shared'.
523
524 4. 'A' is a unbindable mount and 'B' is a shared mount. The operation
525 is invalid. Because mounting anything on the shared mount 'B' can
526 create new mounts that get mounted on the mounts that receive
527 propagation from 'B'. And since the mount 'A' is unbindable, cloning
528 it to mount at other mountpoints is not possible.
529
530 5. 'A' is a private mount and 'B' is a non-shared(private or slave or
531 unbindable) mount. The mount 'A' is mounted on mount 'B' at dentry 'b'.
532
533 6. 'A' is a shared mount and 'B' is a non-shared mount. The mount 'A'
534 is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a
535 shared mount.
536
537 7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount.
538 The mount 'A' is mounted on mount 'B' at dentry 'b'. Mount 'A'
539 continues to be a slave mount of mount 'Z'.
540
541 8. 'A' is a unbindable mount and 'B' is a non-shared mount. The mount
542 'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a
543 unbindable mount.
544
545 e) Mount semantics
546
547 Consider the following command::
548
549 mount device B/b
550
551 'B' is the destination mount and 'b' is the dentry in the destination
552 mount.
553
554 The above operation is the same as bind operation with the exception
555 that the source mount is always a private mount.
556
557
558 f) Unmount semantics
559
560 Consider the following command::
561
562 umount A
563
564 where 'A' is a mount mounted on mount 'B' at dentry 'b'.
565
566 If mount 'B' is shared, then all most-recently-mounted mounts at dentry
567 'b' on mounts that receive propagation from mount 'B' and does not have
568 sub-mounts within them are unmounted.
569
570 Example: Let's say 'B1', 'B2', 'B3' are shared mounts that propagate to
571 each other.
572
573 let's say 'A1', 'A2', 'A3' are first mounted at dentry 'b' on mount
574 'B1', 'B2' and 'B3' respectively.
575
576 let's say 'C1', 'C2', 'C3' are next mounted at the same dentry 'b' on
577 mount 'B1', 'B2' and 'B3' respectively.
578
579 if 'C1' is unmounted, all the mounts that are most-recently-mounted on
580 'B1' and on the mounts that 'B1' propagates-to are unmounted.
581
582 'B1' propagates to 'B2' and 'B3'. And the most recently mounted mount
583 on 'B2' at dentry 'b' is 'C2', and that of mount 'B3' is 'C3'.
584
585 So all 'C1', 'C2' and 'C3' should be unmounted.
586
587 If any of 'C2' or 'C3' has some child mounts, then that mount is not
588 unmounted, but all other mounts are unmounted. However if 'C1' is told
589 to be unmounted and 'C1' has some sub-mounts, the umount operation is
590 failed entirely.
591
592 g) Clone Namespace
593
594 A cloned namespace contains all the mounts as that of the parent
595 namespace.
596
597 Let's say 'A' and 'B' are the corresponding mounts in the parent and the
598 child namespace.
599
600 If 'A' is shared, then 'B' is also shared and 'A' and 'B' propagate to
601 each other.
602
603 If 'A' is a slave mount of 'Z', then 'B' is also the slave mount of
604 'Z'.
605
606 If 'A' is a private mount, then 'B' is a private mount too.
607
608 If 'A' is unbindable mount, then 'B' is a unbindable mount too.
609
610
611 6) Quiz
612 -------
613
614 A. What is the result of the following command sequence?
615
616 ::
617
618 mount --bind /mnt /mnt
619 mount --make-shared /mnt
620 mount --bind /mnt /tmp
621 mount --move /tmp /mnt/1
622
623 what should be the contents of /mnt /mnt/1 /mnt/1/1 should be?
624 Should they all be identical? or should /mnt and /mnt/1 be
625 identical only?
626
627
628 B. What is the result of the following command sequence?
629
630 ::
631
632 mount --make-rshared /
633 mkdir -p /v/1
634 mount --rbind / /v/1
635
636 what should be the content of /v/1/v/1 be?
637
638
639 C. What is the result of the following command sequence?
640
641 ::
642
643 mount --bind /mnt /mnt
644 mount --make-shared /mnt
645 mkdir -p /mnt/1/2/3 /mnt/1/test
646 mount --bind /mnt/1 /tmp
647 mount --make-slave /mnt
648 mount --make-shared /mnt
649 mount --bind /mnt/1/2 /tmp1
650 mount --make-slave /mnt
651
652 At this point we have the first mount at /tmp and
653 its root dentry is 1. Let's call this mount 'A'
654 And then we have a second mount at /tmp1 with root
655 dentry 2. Let's call this mount 'B'
656 Next we have a third mount at /mnt with root dentry
657 mnt. Let's call this mount 'C'
658
659 'B' is the slave of 'A' and 'C' is a slave of 'B'
660 A -> B -> C
661
662 at this point if we execute the following command::
663
664 mount --bind /bin /tmp/test
665
666 The mount is attempted on 'A'
667
668 will the mount propagate to 'B' and 'C' ?
669
670 what would be the contents of
671 /mnt/1/test be?
672
673 7) FAQ
674 ------
675
676 1. Why is bind mount needed? How is it different from symbolic links?
677
678 symbolic links can get stale if the destination mount gets
679 unmounted or moved. Bind mounts continue to exist even if the
680 other mount is unmounted or moved.
681
682 2. Why can't the shared subtree be implemented using exportfs?
683
684 exportfs is a heavyweight way of accomplishing part of what
685 shared subtree can do. I cannot imagine a way to implement the
686 semantics of slave mount using exportfs?
687
688 3. Why is unbindable mount needed?
689
690 Let's say we want to replicate the mount tree at multiple
691 locations within the same subtree.
692
693 if one rbind mounts a tree within the same subtree 'n' times
694 the number of mounts created is an exponential function of 'n'.
695 Having unbindable mount can help prune the unneeded bind
696 mounts. Here is an example.
697
698 step 1:
699 let's say the root tree has just two directories with
700 one vfsmount::
701
702 root
703 / \
704 tmp usr
705
706 And we want to replicate the tree at multiple
707 mountpoints under /root/tmp
708
709 step 2:
710 ::
711
712
713 mount --make-shared /root
714
715 mkdir -p /tmp/m1
716
717 mount --rbind /root /tmp/m1
718
719 the new tree now looks like this::
720
721 root
722 / \
723 tmp usr
724 /
725 m1
726 / \
727 tmp usr
728 /
729 m1
730
731 it has two vfsmounts
732
733 step 3:
734 ::
735
736 mkdir -p /tmp/m2
737 mount --rbind /root /tmp/m2
738
739 the new tree now looks like this::
740
741 root
742 / \
743 tmp usr
744 / \
745 m1 m2
746 / \ / \
747 tmp usr tmp usr
748 / \ /
749 m1 m2 m1
750 / \ / \
751 tmp usr tmp usr
752 / / \
753 m1 m1 m2
754 / \
755 tmp usr
756 / \
757 m1 m2
758
759 it has 6 vfsmounts
760
761 step 4:
762 ::
763
764 mkdir -p /tmp/m3
765 mount --rbind /root /tmp/m3
766
767 I won't draw the tree..but it has 24 vfsmounts
768
769
770 at step i the number of vfsmounts is V[i] = i*V[i-1].
771 This is an exponential function. And this tree has way more
772 mounts than what we really needed in the first place.
773
774 One could use a series of umount at each step to prune
775 out the unneeded mounts. But there is a better solution.
776 Unclonable mounts come in handy here.
777
778 step 1:
779 let's say the root tree has just two directories with
780 one vfsmount::
781
782 root
783 / \
784 tmp usr
785
786 How do we set up the same tree at multiple locations under
787 /root/tmp
788
789 step 2:
790 ::
791
792
793 mount --bind /root/tmp /root/tmp
794
795 mount --make-rshared /root
796 mount --make-unbindable /root/tmp
797
798 mkdir -p /tmp/m1
799
800 mount --rbind /root /tmp/m1
801
802 the new tree now looks like this::
803
804 root
805 / \
806 tmp usr
807 /
808 m1
809 / \
810 tmp usr
811
812 step 3:
813 ::
814
815 mkdir -p /tmp/m2
816 mount --rbind /root /tmp/m2
817
818 the new tree now looks like this::
819
820 root
821 / \
822 tmp usr
823 / \
824 m1 m2
825 / \ / \
826 tmp usr tmp usr
827
828 step 4:
829 ::
830
831 mkdir -p /tmp/m3
832 mount --rbind /root /tmp/m3
833
834 the new tree now looks like this::
835
836 root
837 / \
838 tmp usr
839 / \ \
840 m1 m2 m3
841 / \ / \ / \
842 tmp usr tmp usr tmp usr
843
844 8) Implementation
845 -----------------
846
847 A) Datastructure
848
849 Several new fields are introduced to struct vfsmount:
850
851 ->mnt_share
852 Links together all the mount to/from which this vfsmount
853 send/receives propagation events.
854
855 ->mnt_slave_list
856 Links all the mounts to which this vfsmount propagates
857 to.
858
859 ->mnt_slave
860 Links together all the slaves that its master vfsmount
861 propagates to.
862
863 ->mnt_master
864 Points to the master vfsmount from which this vfsmount
865 receives propagation.
866
867 ->mnt_flags
868 Takes two more flags to indicate the propagation status of
869 the vfsmount. MNT_SHARE indicates that the vfsmount is a shared
870 vfsmount. MNT_UNCLONABLE indicates that the vfsmount cannot be
871 replicated.
872
873 All the shared vfsmounts in a peer group form a cyclic list through
874 ->mnt_share.
875
876 All vfsmounts with the same ->mnt_master form on a cyclic list anchored
877 in ->mnt_master->mnt_slave_list and going through ->mnt_slave.
878
879 ->mnt_master can point to arbitrary (and possibly different) members
880 of master peer group. To find all immediate slaves of a peer group
881 you need to go through _all_ ->mnt_slave_list of its members.
882 Conceptually it's just a single set - distribution among the
883 individual lists does not affect propagation or the way propagation
884 tree is modified by operations.
885
886 All vfsmounts in a peer group have the same ->mnt_master. If it is
887 non-NULL, they form a contiguous (ordered) segment of slave list.
888
889 A example propagation tree looks as shown in the figure below.
890
891 .. note::
892 Though it looks like a forest, if we consider all the shared
893 mounts as a conceptual entity called 'pnode', it becomes a tree.
894
895 ::
896
897
898 A <--> B <--> C <---> D
899 /|\ /| |\
900 / F G J K H I
901 /
902 E<-->K
903 /|\
904 M L N
905
906 In the above figure A,B,C and D all are shared and propagate to each
907 other. 'A' has got 3 slave mounts 'E' 'F' and 'G' 'C' has got 2 slave
908 mounts 'J' and 'K' and 'D' has got two slave mounts 'H' and 'I'.
909 'E' is also shared with 'K' and they propagate to each other. And
910 'K' has 3 slaves 'M', 'L' and 'N'
911
912 A's ->mnt_share links with the ->mnt_share of 'B' 'C' and 'D'
913
914 A's ->mnt_slave_list links with ->mnt_slave of 'E', 'K', 'F' and 'G'
915
916 E's ->mnt_share links with ->mnt_share of K
917
918 'E', 'K', 'F', 'G' have their ->mnt_master point to struct vfsmount of 'A'
919
920 'M', 'L', 'N' have their ->mnt_master point to struct vfsmount of 'K'
921
922 K's ->mnt_slave_list links with ->mnt_slave of 'M', 'L' and 'N'
923
924 C's ->mnt_slave_list links with ->mnt_slave of 'J' and 'K'
925
926 J and K's ->mnt_master points to struct vfsmount of C
927
928 and finally D's ->mnt_slave_list links with ->mnt_slave of 'H' and 'I'
929
930 'H' and 'I' have their ->mnt_master pointing to struct vfsmount of 'D'.
931
932
933 NOTE: The propagation tree is orthogonal to the mount tree.
934
935 B) Locking:
936
937 ->mnt_share, ->mnt_slave, ->mnt_slave_list, ->mnt_master are protected
938 by namespace_sem (exclusive for modifications, shared for reading).
939
940 Normally we have ->mnt_flags modifications serialized by vfsmount_lock.
941 There are two exceptions: do_add_mount() and clone_mnt().
942 The former modifies a vfsmount that has not been visible in any shared
943 data structures yet.
944 The latter holds namespace_sem and the only references to vfsmount
945 are in lists that can't be traversed without namespace_sem.
946
947 C) Algorithm:
948
949 The crux of the implementation resides in rbind/move operation.
950
951 The overall algorithm breaks the operation into 3 phases: (look at
952 attach_recursive_mnt() and propagate_mnt())
953
954 1. Prepare phase.
955
956 For each mount in the source tree:
957
958 a) Create the necessary number of mount trees to
959 be attached to each of the mounts that receive
960 propagation from the destination mount.
961 b) Do not attach any of the trees to its destination.
962 However note down its ->mnt_parent and ->mnt_mountpoint
963 c) Link all the new mounts to form a propagation tree that
964 is identical to the propagation tree of the destination
965 mount.
966
967 If this phase is successful, there should be 'n' new
968 propagation trees; where 'n' is the number of mounts in the
969 source tree. Go to the commit phase
970
971 Also there should be 'm' new mount trees, where 'm' is
972 the number of mounts to which the destination mount
973 propagates to.
974
975 If any memory allocations fail, go to the abort phase.
976
977 2. Commit phase.
978
979 Attach each of the mount trees to their corresponding
980 destination mounts.
981
982 3. Abort phase.
983
984 Delete all the newly created trees.
985
986 .. Note::
987 all the propagation related functionality resides in the file pnode.c
988
989
990 ------------------------------------------------------------------------
991
992 version 0.1 (created the initial document, Ram Pai [email protected])
993
994 version 0.2 (Incorporated comments from Al Viro)
995

3. 한국어 전문 번역

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

개요와 네 가지 전파 유형

1-34

공유 서브트리(shared subtree)는 프로세스가 자신의 mount namespace를 복제한 뒤에도 부모 namespace에서 새로 마운트된 CD 같은 자원을 볼 수 있게 하는 전파 규칙이다. 이 규칙은 사용자별 namespace와 버전 파일 시스템 같은 기능을 조립하는 기반도 제공한다.

전파 속성은 정확히는 `struct vfsmount` 단위로 적용된다. 문서는 shared, slave, private, unbindable의 네 유형을 소개한 다음 상태 변경, 실제 사용 사례, 연산별 상세 의미, 구현 자료구조와 알고리즘을 설명한다.

마운트 전파 유형
상태이벤트 수신이벤트 송신bind 복제
sharedpeer와 master에서 수신 가능peer와 slave로 전달가능
slavemaster에서 수신master로 역전파하지 않음가능
private수신하지 않음전달하지 않음가능
unbindable수신하지 않음전달하지 않음불가능

이벤트를 보내고 받는 방향과 bind 가능 여부를 함께 비교한다.

.. SPDX-License-Identifier: GPL-2.0

===============
Shared Subtrees
===============

.. Contents:
        1) Overview
        2) Features
        3) Setting mount states
        4) Use-case
        5) Detailed semantics
        6) Quiz
        7) FAQ
        8) Implementation


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

Consider the following situation:

A process wants to clone its own namespace, but still wants to access the CD
that got mounted recently.  Shared subtree semantics provide the necessary
mechanism to accomplish the above.

It provides the necessary building blocks for features like per-user-namespace
and versioned filesystem.

2) Features
-----------

Shared subtree provides four different flavors of mounts; struct vfsmount to be
precise:

Shared mount의 양방향 전파

35-81

shared mount는 여러 mountpoint에 복제할 수 있으며, 모든 복제본은 같은 peer group에 속해 계속 동일한 전파 관계를 유지한다. `/mnt`를 shared로 만든 뒤 `/tmp`에 bind mount하면 두 위치의 기존 내용뿐 아니라 이후의 mount·umount 이벤트도 서로에게 전파된다.

예제에서 `/dev/sd0`를 `/tmp/a`에 마운트하면 `/mnt/a`에서도 `t1 t2 t3`을 볼 수 있다. 반대로 `/mnt/a`에 마운트해도 `/tmp/a`에 나타난다. 현재 `mount(8)`은 `--make-shared`를 직접 지원하므로 예전의 `smount` 예제 프로그램은 필요 없어 제거되었다.

Shared peer group
`mount --make-shared /mnt``mount --bind /mnt /tmp`로 같은 peer group 형성`/tmp/a`에 `/dev/sd0` 마운트이벤트가 `/mnt/a`로 전파반대 방향의 이벤트도 같은 방식으로 전파

`/mnt`와 `/tmp` 사이에서는 새 하위 마운트가 양방향으로 전파된다.



a) A **shared mount** can be replicated to as many mountpoints and all the
   replicas continue to be exactly same.

   Here is an example:

   Let's say /mnt has a mount that is shared::

     # mount --make-shared /mnt

   .. note::
      mount(8) command now supports the --make-shared flag,
      so the sample 'smount' program is no longer needed and has been
      removed.

   ::

     # mount --bind /mnt /tmp

   The above command replicates the mount at /mnt to the mountpoint /tmp
   and the contents of both the mounts remain identical.

   ::

     #ls /mnt
     a b c

     #ls /tmp
     a b c

   Now let's say we mount a device at /tmp/a::

     # mount /dev/sd0  /tmp/a

     # ls /tmp/a
     t1 t2 t3

     # ls /mnt/a
     t1 t2 t3

   Note that the mount has propagated to the mount at /mnt as well.

   And the same is true even when /dev/sd0 is mounted on /mnt/a. The
   contents will be visible under /tmp/a too.

Slave mount의 단방향 전파

82-129

slave mount는 shared mount와 비슷하지만 mount·umount 이벤트가 master에서 slave 방향으로만 흐른다. 모든 slave에는 shared 상태인 master가 있다.

예제에서는 shared `/mnt`를 `/tmp`로 bind한 뒤 `/tmp`를 `--make-slave`로 바꾼다. `/mnt/a`에 마운트한 `/dev/sd0`는 `/tmp/a`에 전파되지만, slave인 `/tmp/b`에 마운트한 `/dev/sd1`은 master의 `/mnt/b`로 되돌아가지 않는다.

Master에서 slave로만 전파
shared master `/mnt`bind 복제 `/tmp``mount --make-slave /tmp``/mnt`의 이벤트 → `/tmp`에 도착`/tmp`의 이벤트 → `/mnt`로 전달되지 않음

화살표의 역방향은 차단된다.

b) A **slave mount** is like a shared mount except that mount and umount events
   only propagate towards it.

   All slave mounts have a master mount which is a shared.

   Here is an example:

   Let's say /mnt has a mount which is shared::

     # mount --make-shared /mnt

   Let's bind mount /mnt to /tmp::

     # mount --bind /mnt /tmp

   the new mount at /tmp becomes a shared mount and it is a replica of
   the mount at /mnt.

   Now let's make the mount at /tmp; a slave of /mnt::

     # mount --make-slave /tmp

   let's mount /dev/sd0 on /mnt/a::

     # mount /dev/sd0 /mnt/a

     # ls /mnt/a
     t1 t2 t3

     # ls /tmp/a
     t1 t2 t3

   Note the mount event has propagated to the mount at /tmp

   However let's see what happens if we mount something on the mount at
   /tmp::

     # mount /dev/sd1 /tmp/b

     # ls /tmp/b
     s1 s2 s3

     # ls /mnt/b

   Note how the mount event has not propagated to the mount at
   /mnt

Private·unbindable과 상태 설정 명령

130-161

private mount는 전파 이벤트를 보내지도 받지도 않는 익숙한 기본 유형이다. unbindable mount는 private의 성질에 더해 bind mount의 원본으로 사용할 수도 없다.

따라서 `/mnt`에 `mount --make-unbindable /mnt`를 실행한 다음 이를 `/tmp`로 bind하려는 시도는 잘못된 연산으로 실패한다. util-linux의 `mount` 명령은 `--make-shared`, `--make-slave`, `--make-private`, `--make-unbindable`로 각 상태를 지정한다.

상태 변경 명령
명령결과
`mount --make-shared mountpoint`peer group에 속하는 shared 상태
`mount --make-slave mountpoint`master의 이벤트만 받는 slave 상태
`mount --make-private mountpoint`전파가 완전히 차단된 상태
`mount --make-unbindable mountpoint`bind도 금지된 private 상태

명령은 지정한 mountpoint의 전파 속성을 바꾼다.

c) A **private mount** does not forward or receive propagation.

   This is the mount we are familiar with. Its the default type.


d) An **unbindable mount** is, as the name suggests, an unbindable private
   mount.

   let's say we have a mount at /mnt and we make it unbindable::

     # mount --make-unbindable /mnt

   Let's try to bind mount this mount somewhere else::

     # mount --bind /mnt /tmp mount: wrong fs type, bad option, bad
     superblock on /mnt, or too many mounted file systems

   Binding a unbindable mount is a invalid operation.


3) Setting mount states
-----------------------

The mount command (util-linux package) can be used to set mount
states::

    mount --make-shared mountpoint
    mount --make-slave mountpoint
    mount --make-private mountpoint
    mount --make-unbindable mountpoint

Namespace·개인 트리·버전 파일 사용 사례

162-239

첫 번째 사용 사례는 복제한 namespace에서도 새 CD mount를 보는 것이다. 관리자가 `/cdrom`을 자기 자신에 bind한 뒤 shared로 만들면, 자식 namespace의 `/cdrom`은 부모의 복제본이 된다. 이후 어느 namespace에서든 `/cdrom` 아래에 생긴 mount가 peer에 전파된다.

두 번째는 프로세스 자신의 mount는 감추되 시스템의 mount는 계속 받는 구성이다. 관리자는 전체 트리를 `mount --make-rshared /`로 공유하고, 새 namespace의 `/myprivatetree`만 `mount --make-rslave`로 바꾼다. 그러면 부모 쪽 변경은 자식에게 보이지만 자식의 사적 변경은 다른 namespace로 새지 않는다.

이 의미론은 사용자별 namespace에도 활용할 수 있다. namespace를 사용자 ID와 연결·해제할 수 있는 일급 객체로 만들고 PAM이 이를 지원한다면 사용자마다 요구에 맞는 mount view를 가질 수 있다.

버전 파일 시스템에서는 전체 mount tree를 `/view/v1`부터 `/view/v4`까지 `--rbind`한다. `/usr`의 기반 파일 시스템은 접근 경로를 보고 `/view/v3/usr/fs/namespace.c` 요청이 v3임을 판별해 해당 inode를 반환할 수 있다.

대표 사용 사례
목표핵심 설정효과
새 CD 공유`/cdrom` self-bind 후 shared복제 namespace 모두 새 mount 수신
자식의 사적 트리루트 rshared, 일부 rslave부모→자식만 전파
사용자별 viewnamespace와 user ID 연결사용자별 mount 구성
버전 view루트를 여러 `/view/vN`에 rbind경로로 버전 선택

전파 방향을 조합해 namespace별 가시성을 정한다.

4) Use cases
------------

A) A process wants to clone its own namespace, but still wants to
   access the CD that got mounted recently.

   Solution:

   The system administrator can make the mount at /cdrom shared::

     mount --bind /cdrom /cdrom
     mount --make-shared /cdrom

   Now any process that clones off a new namespace will have a
   mount at /cdrom which is a replica of the same mount in the
   parent namespace.

   So when a CD is inserted and mounted at /cdrom that mount gets
   propagated to the other mount at /cdrom in all the other clone
   namespaces.

B) A process wants its mounts invisible to any other process, but
   still be able to see the other system mounts.

   Solution:

   To begin with, the administrator can mark the entire mount tree
   as shareable::

     mount --make-rshared /

   A new process can clone off a new namespace. And mark some part
   of its namespace as slave::

     mount --make-rslave /myprivatetree

   Hence forth any mounts within the /myprivatetree done by the
   process will not show up in any other namespace. However mounts
   done in the parent namespace under /myprivatetree still shows
   up in the process's namespace.


Apart from the above semantics this feature provides the
building blocks to solve the following problems:

C)  Per-user namespace

    The above semantics allows a way to share mounts across
    namespaces.  But namespaces are associated with processes. If
    namespaces are made first class objects with user API to
    associate/disassociate a namespace with userid, then each user
    could have his/her own namespace and tailor it to his/her
    requirements. This needs to be supported in PAM.

D)  Versioned files

    If the entire mount tree is visible at multiple locations, then
    an underlying versioning file system can return different
    versions of the file depending on the path used to access that
    file.

    An example is::

       mount --make-shared /
       mount --rbind / /view/v1
       mount --rbind / /view/v2
       mount --rbind / /view/v3
       mount --rbind / /view/v4

    and if /usr has a versioning filesystem mounted, then that
    mount appears at /view/v1/usr, /view/v2/usr, /view/v3/usr and
    /view/v4/usr too

    A user can request v3 version of the file /usr/fs/namespace.c
    by accessing /view/v3/usr/fs/namespace.c . The underlying
    versioning filesystem can then decipher that v3 version of the
    filesystem is being requested and return the corresponding
    inode.

전파 이벤트·peer group과 다섯 상태

240-321

이 문서에서 `vfsmount`와 mount라는 명사는 같은 뜻으로 사용한다. 전파 이벤트는 한 vfsmount에서 발생해 다른 vfsmount의 mount 또는 unmount 동작을 일으키는 사건이며, peer group은 서로에게 이벤트를 전파하는 vfsmount 집합이다.

shared mount는 peer group의 구성원이다. `/mnt`를 shared로 만들고 `/tmp`로 bind하면 두 mount가 같은 peer group이 되어 어느 쪽 아래의 변경도 다른 구성원에 반영된다.

slave mount는 전파 이벤트를 받지만 보내지 않는다. `mount --make-slave mount`는 shared mount를 slave로 바꿀 수 있다. 이때 peer group의 유일한 구성원이라 master가 없으면 private이 되며, 그렇지 않으면 일반적으로 shared 속성을 잃는다.

shared and slave 상태는 어떤 peer group의 slave이면서 동시에 자체 peer group을 가진다. master의 이벤트를 받아 자신의 peer와 slave로 전달한다. slave에 `--make-shared`를 실행하거나 shared mount 아래로 이동하면 이 상태가 될 수 있다.

private은 이벤트를 보내거나 받지 않으며, unbindable은 여기에 bind 복제 금지를 더한다.

Shared and slave의 전파
상위 master peer group이벤트를 slave peer group이 수신그룹 안의 shared peer들에게 전달그 그룹의 하위 slave들에게 다시 전달하위에서 master 방향으로는 역전파하지 않음

한 mount가 수신 경로와 자체 peer 전파 경로를 동시에 가질 수 있다.


5) Detailed semantics
---------------------
The section below explains the detailed semantics of
bind, rbind, move, mount, umount and clone-namespace operations.

.. Note::
   the word 'vfsmount' and the noun 'mount' have been used
   to mean the same thing, throughout this document.

a) Mount states

   A **propagation event** is defined as event generated on a vfsmount
   that leads to mount or unmount actions in other vfsmounts.

   A **peer group** is defined as a group of vfsmounts that propagate
   events to each other.

   A given mount can be in one of the following states:

   (1) Shared mounts

       A **shared mount** is defined as a vfsmount that belongs to a
       peer group.

       For example::

         mount --make-shared /mnt
         mount --bind /mnt /tmp

       The mount at /mnt and that at /tmp are both shared and belong
       to the same peer group. Anything mounted or unmounted under
       /mnt or /tmp reflect in all the other mounts of its peer
       group.


   (2) Slave mounts

       A **slave mount** is defined as a vfsmount that receives
       propagation events and does not forward propagation events.

       A slave mount as the name implies has a master mount from which
       mount/unmount events are received. Events do not propagate from
       the slave mount to the master.  Only a shared mount can be made
       a slave by executing the following command::

         mount --make-slave mount

       A shared mount that is made as a slave is no more shared unless
       modified to become shared.

   (3) Shared and Slave

       A vfsmount can be both **shared** as well as **slave**.  This state
       indicates that the mount is a slave of some vfsmount, and
       has its own peer group too.  This vfsmount receives propagation
       events from its master vfsmount, and also forwards propagation
       events to its 'peer group' and to its slave vfsmounts.

       Strictly speaking, the vfsmount is shared having its own
       peer group, and this peer-group is a slave of some other
       peer group.

       Only a slave vfsmount can be made as 'shared and slave' by
       either executing the following command::

         mount --make-shared mount

       or by moving the slave vfsmount under a shared vfsmount.

   (4) Private mount

       A **private mount** is defined as vfsmount that does not
       receive or forward any propagation events.

   (5) Unbindable mount

       A **unbindable mount** is defined as vfsmount that does not
       receive or forward any propagation events and cannot
       be bind mounted.

마운트 상태 전이표

322-353

다음 표는 현재 상태에 각 `--make-*` 명령을 적용한 결과다. shared mount를 slave로 바꿀 때 peer group에 자기 혼자뿐이면 연결할 master가 없어 private이 된다. 반대로 non-shared mount에 slave 명령을 적용해도 효과가 없다.

표에 없는 `mount --move`도 목적지 mount의 유형에 따라 상태를 바꿀 수 있으며, 그 세부 규칙은 move 의미론에서 설명한다.

Mount propagation 상태 전이
현재 상태make-sharedmake-slavemake-privatemake-unbindable
sharedsharedslave 또는 private*privateunbindable
slaveshared and slaveslave**privateunbindable
shared and slaveshared and slaveslaveprivateunbindable
privatesharedprivate**privateunbindable
unbindablesharedunbindable**privateunbindable

행은 현재 상태, 열은 실행할 명령이다.

`*` peer가 하나인 shared mount는 slave로 만들 master가 없어 자동으로 private이 된다. `**` non-shared mount를 slave로 만드는 명령은 상태를 바꾸지 않는다.

       State diagram:

       The state diagram below explains the state transition of a mount,
       in response to various commands::

            -----------------------------------------------------------------------
            |             |make-shared |  make-slave  | make-private |make-unbindab|
            --------------|------------|--------------|--------------|-------------|
            |shared       |shared      |*slave/private|   private    | unbindable  |
            |             |            |              |              |             |
            |-------------|------------|--------------|--------------|-------------|
            |slave        |shared      | **slave      |    private   | unbindable  |
            |             |and slave   |              |              |             |
            |-------------|------------|--------------|--------------|-------------|
            |shared       |shared      | slave        |    private   | unbindable  |
            |and slave    |and slave   |              |              |             |
            |-------------|------------|--------------|--------------|-------------|
            |private      |shared      |  **private   |    private   | unbindable  |
            |-------------|------------|--------------|--------------|-------------|
            |unbindable   |shared      |**unbindable  |    private   | unbindable  |
            ------------------------------------------------------------------------

            * if the shared mount is the only mount in its peer group, making it
            slave, makes it private automatically. Note that there is no master to
            which it can be slaved to.

            ** slaving a non-shared mount has no effect on the mount.

       Apart from the commands listed below, the 'move' operation also changes
       the state of a mount depending on type of the destination mount. Its
       explained in section 5d.

Bind 연산의 상태 조합

354-430

`mount --bind A/a B/b`에서 `A`는 원본 mount, `a`는 그 안의 dentry, `B`는 목적지 mount, `b`는 목적지 dentry다. 결과는 원본과 목적지의 전파 상태 조합에 따라 달라진다.

Bind mount 결과
목적지 B원본 shared원본 private원본 slave원본 unbindable
sharedsharedsharedshared and slaveinvalid
non-sharedsharedprivateslaveinvalid

열은 원본 A, 행은 목적지 B의 유형이다.

목적지 `B`가 shared이면 `A`의 clone `C`뿐 아니라 `B`가 전파하는 모든 위치에 `C1`부터 `Cn`까지 만들어진다. 이 새 전파 트리는 `B`의 전파 트리와 같은 모양이다. 원본이 shared이면 `C`의 peer group을 `A`와 합치고, private이면 새 clone들끼리 목적지와 같은 전파 구성을 만든다.

원본 `A`가 `Z`의 slave이면 shared 목적지에 생긴 `C`와 그 peer group도 `Z`의 slave가 되므로 `C`는 shared and slave 상태다. 원본이 unbindable이면 목적지가 shared인지와 관계없이 bind 자체가 잘못된 연산이다.

목적지가 non-shared라면 clone 하나만 `B/b`에 붙는다. shared 원본의 clone은 `A`의 peer group 구성원이 되고, `Z`의 slave 원본을 복제한 `C`는 `A`와 함께 `Z`의 slave가 된다. `A`와 `C`의 로컬 이벤트는 서로에게 전파되지 않는다.

b) Bind semantics

   Consider the following command::

     mount --bind A/a  B/b

   where 'A' is the source mount, 'a' is the dentry in the mount 'A', 'B'
   is the destination mount and 'b' is the dentry in the destination mount.

   The outcome depends on the type of mount of 'A' and 'B'. The table
   below contains quick reference::

            --------------------------------------------------------------------------
            |         BIND MOUNT OPERATION                                           |
            |************************************************************************|
            |source(A)->| shared      |       private  |       slave    | unbindable |
            | dest(B)  |              |                |                |            |
            |   |      |              |                |                |            |
            |   v      |              |                |                |            |
            |************************************************************************|
            |  shared  | shared       |     shared     | shared & slave |  invalid   |
            |          |              |                |                |            |
            |non-shared| shared       |      private   |      slave     |  invalid   |
            **************************************************************************

   Details:

   1. 'A' is a shared mount and 'B' is a shared mount. A new mount 'C'
      which is clone of 'A', is created. Its root dentry is 'a' . 'C' is
      mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
      are created and mounted at the dentry 'b' on all mounts where 'B'
      propagates to. A new propagation tree containing 'C1',..,'Cn' is
      created. This propagation tree is identical to the propagation tree of
      'B'.  And finally the peer-group of 'C' is merged with the peer group
      of 'A'.

   2. 'A' is a private mount and 'B' is a shared mount. A new mount 'C'
      which is clone of 'A', is created. Its root dentry is 'a'. 'C' is
      mounted on mount 'B' at dentry 'b'. Also new mount 'C1', 'C2', 'C3' ...
      are created and mounted at the dentry 'b' on all mounts where 'B'
      propagates to. A new propagation tree is set containing all new mounts
      'C', 'C1', .., 'Cn' with exactly the same configuration as the
      propagation tree for 'B'.

   3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount. A new
      mount 'C' which is clone of 'A', is created. Its root dentry is 'a' .
      'C' is mounted on mount 'B' at dentry 'b'. Also new mounts 'C1', 'C2',
      'C3' ... are created and mounted at the dentry 'b' on all mounts where
      'B' propagates to. A new propagation tree containing the new mounts
      'C','C1',..  'Cn' is created. This propagation tree is identical to the
      propagation tree for 'B'. And finally the mount 'C' and its peer group
      is made the slave of mount 'Z'.  In other words, mount 'C' is in the
      state 'slave and shared'.

   4. 'A' is a unbindable mount and 'B' is a shared mount. This is a
      invalid operation.

   5. 'A' is a private mount and 'B' is a non-shared(private or slave or
      unbindable) mount. A new mount 'C' which is clone of 'A', is created.
      Its root dentry is 'a'. 'C' is mounted on mount 'B' at dentry 'b'.

   6. 'A' is a shared mount and 'B' is a non-shared mount. A new mount 'C'
      which is a clone of 'A' is created. Its root dentry is 'a'. 'C' is
      mounted on mount 'B' at dentry 'b'.  'C' is made a member of the
      peer-group of 'A'.

   7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount. A
      new mount 'C' which is a clone of 'A' is created. Its root dentry is
      'a'.  'C' is mounted on mount 'B' at dentry 'b'. Also 'C' is set as a
      slave mount of 'Z'. In other words 'A' and 'C' are both slave mounts of
      'Z'.  All mount/unmount events on 'Z' propagates to 'A' and 'C'. But
      mount/unmount on 'A' do not propagate anywhere else. Similarly
      mount/unmount on 'C' do not propagate anywhere else.

   8. 'A' is a unbindable mount and 'B' is a non-shared mount. This is a
      invalid operation. A unbindable mount cannot be bind mounted.

Rbind와 unbindable 가지치기

431-467

rbind는 bind를 지정 mount 하나가 아니라 그 아래 mount tree 전체에 적용한다. 원본 트리에 unbindable mount가 있으면 새 위치에서는 그 mount와 아래 subtree가 복제 대상에서 잘려 나간다.

예제 트리 `A` 아래에 `B`, `C`가 있고 각각 두 자식이 있을 때 `C`만 unbindable이라면, `Z`로 rbind한 결과는 `Z/A'/B'`와 `D'`, `E'`만 남는다. `C`, `F`, `G` 가지 전체는 복제되지 않는다.

Rbind 가지치기
원본 경로상태새 위치
Abind 가능Z/A'
A/Bbind 가능Z/A'/B'
A/B/D, A/B/Ebind 가능D', E' 복제
A/CunbindableC 이하 전체 제외
A/C/F, A/C/G잘린 subtree복제 없음

원본과 복제 결과를 노드 경로로 비교한다.

c) Rbind semantics

   rbind is same as bind. Bind replicates the specified mount.  Rbind
   replicates all the mounts in the tree belonging to the specified mount.
   Rbind mount is bind mount applied to all the mounts in the tree.

   If the source tree that is rbind has some unbindable mounts,
   then the subtree under the unbindable mount is pruned in the new
   location.

   eg:

   let's say we have the following mount tree::

                A
              /   \
              B   C
             / \ / \
             D E F G

   Let's say all the mount except the mount C in the tree are
   of a type other than unbindable.

   If this tree is rbound to say Z

   We will have the following tree at the new location::

                Z
                |
                A'
               /
              B'                Note how the tree under C is pruned
             / \                in the new location.
            D' E'


Move 연산과 목적지 전파

468-544

`mount --move A B/b`는 원본 mount `A`를 목적지 `B`의 dentry `b`로 옮긴다. shared mount 아래에 놓여 있는 mount를 원본으로 이동하는 것은 허용되지 않는다.

Move mount 결과
목적지 B원본 shared원본 private원본 slave원본 unbindable
sharedsharedsharedshared and slaveinvalid
non-sharedsharedprivateslaveunbindable

열은 원본 A, 행은 목적지 B의 유형이다.

shared 목적지에서는 `A`를 `B/b`에 붙이는 동시에 `B`의 모든 전파 대상에 `A1`부터 `An`을 생성한다. 원본이 shared이면 새 전파 트리를 기존 `A` 전파 트리에 덧붙인다. private 원본은 shared로 바뀌고, slave 원본은 master `Z`의 slave 관계를 유지하면서 shared도 된다.

unbindable 원본을 shared 목적지로 옮기면 목적지 전파 때문에 clone이 필요하지만 unbindable은 복제할 수 없으므로 연산이 실패한다. 목적지가 non-shared이면 추가 clone이 필요 없어 private·shared·slave·unbindable 원본 모두 자신의 상태를 유지한 채 이동할 수 있다.

d) Move semantics

   Consider the following command::

     mount --move A  B/b

   where 'A' is the source mount, 'B' is the destination mount and 'b' is
   the dentry in the destination mount.

   The outcome depends on the type of the mount of 'A' and 'B'. The table
   below is a quick reference::

            ---------------------------------------------------------------------------
            |                   MOVE MOUNT OPERATION                                 |
            |**************************************************************************
            | source(A)->| shared      |       private  |       slave    | unbindable |
            | dest(B)  |               |                |                |            |
            |   |      |               |                |                |            |
            |   v      |               |                |                |            |
            |**************************************************************************
            |  shared  | shared        |     shared     |shared and slave|  invalid   |
            |          |               |                |                |            |
            |non-shared| shared        |      private   |    slave       | unbindable |
            ***************************************************************************

   .. Note:: moving a mount residing under a shared mount is invalid.

   Details follow:

   1. 'A' is a shared mount and 'B' is a shared mount.  The mount 'A' is
      mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1', 'A2'...'An'
      are created and mounted at dentry 'b' on all mounts that receive
      propagation from mount 'B'. A new propagation tree is created in the
      exact same configuration as that of 'B'. This new propagation tree
      contains all the new mounts 'A1', 'A2'...  'An'.  And this new
      propagation tree is appended to the already existing propagation tree
      of 'A'.

   2. 'A' is a private mount and 'B' is a shared mount. The mount 'A' is
      mounted on mount 'B' at dentry 'b'. Also new mount 'A1', 'A2'... 'An'
      are created and mounted at dentry 'b' on all mounts that receive
      propagation from mount 'B'. The mount 'A' becomes a shared mount and a
      propagation tree is created which is identical to that of
      'B'. This new propagation tree contains all the new mounts 'A1',
      'A2'...  'An'.

   3. 'A' is a slave mount of mount 'Z' and 'B' is a shared mount.  The
      mount 'A' is mounted on mount 'B' at dentry 'b'.  Also new mounts 'A1',
      'A2'... 'An' are created and mounted at dentry 'b' on all mounts that
      receive propagation from mount 'B'. A new propagation tree is created
      in the exact same configuration as that of 'B'. This new propagation
      tree contains all the new mounts 'A1', 'A2'...  'An'.  And this new
      propagation tree is appended to the already existing propagation tree of
      'A'.  Mount 'A' continues to be the slave mount of 'Z' but it also
      becomes 'shared'.

   4. 'A' is a unbindable mount and 'B' is a shared mount. The operation
      is invalid. Because mounting anything on the shared mount 'B' can
      create new mounts that get mounted on the mounts that receive
      propagation from 'B'.  And since the mount 'A' is unbindable, cloning
      it to mount at other mountpoints is not possible.

   5. 'A' is a private mount and 'B' is a non-shared(private or slave or
      unbindable) mount. The mount 'A' is mounted on mount 'B' at dentry 'b'.

   6. 'A' is a shared mount and 'B' is a non-shared mount.  The mount 'A'
      is mounted on mount 'B' at dentry 'b'.  Mount 'A' continues to be a
      shared mount.

   7. 'A' is a slave mount of mount 'Z' and 'B' is a non-shared mount.
      The mount 'A' is mounted on mount 'B' at dentry 'b'.  Mount 'A'
      continues to be a slave mount of mount 'Z'.

   8. 'A' is a unbindable mount and 'B' is a non-shared mount. The mount
      'A' is mounted on mount 'B' at dentry 'b'. Mount 'A' continues to be a
      unbindable mount.

일반 mount와 unmount 전파

545-591

`mount device B/b`는 원본 mount가 항상 private이라는 점을 제외하면 bind 연산과 같다. 따라서 목적지 `B`가 shared이면 새 device mount가 `B`의 전파 대상들에도 복제된다.

`umount A`에서 `A`가 shared `B`의 dentry `b`에 붙어 있으면, `B` 및 그 전파 대상의 같은 `b`에 가장 최근에 쌓인 mount 가운데 하위 mount가 없는 것들을 함께 해제한다.

예제에서 peer인 `B1`, `B2`, `B3`의 `b`에 먼저 `A1..A3`, 다음으로 `C1..C3`을 올린 뒤 `C1`을 해제하면 가장 최근 층인 `C1`, `C2`, `C3`이 대상이다. `C2`나 `C3`에 자식 mount가 있으면 그것만 남고 나머지는 해제된다. 그러나 직접 요청한 `C1` 자체에 자식이 있으면 전체 umount 연산이 실패한다.

전파되는 unmount 선택
요청 대상 `C1`과 peer 목적지 찾기각 목적지 `b`의 most-recently-mounted 항목 선택요청 대상 `C1`에 하위 mount가 있으면 전체 실패전파 대상 중 하위 mount가 있는 항목은 건너뜀나머지 `C1`, `C2`, `C3`을 함께 해제

같은 dentry의 최상단 mount와 하위 mount 유무를 검사한다.

e) Mount semantics

   Consider the following command::

     mount device  B/b

   'B' is the destination mount and 'b' is the dentry in the destination
   mount.

   The above operation is the same as bind operation with the exception
   that the source mount is always a private mount.


f) Unmount semantics

   Consider the following command::

     umount A

   where 'A' is a mount mounted on mount 'B' at dentry 'b'.

   If mount 'B' is shared, then all most-recently-mounted mounts at dentry
   'b' on mounts that receive propagation from mount 'B' and does not have
   sub-mounts within them are unmounted.

   Example: Let's say 'B1', 'B2', 'B3' are shared mounts that propagate to
   each other.

   let's say 'A1', 'A2', 'A3' are first mounted at dentry 'b' on mount
   'B1', 'B2' and 'B3' respectively.

   let's say 'C1', 'C2', 'C3' are next mounted at the same dentry 'b' on
   mount 'B1', 'B2' and 'B3' respectively.

   if 'C1' is unmounted, all the mounts that are most-recently-mounted on
   'B1' and on the mounts that 'B1' propagates-to are unmounted.

   'B1' propagates to 'B2' and 'B3'. And the most recently mounted mount
   on 'B2' at dentry 'b' is 'C2', and that of mount 'B3' is 'C3'.

   So all 'C1', 'C2' and 'C3' should be unmounted.

   If any of 'C2' or 'C3' has some child mounts, then that mount is not
   unmounted, but all other mounts are unmounted. However if 'C1' is told
   to be unmounted and 'C1' has some sub-mounts, the umount operation is
   failed entirely.

Mount namespace 복제 규칙

592-610

복제된 namespace는 부모 namespace의 모든 mount를 가진다. 부모의 대응 mount를 `A`, 자식의 clone을 `B`라고 하면 전파 상태도 원칙적으로 보존된다.

Namespace clone 결과
부모 A자식 B추가 관계
sharedsharedA와 B가 서로 전파하는 peer
Z의 slaveZ의 slave같은 master Z에서 수신
privateprivate전파 관계 없음
unbindableunbindable복제 뒤에도 bind 금지

부모 A의 상태와 자식 B의 관계다.

g) Clone Namespace

   A cloned namespace contains all the mounts as that of the parent
   namespace.

   Let's say 'A' and 'B' are the corresponding mounts in the parent and the
   child namespace.

   If 'A' is shared, then 'B' is also shared and 'A' and 'B' propagate to
   each other.

   If 'A' is a slave mount of 'Z', then 'B' is also the slave mount of
   'Z'.

   If 'A' is a private mount, then 'B' is a private mount too.

   If 'A' is unbindable mount, then 'B' is a unbindable mount too.

경계 조건을 묻는 세 가지 퀴즈

611-673

퀴즈 A는 shared `/mnt`의 bind 복제 `/tmp`를 `/mnt/1`로 이동했을 때 `/mnt`, `/mnt/1`, `/mnt/1/1`의 내용이 모두 같은지, 아니면 앞의 둘만 같은지를 묻는다. shared 목적지로 move할 때 생기는 전파와 재귀적 자기 포함 가능성을 점검하는 문제다.

퀴즈 B는 루트 전체를 rshared로 만든 뒤 `/`를 `/v/1`에 rbind했을 때 `/v/1/v/1`에 무엇이 보이는지 묻는다. shared 트리를 자기 하위로 재귀 복제할 때의 결과를 생각하게 한다.

퀴즈 C는 여러 bind와 `--make-slave`, `--make-shared`를 조합해 `A → B → C` slave 연쇄를 만든다. `/bin`을 `A`의 `/tmp/test`에 bind했을 때 이벤트가 `B`, `C`까지 전파되는지와 `/mnt/1/test`의 내용을 묻는다.

퀴즈 C의 master-slave 연쇄
A: `/tmp`, root dentry `1`A → B: `/tmp1`, root dentry `2`B → C: `/mnt`, root dentry `mnt``/tmp/test`에서 A에 mount 시도B와 C로의 연쇄 전파 여부를 판정

문제에서 이름 붙인 세 mount의 수신 방향이다.

6) Quiz
-------

A. What is the result of the following command sequence?

   ::

       mount --bind /mnt /mnt
       mount --make-shared /mnt
       mount --bind /mnt /tmp
       mount --move /tmp /mnt/1

   what should be the contents of /mnt /mnt/1 /mnt/1/1 should be?
   Should they all be identical? or should /mnt and /mnt/1 be
   identical only?


B. What is the result of the following command sequence?

   ::

       mount --make-rshared /
       mkdir -p /v/1
       mount --rbind / /v/1

   what should be the content of /v/1/v/1 be?


C. What is the result of the following command sequence?

   ::

       mount --bind /mnt /mnt
       mount --make-shared /mnt
       mkdir -p /mnt/1/2/3 /mnt/1/test
       mount --bind /mnt/1 /tmp
       mount --make-slave /mnt
       mount --make-shared /mnt
       mount --bind /mnt/1/2 /tmp1
       mount --make-slave /mnt

   At this point we have the first mount at /tmp and
   its root dentry is 1. Let's call this mount 'A'
   And then we have a second mount at /tmp1 with root
   dentry 2. Let's call this mount 'B'
   Next we have a third mount at /mnt with root dentry
   mnt. Let's call this mount 'C'

   'B' is the slave of 'A' and 'C' is a slave of 'B'
   A -> B -> C

   at this point if we execute the following command::

     mount --bind /bin /tmp/test

   The mount is attempted on 'A'

   will the mount propagate to 'B' and 'C' ?

   what would be the contents of
   /mnt/1/test be?

7) FAQ

FAQ: bind mount와 exportfs

674-688

bind mount는 symbolic link와 달리 다른 쪽 mount가 해제되거나 이동해도 계속 존재한다. symbolic link는 대상 경로가 사라지거나 바뀌면 낡은 링크가 될 수 있다.

exportfs는 shared subtree 기능 일부를 흉내 내기에는 지나치게 무거운 수단이며, 특히 master에서 slave로만 흐르는 단방향 slave 의미론을 exportfs로 구현할 뚜렷한 방법이 없다.

------

1. Why is bind mount needed? How is it different from symbolic links?

   symbolic links can get stale if the destination mount gets
   unmounted or moved. Bind mounts continue to exist even if the
   other mount is unmounted or moved.

2. Why can't the shared subtree be implemented using exportfs?

   exportfs is a heavyweight way of accomplishing part of what
   shared subtree can do. I cannot imagine a way to implement the
   semantics of slave mount using exportfs?

3. Why is unbindable mount needed?

FAQ: 재귀 rbind의 폭발적 증가

689-777

unbindable mount는 같은 subtree 내부의 여러 위치에 mount tree를 반복 복제할 때 불필요한 재귀 복제를 잘라 내는 데 필요하다. 한 트리를 자기 하위에 `n`번 rbind하면 생성 mount 수가 `n`에 대해 급격히 증가한다.

초기 `/root`에는 `tmp`와 `usr`이 있고 vfsmount는 하나뿐이다. `/root`를 `/tmp/m1`에 rbind하면 복제본 안의 `tmp/m1`까지 다시 포함되어 vfsmount가 2개가 된다. 다시 `/tmp/m2`에 rbind하면 기존 복제 위치들까지 중첩 복제되어 6개가 되고, `/tmp/m3` 단계에서는 24개가 된다.

문서가 제시하는 점화식은 `V[i] = i*V[i-1]`이다. 매 단계에서 일련의 umount로 불필요한 가지를 제거할 수 있지만, unbindable로 애초에 clone 대상에서 제외하는 편이 낫다.

자기 하위 rbind 증가
단계새 위치vfsmount 수
초기root1
1차 rbind/tmp/m12
2차 rbind/tmp/m26
3차 rbind/tmp/m324
일반식i번째 단계`V[i] = i*V[i-1]`

원문의 예에서 단계마다 생성되는 vfsmount 수다.

폭증 원인
root tree를 `/tmp/m1`에 rbind새 복제본도 root의 다음 rbind 대상에 포함`/tmp/m2` 생성 때 m1 내부 구조까지 중첩 복제반복할 때 기존 모든 clone 위치가 다시 증식명시적 가지치기가 없으면 factorial 형태로 증가

복제 대상이 자기 자신이 들어 있는 subtree를 다시 포함한다.


   Let's say we want to replicate the mount tree at multiple
   locations within the same subtree.

   if one rbind mounts a tree within the same subtree 'n' times
   the number of mounts created is an exponential function of 'n'.
   Having unbindable mount can help prune the unneeded bind
   mounts. Here is an example.

   step 1:
      let's say the root tree has just two directories with
      one vfsmount::

                                    root
                                   /    \
                                  tmp    usr

      And we want to replicate the tree at multiple
      mountpoints under /root/tmp

   step 2:
      ::


                        mount --make-shared /root

                        mkdir -p /tmp/m1

                        mount --rbind /root /tmp/m1

      the new tree now looks like this::

                                    root
                                   /    \
                                 tmp    usr
                                /
                               m1
                              /  \
                             tmp  usr
                             /
                            m1

      it has two vfsmounts

   step 3:
      ::

                            mkdir -p /tmp/m2
                            mount --rbind /root /tmp/m2

      the new tree now looks like this::

                                      root
                                     /    \
                                   tmp     usr
                                  /    \
                                m1       m2
                               / \       /  \
                             tmp  usr   tmp  usr
                             / \          /
                            m1  m2      m1
                                / \     /  \
                              tmp usr  tmp   usr
                              /        / \
                             m1       m1  m2
                            /  \
                          tmp   usr
                          /  \
                         m1   m2

                    it has 6 vfsmounts

   step 4:
      ::

                          mkdir -p /tmp/m3
                          mount --rbind /root /tmp/m3

      I won't draw the tree..but it has 24 vfsmounts


   at step i the number of vfsmounts is V[i] = i*V[i-1].
   This is an exponential function. And this tree has way more
   mounts than what we really needed in the first place.

   One could use a series of umount at each step to prune
   out the unneeded mounts. But there is a better solution.
   Unclonable mounts come in handy here.

Unbindable로 재귀 복제 가지치기

778-843

개선된 구성은 먼저 `/root/tmp`를 자기 자신에 bind해 별도 mountpoint로 만든다. 이어 `/root`를 재귀 shared로 만들고 `/root/tmp`는 unbindable로 바꾼다.

이제 `/root`를 `/tmp/m1`, `/tmp/m2`, `/tmp/m3`에 차례로 rbind해도 원본의 unbindable `tmp` 아래 subtree는 복제본 안에서 더 깊게 복제되지 않는다. 결과 트리는 root 아래 `m1`, `m2`, `m3`이 나란히 있고, 각 복제본에는 `tmp`와 `usr` 한 쌍만 있는 선형적인 구조가 된다.

Unbindable 적용 후 트리
root/tmp 아래각 복제본의 자식재귀 clone
m1tmp, usrtmp가 unbindable이므로 중단
m2tmp, usrtmp가 unbindable이므로 중단
m3tmp, usrtmp가 unbindable이므로 중단

각 rbind가 새 복제본 하나만 추가하고 기존 복제본 안으로 재귀하지 않는다.

가지치기 설정 순서
`mount --bind /root/tmp /root/tmp``mount --make-rshared /root``mount --make-unbindable /root/tmp``mount --rbind /root /tmp/mN`새 위치에서 unbindable subtree를 만나면 복제 중단

복제 루트는 shared로 유지하고 재귀 진입점만 unbindable로 만든다.

   step 1:
      let's say the root tree has just two directories with
      one vfsmount::

                                    root
                                   /    \
                                  tmp    usr

         How do we set up the same tree at multiple locations under
         /root/tmp

   step 2:
      ::


                        mount --bind /root/tmp /root/tmp

                        mount --make-rshared /root
                        mount --make-unbindable /root/tmp

                        mkdir -p /tmp/m1

                        mount --rbind /root /tmp/m1

      the new tree now looks like this::

                                    root
                                   /    \
                                 tmp    usr
                                /
                               m1
                              /  \
                             tmp  usr

   step 3:
      ::

                            mkdir -p /tmp/m2
                            mount --rbind /root /tmp/m2

      the new tree now looks like this::

                                    root
                                   /    \
                                 tmp    usr
                                /   \
                               m1     m2
                              /  \     / \
                             tmp  usr tmp usr

   step 4:
      ::

                            mkdir -p /tmp/m3
                            mount --rbind /root /tmp/m3

      the new tree now looks like this::

                                          root
                                      /           \
                                     tmp           usr
                                 /    \    \
                               m1     m2     m3
                              /  \     / \    /  \
                             tmp  usr tmp usr tmp usr

`struct vfsmount` 전파 자료구조

844-888

구현은 `struct vfsmount`에 전파 관계를 나타내는 필드를 둔다. `mnt_share`는 서로 이벤트를 보내고 받는 peer들을, `mnt_slave_list`는 이 mount가 이벤트를 보내는 slave들을, `mnt_slave`는 같은 master를 둔 slave들을 연결한다. `mnt_master`는 이벤트를 받는 원천 master를 가리킨다.

`mnt_flags`에는 shared 상태를 나타내는 `MNT_SHARE`와 복제 불가를 나타내는 `MNT_UNCLONABLE`이 추가된다. 한 peer group의 shared mount는 `mnt_share`를 통해 원형 목록을 이룬다.

같은 `mnt_master`를 가진 vfsmount들은 master의 `mnt_slave_list`를 머리로 하고 `mnt_slave`를 따라가는 원형 목록을 이룬다. `mnt_master`는 master peer group의 임의 구성원을 가리킬 수 있으므로, peer group의 모든 직접 slave를 찾으려면 모든 구성원의 `mnt_slave_list`를 순회해야 한다.

개념적으로 slave들은 하나의 집합이며 개별 목록에 어떻게 분산됐는지는 전파 의미나 트리 변경에 영향을 주지 않는다. 한 peer group의 모든 vfsmount는 같은 `mnt_master`를 가지며, non-NULL이면 slave list에서 연속된 정렬 구간을 이룬다.

`struct vfsmount` 전파 필드
필드역할
`mnt_share`같은 peer group의 원형 목록
`mnt_slave_list`이 mount가 전파하는 slave 목록의 anchor
`mnt_slave`같은 master를 둔 slave들의 연결
`mnt_master`이벤트를 받는 master vfsmount 포인터
`mnt_flags``MNT_SHARE`, `MNT_UNCLONABLE` 상태

필드가 표현하는 연결과 상태다.

8) Implementation
-----------------

A) Datastructure

   Several new fields are introduced to struct vfsmount:

   ->mnt_share
           Links together all the mount to/from which this vfsmount
           send/receives propagation events.

   ->mnt_slave_list
           Links all the mounts to which this vfsmount propagates
           to.

   ->mnt_slave
           Links together all the slaves that its master vfsmount
           propagates to.

   ->mnt_master
           Points to the master vfsmount from which this vfsmount
           receives propagation.

   ->mnt_flags
           Takes two more flags to indicate the propagation status of
           the vfsmount.  MNT_SHARE indicates that the vfsmount is a shared
           vfsmount.  MNT_UNCLONABLE indicates that the vfsmount cannot be
           replicated.

   All the shared vfsmounts in a peer group form a cyclic list through
   ->mnt_share.

   All vfsmounts with the same ->mnt_master form on a cyclic list anchored
   in ->mnt_master->mnt_slave_list and going through ->mnt_slave.

   ->mnt_master can point to arbitrary (and possibly different) members
   of master peer group.  To find all immediate slaves of a peer group
   you need to go through _all_ ->mnt_slave_list of its members.
   Conceptually it's just a single set - distribution among the
   individual lists does not affect propagation or the way propagation
   tree is modified by operations.

   All vfsmounts in a peer group have the same ->mnt_master.  If it is
   non-NULL, they form a contiguous (ordered) segment of slave list.

Peer와 slave로 이루어진 전파 트리

889-934

그림의 `A`, `B`, `C`, `D`는 서로 전파하는 하나의 shared peer group이다. `A`에는 slave `E`, `F`, `G`가 있고, `C`에는 `J`, `K`, `D`에는 `H`, `I`가 있다. `E`와 `K`도 서로 shared이며, `K`에는 다시 slave `M`, `L`, `N`이 있다.

`A.mnt_share`는 `B`, `C`, `D`의 `mnt_share`와 연결된다. `A.mnt_slave_list`는 `E`, `K`, `F`, `G`의 `mnt_slave`를 연결하고 이들의 `mnt_master`는 `A`를 가리킨다. 마찬가지로 `K`의 slave list는 `M`, `L`, `N`, `C`의 목록은 `J`, `K`, `D`의 목록은 `H`, `I`를 연결한다.

겉보기에는 forest처럼 보이지만 shared mount 전체를 `pnode`라는 하나의 개념적 노드로 묶으면 트리다. 이 propagation tree는 파일 경로의 mount tree와 서로 직교하는 별도 관계다.

개념적 propagation tree
pnode 또는 mountshared peer직접 slave
P1A, B, C, DE, F, G, J, K, H, I
P2E, KM, L, N
AB, C, DE, F, G 및 목록에 연결된 K
CA, B, DJ, K
DA, B, CH, I

shared peer group을 하나의 pnode로 접어서 표현한다.

전파 방향
P1: A ↔ B ↔ C ↔ DA/C/D의 slave들로 이벤트 전달E ↔ K가 하위 shared pnode P2 형성P2에서 M, L, N으로 전달mount tree 경로와 무관한 독립 propagation tree

peer 안에서는 양방향이고 slave 계층에서는 아래 방향이다.

   A example propagation tree looks as shown in the figure below.

   .. note::
      Though it looks like a forest, if we consider all the shared
      mounts as a conceptual entity called 'pnode', it becomes a tree.

   ::


                        A <--> B <--> C <---> D
                       /|\            /|      |\
                      / F G          J K      H I
                     /
                    E<-->K
                        /|\
                       M L N

   In the above figure  A,B,C and D all are shared and propagate to each
   other.   'A' has got 3 slave mounts 'E' 'F' and 'G' 'C' has got 2 slave
   mounts 'J' and 'K'  and  'D' has got two slave mounts 'H' and 'I'.
   'E' is also shared with 'K' and they propagate to each other.  And
   'K' has 3 slaves 'M', 'L' and 'N'

   A's ->mnt_share links with the ->mnt_share of 'B' 'C' and 'D'

   A's ->mnt_slave_list links with ->mnt_slave of 'E', 'K', 'F' and 'G'

   E's ->mnt_share links with ->mnt_share of K

   'E', 'K', 'F', 'G' have their ->mnt_master point to struct vfsmount of 'A'

   'M', 'L', 'N' have their ->mnt_master point to struct vfsmount of 'K'

   K's ->mnt_slave_list links with ->mnt_slave of 'M', 'L' and 'N'

   C's ->mnt_slave_list links with ->mnt_slave of 'J' and 'K'

   J and K's ->mnt_master points to struct vfsmount of C

   and finally D's ->mnt_slave_list links with ->mnt_slave of 'H' and 'I'

   'H' and 'I' have their ->mnt_master pointing to struct vfsmount of 'D'.


   NOTE: The propagation tree is orthogonal to the mount tree.

잠금과 prepare·commit·abort 알고리즘

935-994

`mnt_share`, `mnt_slave`, `mnt_slave_list`, `mnt_master`는 `namespace_sem`으로 보호한다. 수정할 때는 exclusive, 읽을 때는 shared로 잡는다. 보통 `mnt_flags` 변경은 `vfsmount_lock`으로 직렬화한다.

예외는 `do_add_mount()`와 `clone_mnt()`다. 전자는 아직 어떤 shared 자료구조에도 공개되지 않은 vfsmount를 바꾼다. 후자는 `namespace_sem`을 잡고 있으며 해당 vfsmount의 참조는 이 semaphore 없이는 순회할 수 없는 목록에만 있다.

구현의 핵심은 rbind와 move이며 `attach_recursive_mnt()`와 `propagate_mnt()`에서 세 단계로 나뉜다. prepare 단계는 원본 트리의 각 mount마다 목적지의 모든 전파 수신 mount에 붙일 mount tree를 필요한 수만큼 생성한다. 아직 붙이지 않고 `mnt_parent`와 `mnt_mountpoint`만 기록한 뒤 목적지와 같은 propagation tree로 연결한다.

prepare가 성공하면 원본 트리의 mount 수 `n`개에 대응하는 새 propagation tree가 생기고, 목적지가 전파하는 mount 수 `m`개에 대응하는 새 mount tree가 생긴다. 메모리 할당이 실패하면 abort로 간다. commit은 각 mount tree를 해당 목적지에 붙이고, abort는 새로 만든 tree를 모두 삭제한다.

전파 관련 기능은 `pnode.c`에 있다. 문서 이력은 Ram Pai가 만든 version 0.1과 Al Viro의 의견을 반영한 version 0.2를 기록한다.

재귀 mount 연산의 3단계
Prepare: 필요한 clone tree 수 계산·할당`mnt_parent`와 `mnt_mountpoint` 기록목적지와 같은 propagation tree 구성Commit: 모든 tree를 대응 목적지에 attachAbort: 할당 실패 시 새 tree 전체 삭제

공개 전에 전부 준비하고, 성공 시 한꺼번에 붙이며, 실패 시 모두 버린다.

Prepare 완료 시 불변량
기호의미생성 결과
n원본 tree의 mount 수새 propagation tree n개
m목적지가 전파하는 mount 수새 mount tree m개
실패어느 메모리 할당 실패abort 단계로 전환

원본과 목적지 전파 규모에 대응하는 준비 결과다.

B) Locking:

   ->mnt_share, ->mnt_slave, ->mnt_slave_list, ->mnt_master are protected
   by namespace_sem (exclusive for modifications, shared for reading).

   Normally we have ->mnt_flags modifications serialized by vfsmount_lock.
   There are two exceptions: do_add_mount() and clone_mnt().
   The former modifies a vfsmount that has not been visible in any shared
   data structures yet.
   The latter holds namespace_sem and the only references to vfsmount
   are in lists that can't be traversed without namespace_sem.

C) Algorithm:

   The crux of the implementation resides in rbind/move operation.

   The overall algorithm breaks the operation into 3 phases: (look at
   attach_recursive_mnt() and propagate_mnt())

   1. Prepare phase.

      For each mount in the source tree:

      a) Create the necessary number of mount trees to
         be attached to each of the mounts that receive
         propagation from the destination mount.
      b) Do not attach any of the trees to its destination.
         However note down its ->mnt_parent and ->mnt_mountpoint
      c) Link all the new mounts to form a propagation tree that
         is identical to the propagation tree of the destination
         mount.

      If this phase is successful, there should be 'n' new
      propagation trees; where 'n' is the number of mounts in the
      source tree.  Go to the commit phase

      Also there should be 'm' new mount trees, where 'm' is
      the number of mounts to which the destination mount
      propagates to.

      If any memory allocations fail, go to the abort phase.

   2. Commit phase.

      Attach each of the mount trees to their corresponding
      destination mounts.

   3. Abort phase.

      Delete all the newly created trees.

   .. Note::
      all the propagation related functionality resides in the file pnode.c


------------------------------------------------------------------------

version 0.1  (created the initial document, Ram Pai [email protected])

version 0.2  (Incorporated comments from Al Viro)