เหตุใดการเมานท์จึงไม่เคารพตัวเลือกแบบอ่านอย่างเดียวสำหรับการเชื่อมการเชื่อมโยง?


35

บนระบบ Arch Linux ของฉัน (Linux Kernel 3.14.2) การเชื่อมต่อผูกไม่เคารพตัวเลือกอ่านอย่างเดียว

# mkdir test
# mount --bind -o ro test/ /mnt
# touch /mnt/foo

/mnt/fooสร้างไฟล์ รายการที่เกี่ยวข้องใน/proc/mountsคือ

/dev/sda2 /mnt ext4 rw,noatime,data=ordered 0 0

ตัวเลือกการติดตั้งไม่ตรงกับตัวเลือกที่ร้องขอของฉัน แต่ทำตรงทั้งพฤติกรรมการอ่าน / เขียนของผูกติดและตัวเลือกที่ใช้ในการติดเดิม/dev/sda2บน/

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

อย่างไรก็ตามถ้าฉันเมานต์ใหม่ก็จะเคารพตัวเลือกการอ่านอย่างเดียว

# mount --bind -o remount,ro test/ /mnt
# touch /mnt/bar
touch: cannot touch ‘/mnt/bar’: Read-only file system

และรายการที่เกี่ยวข้องใน /proc/mounts/

/dev/sda2 /mnt ext4 ro,relatime,data=ordered 0 0

ดูเหมือนว่าสิ่งที่ฉันคาดหวัง (แม้ว่าในความจริงแล้วฉันคาดว่าจะเห็นเส้นทางแบบเต็มของtestไดเรกทอรี) รายการใน/proc/mounts/สำหรับการเมานต์ orignal ของ/dev/sda2/on /ยังไม่เปลี่ยนแปลงและยังคงอ่าน / เขียน

/dev/sda2 / ext4 rw,noatime,data=ordered 0 0

พฤติกรรมนี้และการทำงานรอบด้านได้รับการรู้จักกันตั้งแต่อย่างน้อยปี 2008และได้รับการบันทึกไว้ใน man page ของmount

โปรดทราบว่าตัวเลือกการเมานต์ระบบไฟล์จะยังคงเหมือนเดิมในจุดเมานท์ดั้งเดิมและไม่สามารถเปลี่ยนแปลงได้โดยผ่านตัวเลือก -o พร้อมกับ --bind / - rbind ตัวเลือกการเมาท์สามารถเปลี่ยนแปลงได้โดยคำสั่ง remount แยกต่างหาก

การแจกแจงทั้งหมดไม่ทำงานเหมือนกัน Arch ดูเหมือนจะล้มเหลวในการเคารพตัวเลือกต่าง ๆ ในขณะที่ Debian สร้างคำเตือนเมื่อ bind mount ไม่ได้รับ mount แบบอ่านอย่างเดียว

mount: warning: /mnt seems to be mounted read-write.

มีรายงานว่าพฤติกรรมนี้ "คงที่" ใน Debian Lenny และ Squeezeแม้ว่ามันจะดูเหมือนจะไม่ได้รับการแก้ไขที่เป็นสากลหรือมันยังคงทำงานใน Debian Wheezy อะไรคือความยากลำบากในการเชื่อมโยงเข้ากับการผูกตัวเลือกอ่านอย่างเดียวบนเมานต์เริ่มต้น?


คุณมี / etc / mtab หรือไม่
eyoung100

ดูเพิ่มเติมที่thread.gmane.org/gmane.linux.utilities.util-linux-ng/2979และวิธีแก้ปัญหาโดยใช้mount -t bindและสคริปต์ผู้ช่วยเหลือที่bugs.launchpad.net/ubuntu/+source/mountall/+bug/519380
Stéphane Chazelas

@ECarterYoung /etc/mtabใช่ฉันมี หลังจากการเมานต์เริ่มต้นรายการจะบอกว่าการเมานต์เป็น rw และหลังจากการเมานต์ใหม่จะบอกว่า ro ดังนั้นมันจึงรายงานสถานะของการเมานต์อย่างถูกต้อง มันเป็นเพียงคำสั่ง mount ที่ล้มเหลว
StrongBad

3
ฉันทดสอบบนเครื่องทดสอบ Debian สองเครื่อง / เครื่องที่ไม่เสถียรหนึ่งเครื่องที่ทำงานกับเคอร์เนล Debian และอีกหนึ่งเครื่องที่ใช้เคอร์เนล kernel.org ไม่สามารถทำงานได้mount --bind -o roพวกเขาทั้งสองคายข้อความmount: warning: «mountpoint» seems to be mounted read-write.ดังนั้นดูเหมือนว่า Debian จะหลุดหรือแพทช์หายไปในบางจุด ... Remount ทำงานได้แม้ว่า
derobert

