NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/48808: Enhance mount_cd9660 by option -s like in other BSDs



>Number:         48808
>Category:       kern
>Synopsis:       Enhance mount_cd9660 by option -s like in other BSDs
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed May 14 08:35:00 +0000 2014
>Originator:     Thomas Schmitt
>Release:        6.99.40 as of early may 2014, with kern/48787
>Organization:
>Environment:
NetBSD netbsd 6.99.40 NetBSD 6.99.40 (GENERIC) #65: Tue May 13 20:39:35 UTC 
2014  thomas@netbsd:/usr/obj/sys/arch/i386/compile/GENERIC i386
>Description:
I have running on my modified 6.99.40 kernel a /sbin/mount_cd9660
which knows option -s to address an ISO 9660 superblock other than
the ones pointed to by /dev/cd0a or /dev/cd0d.

struct iso_args as of /usr/include/isofs/cd9660/mount_cd9660.h
has been enhanced with special care to maintain API and ABI
compatibility for older userland and kernels.

My addition to man 8 mount_cd9660 says: 

[ The options are as follows:]
[...]
[ -o  Options are specified with a -o flag followed by a comma]
     [...]
     ssector
             Is ignored as input option but reported by getargs if
             option -s is in effect.

 -s block_offset
     Read the superblock from a block address, which is computed by
     adding block_offset to the partition offset implied by the choice
     of the device file.  With /dev/cdXd this partition offset is 0,
     which leads to the first and oldest ISO-9660 session on the
     medium.  /dev/cdXa has the offset of the last and youngest
     recognized medium partition.  Other sessions may be reached from
     /dev/cdXd by -s with a block_offset which can be obtained from
     burn software for optical media.  The block size is 2048 bytes.

     /dev/cdX partitions are recognized from logical tracks of
     unformatted optical media.  Formatted media appear as a single
     partition. Nevertheless they may bear several ISO-9660 sessions.
     Refer to their ISO-9660 producer for offset info.

Compatibility between old/new kernel and new/old userland:

/sbin/mount_cd9660 will not offer option -s if not ISOFSMNT_SSECTOR
was defined in /usr/include/isofs/cd9660/cd9660_mount.h at compile
time.
Such a binary will react on -s like the current /sbin/mount_cd9660:

  netbsd# mount_cd9660 -s 8768 /dev/cd0d /mnt/iso
  mount_cd9660: unknown option -- s
  usage: mount_cd9660 [-o options] special node

If -s is enabled and gets used with a non-zero value, then
mount_cd9660 will check after successful mounting, whether the kernel
seems to have expected the old struct iso_args and thus must have
ignored ISOFSMNT_SSECTOR and iso_args.ssector.
It will then unmount(2) the freshly but wrongly mounted ISO.

On a kernel with old struct iso_args this yields

  netbsd# mount_cd9660 -s 8768 /dev/cd0d /mnt/iso
  mount_cd9660 : Kernel ignored option -s.
  mount_cd9660 : Had to revoke mount attempt with option -s
  netbsd# mount | grep cd0d
  netbsd#

  netbsd# mount_cd9660 /dev/cd0d /mnt/iso
  netbsd# mount | grep cd0d
  /dev/cd0d on /mnt/iso type cd9660 (read-only, local)

On a kernel with new struct iso_args, both are supposed to work

  netbsd# mount_cd9660 -s 8768 /dev/cd0d /mnt/iso
  netbsd# mount | grep cd0d
  /dev/cd0d on /mnt/iso type cd9660 (read-only, local)

The inquiry by MNT_GETARGS will report non-zero -s values

  netbsd# mount_cd9660 -o getargs /dev/cd0d /mnt/iso
  0x40<ssector>
  -s 8768
  
Old mount_9660 on a new kernel works (without -s, of course).
  
Some background about the number used:
  
Session start block numbers for the ISO filesystem are learned from
  
  netbsd$ xorriso -indev /dev/rcd0d -toc
  ...
  TOC layout   : Idx ,  sbsector ,       Size , Volume Id
  ISO session  :   1 ,        32 ,        24s , ISOIMAGE
  ISO session  :   2 ,        64 ,      8695s , ISOIMAGE
  ISO session  :   3 ,      8768 ,      7936s , ISOIMAGE
  ISO session  :   4 ,     16704 ,   2097240s , ISOIMAGE
  ISO session  :   5 ,   2113952 ,      7883s , ISOIMAGE

The numbers underneath "sbsector" are valid parameters for -s.

cd0d and cd0a both are session 5, pointed to by the default
superblock at offset 0. (The other superblocks form a chain
by starting at the next 32-blocks-aligned address after the
previous image end.)