2
@StrongBad ทดสอบแล้วตามที่ร้องขอและมันก็ไม่ทำงานเหมือนกัน
derobert

คำตอบ:


21

ผูกติดเป็นเพียง ... ดี ... ผูกติด นั่นคือมันไม่ใช่การติดตั้งใหม่ มันเป็นแค่ "ลิงค์" / "exposes" / "พิจารณา" ไดเรกทอรีย่อยเป็นจุดเชื่อมต่อใหม่ ดังนั้นจึงไม่สามารถแก้ไขพารามิเตอร์การเมานต์ได้ นั่นเป็นเหตุผลที่คุณได้รับการร้องเรียน:

# mount /mnt/1/lala /mnt/2 -o bind,ro
mount: warning: /mnt/2 seems to be mounted read-write.

แต่ในขณะที่คุณพูดปกติผูกติดทำงาน:

# mount /mnt/1/lala /mnt/2 -o bind

และจากนั้นนับใหม่ ro ยังใช้งานได้:

# mount /mnt/1/lala /mnt/2 -o bind,remount,ro 

อย่างไรก็ตามสิ่งที่เกิดขึ้นคือคุณกำลังเปลี่ยนเมานต์ทั้งหมดไม่ใช่แค่เมานต์นี้เท่านั้น หากคุณดูที่ / proc / mounts คุณจะเห็นว่าทั้งการผูกและการเมาท์เดิมเปลี่ยนเป็นแบบอ่านอย่างเดียว:

/dev/loop0 /mnt/1 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0
/dev/loop0 /mnt/2 ext2 ro,relatime,errors=continue,user_xattr,acl 0 0

ดังนั้นสิ่งที่คุณทำคือการเปลี่ยนเมานต์เริ่มต้นเป็นเมานต์อ่านอย่างเดียวจากนั้นทำเมานต์แบบติดตั้งซึ่งแน่นอนว่าจะเป็นแบบอ่านอย่างเดียว

อัพเดท 2016-07-20:

ข้อมูลต่อไปนี้เป็นจริงสำหรับ 4.5 kernels แต่ไม่เป็นจริงสำหรับ 4.3 kernels (สิ่งนี้ผิดดูการอัปเดต # 2 ด้านล่าง):

เคอร์เนลมีสองแฟล็กที่ควบคุมการอ่านอย่างเดียว:

  • กระบวนการMS_READONLY: ระบุว่าการเมาท์เป็นแบบอ่านอย่างเดียวหรือไม่
  • กระบวนการMNT_READONLY: ระบุว่า "ผู้ใช้" ต้องการแบบอ่านอย่างเดียวหรือไม่

บนเคอร์เนล 4.5 การทำ a mount -o bind,roจะเป็นการหลอกลวง ตัวอย่างเช่นสิ่งนี้:

# mkdir /tmp/test
# mkdir /tmp/test/a /tmp/test/b
# mount -t tmpfs none /tmp/test/a
# mkdir /tmp/test/a/d
# mount -o bind,ro /tmp/test/a/d /tmp/test/b

จะสร้างแบบอ่านอย่างเดียวผูกติดของ/tmp/test/a/dไป/tmp/test/bซึ่งจะปรากฏใน/proc/mountsนาม:

none /tmp/test/a tmpfs rw,relatime 0 0
none /tmp/test/b tmpfs ro,relatime 0 0

มุมมองที่ละเอียดมากขึ้นสามารถมองเห็นได้/proc/self/mountinfoซึ่งจะพิจารณามุมมองผู้ใช้ (เนมสเปซ) บรรทัดที่เกี่ยวข้องจะเป็นสิ่งเหล่านี้:

363 74 0:49 / /tmp/test/a rw,relatime shared:273 - tmpfs none rw
368 74 0:49 /d /tmp/test/b ro,relatime shared:273 - tmpfs none rw

ตรงไหนในบรรทัดที่สองคุณจะเห็นว่ามันบอกว่าทั้งro( MNT_READONLY) และrw( !MS_READONLY)

ผลลัพธ์ที่ได้คือ:

# echo a > /tmp/test/a/d/f
# echo a > /tmp/test/b/f
-su: /tmp/test/b/f: Read-only file system

อัพเดท 2016-07-20 # 2:

การขุดเพิ่มเติมลงในนี้แสดงให้เห็นว่าพฤติกรรมในความเป็นจริงขึ้นอยู่กับรุ่นของ libmount ซึ่งเป็นส่วนหนึ่งของ util-linux การสนับสนุนสำหรับการนี้ถูกเพิ่มเข้ามาด้วยนี้กระทำและได้รับการปล่อยตัวในรุ่น 2.27:

กระทำ 9ac77b8a78452eab0612523d27fee52159f5016a
ผู้แต่ง: Karel Zak 
วันที่: จันทร์ 17 ส.ค. 11:54:26 2015 +0200

    libmount: เพิ่มการรองรับ "bind, ro"

    ตอนนี้จำเป็นต้องใช้การเมาท์สองตัว (8) สายเพื่อสร้างแบบอ่านอย่างเดียว
    ติดตั้ง:

      mount / foo / bar -o bind
      mount / bar -o remount, ro, bind

    แพตช์นี้อนุญาตให้ระบุ "ผูก, ro" และทำการเมานต์ใหม่
    โดยอัตโนมัติโดย libmount โดยเมาท์เพิ่มเติม (2) syscall มันไม่ใช่
    อะตอมแน่นอน

    ลงชื่อออกโดย: Karel Zak 

ซึ่งยังให้วิธีแก้ปัญหา พฤติกรรมที่สามารถมองเห็นได้โดยใช้ strace บนภูเขาที่เก่ากว่าและใหม่กว่า:

เก่า:

mount("/tmp/test/a/d", "/tmp/test/b", 0x222e240, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.000681>

ใหม่:

mount("/tmp/test/a/d", "/tmp/test/b", 0x1a8ee90, MS_MGC_VAL|MS_RDONLY|MS_BIND, NULL) = 0 <0.011492>
mount("none", "/tmp/test/b", NULL, MS_RDONLY|MS_REMOUNT|MS_BIND, NULL) = 0 <0.006281>

สรุป:

เพื่อให้ได้ผลลัพธ์ที่ต้องการเราต้องรันสองคำสั่ง (ดังที่ @Thomas กล่าวไว้แล้ว):

mount SRC DST -o bind
mount DST -o remount,ro,bind

เวอร์ชันที่ใหม่กว่าของการเมาท์ (util-linux> = 2.27) ทำสิ่งนี้โดยอัตโนมัติเมื่อมีการรัน

mount SRC DST -o bind,ro

3
ใช่ แต่ไม่ใช่ IIRC มีการสนับสนุนในเคอร์เนลสำหรับจุดเชื่อมต่อที่แตกต่างกัน(ไม่ใช่ระบบไฟล์) เพื่อให้มีตัวเลือกที่แตกต่างกัน Debian เคยมีโปรแกรมปะแก้ที่mount -o bind,roสร้างมุมมองแบบอ่านอย่างเดียวของระบบไฟล์แบบอ่าน - เขียน (แต่ดูเหมือนว่าจะไม่มีอยู่ในนั้นอีกแล้ว)
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

ฉันไม่เห็นว่าสิ่งนี้ขัดแย้งกับข้างต้นอย่างไร Hacks สามารถอนุญาตทุกสิ่งรวมถึงสิ่งที่ไม่สมเหตุสมผล ในปัจจุบันมีการจัดการ remount แบบอ่านอย่างเดียวบนเคอร์เนล 3.14 ในที่สุดโดยการเรียกนี้: mnt_make_readonly (real_mount (mnt)) ซึ่งในขณะที่คุณสามารถเห็นการใช้ real_mount () ดังนั้นในทางปฏิบัติจะส่งผลกระทบต่อการติดตั้งจริง ธงเมาท์ (อ่านอย่างเดียว) อย่างน้อยนั่นก็เป็นความเข้าใจของฉัน
V13

ดังนั้นนี่จะเป็นผลของแพทช์ "ติดตั้งโครงสร้างการกระจาย" (โดยเฉพาะการคอมมิทนี้ ), ปรากฏครั้งแรกในเคอร์เนล 3.3 คุณรู้หรือไม่ว่าผลที่ตามมาของแพทช์นี้ถูกกล่าวถึงใน lkml หรือ lwn?
Gilles 'หยุดความชั่วร้าย' Gilles

7
mount --bind /tmp/ /mnt/tmp/; mount -o remount,bind,ro /mnt/tmp/... แล้วtouch /tmp/aก็โอเค แต่ให้touch /mnt/tmp/b touch: cannot touch ‘/mnt/tmp/b’: Read-only file systemใช้ได้กับทั้ง Debian 3.13 และ kernel.org 3.14.2 ดังนั้นมันไม่เพียงแค่เปลี่ยนภูเขาทั้งหมด อย่างน้อยก็ไม่ใช่เมล็ดข้าวที่ผ่านมา
derobert

1
คำแถลงสันนิษฐานว่าเป็น "การผูกติดเป็นเพียง ... ดี ... การผูกติด" มีความสำคัญจริงๆ แต่ไม่มีความหมายสำหรับฉัน ฉันยังไม่เข้าใจว่าทำไมจึงใช้งานเป็นครั้งที่สองด้วยตัวเลือกการนับใหม่
StrongBad

9

ทางออกที่เหมาะสมคือการติดมันสองครั้ง บนบรรทัดคำสั่ง:

mount -t none -o bind /source/dir /destination/dir
mount -t none -o bind,remount,ro /source/dir /destination/dir

ใน/etc/fstab:

/source/dir            /destination/dir    none  bind            0 0
/source/dir            /destination/dir    none  remount,bind,ro 0 0

คู่มือ ( man mount) ระบุว่าเป็นอย่างนั้น:

   The bind mounts.
          Since Linux 2.4.0 it is possible to remount part of the file hierarchy somewhere else. The call is
                 mount --bind olddir newdir
   [...]
          Note that the filesystem mount options will remain the same as those on the original mount point, and cannot be changed  by  passing  the  -o  option
          along with --bind/--rbind. The mount options can be changed by a separate remount command, for example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro newdir
          .
          Note  that  behavior  of  the remount operation depends on the /etc/mtab file. The first command stores the 'bind' flag to the /etc/mtab file and the
          second command reads the flag from the file.  If you have a system without the /etc/mtab file or if you explicitly define source and target  for  the
          remount command (then mount(8) does not read /etc/mtab), then you have to use bind flag (or option) for the remount command too. For example:
          .
                 mount --bind olddir newdir
                 mount -o remount,ro,bind olddir newdir

ดูเหมือนว่ามันจะทำงานได้กับ Ubuntu 14.04 LTS และเคอร์เนล 3.19.0-51-lowlatency ดี!
Mikko Rantalainen

0

คุณกำลังถามจากมุมมองของmount(8)บรรทัดคำสั่ง (ซึ่งเป็นที่ยอมรับในเว็บไซต์นี้) คำสั่งนั้นได้รับการกล่าวถึงในคำตอบอื่น ๆ และในบางกรณีสรุปออกไปmount(2)เรียกระบบที่สองที่จำเป็น

แต่ทำไมต้องใช้การเรียกระบบครั้งที่สอง? ทำไมการmount(2)โทรครั้งเดียวไม่สามารถสร้างการเชื่อมโยงแบบอ่านอย่างเดียวได้?

mount(2)หน้าคนอธิบายว่ามีเป็นคนอื่นได้ชี้สองชุดของธงเป็นชุด:

  • แฟล็กระบบไฟล์พื้นฐาน
  • แฟล็กเมานต์ VFS

มันบอกว่า:

ตั้งแต่ Linux 2.6.16 คุณMS_RDONLYสามารถตั้งค่าหรือล้างข้อมูลแบบต่อจุดเช่นเดียวกับในระบบไฟล์พื้นฐาน ระบบไฟล์ที่เมาท์จะเขียนได้ก็ต่อเมื่อระบบไฟล์และจุดเมานต์นั้นไม่ได้รับการตั้งค่าสถานะเป็นอ่านอย่างเดียว

และเกี่ยวกับMS_REMOUNT:

ตั้งแต่ Linux 2.6.26 แฟล็กนี้สามารถใช้MS_BINDเพื่อแก้ไขเฉพาะแฟล็กต่อจุด สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับการตั้งค่าหรือล้างค่าสถานะ "อ่านอย่างเดียว" บนจุดเชื่อมต่อโดยไม่ต้องเปลี่ยนระบบไฟล์พื้นฐาน การระบุ mountflags เป็น:

      MS_REMOUNT | MS_BIND | MS_RDONLY

จะทำให้สามารถเข้าถึงผ่านจุดเมานท์แบบอ่านอย่างเดียวโดยไม่กระทบกับจุดเชื่อมต่ออื่น ๆ

ฉันคิดว่าปัญหาเกิดขึ้นเมื่อมีการแนะนำการผูกติดครั้งแรก:

หาก mountflags รวมถึงMS_BIND(มีให้ตั้งแต่ Linux 2.4) ให้ดำเนินการเมาต์ bind ... ส่วนที่เหลืออีกบิตในอาร์กิวเมนต์ mountflags MS_RECจะถูกละเว้นยังมีข้อยกเว้นของ (การผูกเมาท์มีตัวเลือกการเมานท์เดียวกันกับจุดเมานท์พื้นฐาน)

ดูเหมือนว่าแทนที่จะใช้MS_BIND | MS_REMOUNTเป็นสัญญาณในการตั้งค่าเฉพาะแฟล็ก VFS พวกเขาสามารถเลือกยกเว้น (และยอมรับ) MS_RDONLYพร้อมกับค่าเริ่มต้นMS_BINDและนำไปใช้กับจุดเมานท์

ดังนั้นเนื่องจากความหมายที่ค่อนข้างแปลกของการmount(2)เรียกระบบ:

  • การเรียกครั้งแรกจะสร้างการเชื่อมต่อเชื่อมและแฟล็กอื่น ๆ ทั้งหมดจะถูกข้าม
  • การเรียกครั้งที่สอง (พร้อม remount) ตั้งค่าสถานะจุดเมานท์เป็นแบบอ่านอย่างเดียว
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.