Above -toc is from a virtual CD-ROM drive, behaving like a DVD+RW
(i.e. formatted medium) in a read-only drive. Real multi-session media,
e.g. BD-R have their first session at block 0, and there would be a
difference between cd0a and cd0d:
  ISO session  :   1 ,         0 ,   1452463s , HOME_2014_04_20_120026
  ISO session  :   2 ,   1452640 ,     37251s , HOME_2014_04_21_123352
  ...
  ISO session  :  23 ,   2508608 ,     54916s , HOME_2014_05_12_115406
  ISO session  :  24 ,   2563680 ,     54686s , HOME_2014_05_13_111159
cd0d is then session 1. cd0a is (supposed to be) session 24.

The sessions inbetween are now reachable by -s.
They then provide daily snapshots of $HOME from my real computer.
I hope to use this BD-R for another half year of backups.
Somehwere between session 200 and 300 it will go on strike 
if it is not full before. All snapshots will still be readable
then, only writing will not work any more.

Important notice for all reviewers:

The kernel patch proposal contains the termination of publishing
all cd9660 header files, except
  /usr/include/isofs/cd9660/mount_cd9660.h
which is public for usage with mount(2).

A discussion on tech-kern did not yield objections up to now. See
  http://mail-index.netbsd.org/tech-kern/2014/05/13/msg017048.html
and follow-ups.
The public exposure of the then private headers makes it nearly
impossible to augment the implementation without disturbing
potential undue includers.
I hope there are none, or that they show up and start discussing.

>How-To-Repeat:
Test ISO image is once again

    http://scdbackup.webframe.org/large.iso.bz2

4470 bytes, MD5 7d78dc3efaec8ea3f1801335329f410d.
It inflates to 4,329,897,984 bytes.

Do this only if the fix of kern/48787 is applied.
If not, you will not get rid of the /mnt/iso mount point until reboot !

It bears two sessions. Number 2 is mounted by default:
  TOC layout   : Idx ,  sbsector ,       Size , Volume Id
  ISO session  :   1 ,        32 ,   2113977s , ISOIMAGE
  ISO session  :   2 ,   2114016 ,        25s , ISOIMAGE

If the ISO is submitted as /dev/cd0, do:

  mount_cd9660 -s 32 /dev/cd0d /mnt/iso
  ls -l /mnt/iso

which should show only one file in the ISO root (containing a
large file which triggers an interesting bug):

  drwxr-xr-x  1 thomas  dbus  2048 May  6 15:30 my

Now for session 2 which is default:

  umount /mnt/iso
  mount_cd9660 /dev/cd0d /mnt/iso
  ls -l /mnt/iso

should show two files in the ISO root:

  drwxr-xr-x  1 thomas  dbus  2048 May  6 15:30 my
  -rw-r--r--  1 thomas  dbus     6 May  6 15:34 small_file

(Actually user id 1000, group id 1000)

>Fix:
I will propose three patches.
One for sys/fs/cd9660, one for sbin/mount_cd9660, and one for
/usr/src/distrib/sets/lists/comp/mi, where the now private header
files are currently listed as "comp-c-include".

The kernel patch proposal still contains open questions, marked by "XXX":

- There is a very peculiar "partition" semantic with /dev/cd*.
  The position of the superblock is taken from a partition offset.
  cd9660_vfsops.c:
        sess = label.d_partitions[DISKPART(dev)].p_cdsession;
  Nevertheless the block addressing is done relative to the base device
  /dev/cdXd. This is indeed appropriate for ISO 9660 multi-session, but
  hardly for partitions.

  I still have to explore the effect of above code line with partitioned
  hard disk media. Does .p_cdsession show non-zero values there ?
  Do the bread() operations work relative to the partition start ?

- I allocate a struct iso_args as local variable on the stack.
  Size is 120 bytes on i386. Is there a rigid stack dscipline which
  would demand malloc() and free() for larger objects ?

- The old kernels silently ignore my new flags bit ISOFSMNT_SSECTOR.
  This makes necessary in sbin/mount_cd9660 a cumbersome check after
  mount(2) and eventually revocation of the misdirected mount by
  unmount(2).
  I would like to avoid this with future changes.
  Therefore i want to throw EINVAL on unknown flags bits.
  Martin Husemann stated to me, that struct iso_arg is supposed
  to be submitted properly zeroized in all unused bits and bytes.

- I see flags bit ISOFSMNT_NOCASETRANS missing in the statement which
  memorizes the options for inquiry by mount(2) MNT_GETARGS.
  Can this be intentional ? Why ?

None of these is essential for the desired mount feature.
But they need to be decided for getting a neat patch.



Home | Main Index | Thread Index | Old Index