2360 lines
68 KiB
Diff
2360 lines
68 KiB
Diff
Index: linux/Documentation/filesystems/supermount.txt
|
|
diff -u linux/Documentation/filesystems/supermount.txt:1.1 linux/Documentation/filesystems/supermount.txt:1.1.6.1
|
|
--- linux/Documentation/filesystems/supermount.txt:1.1 Mon Feb 26 17:55:03 1996
|
|
+++ linux/Documentation/filesystems/supermount.txt Sat Nov 9 20:35:00 1996
|
|
@@ -0,0 +1,179 @@
|
|
+Supermount README
|
|
+=================
|
|
+
|
|
+For supermount v0.4c, on linux kernels 2.0.23 or later.
|
|
+
|
|
+Supermount is a pseudo-filesystem which manages filesystems on
|
|
+removable media like floppy disks and CD-ROMs. It aims to make
|
|
+management of removable media as easy as it is under DOS.
|
|
+
|
|
+With supermount, you can change the disk in the drive whenever you
|
|
+want (with the obvious exception that you shouldn't do it when the
|
|
+filesystem is actively in use). You don't need to "cd" out of the
|
|
+directory first, and you don't need to tell the kernel what you're
|
|
+doing --- supermount will detect the media change automatically.
|
|
+
|
|
+Supermount will automatically detect whether the media you are
|
|
+mounting is read-write or readonly, and if you mount a write-protected
|
|
+disk, then the subfs will be mounted as a readonly filesystem.
|
|
+
|
|
+Supermount detects when you have finished activity on the subfs, and
|
|
+will flush all buffers to the disk before completing the operation.
|
|
+So, if you copy a file onto a supermounted floppy disk, the data will
|
|
+all be written to disk before the "cp" command finishes. When the
|
|
+command does complete, it will be safe to remove the disk.
|
|
+
|
|
+It is worth while defining what I mean by "activity" here. The subfs
|
|
+is active if there are any processes running which have a handle on a
|
|
+non-directory inode on the subfs, or which have a file open on the
|
|
+subfs (even if only for reading). There is one important case which
|
|
+does NOT count as activity: if you "cd" to a directory or a
|
|
+subdirectory under the supermount mount point, then that reference
|
|
+does not make the subfs active, and you can safely remove the disk.
|
|
+
|
|
+Yes, that's right. You can "cd /floppy; ls" and get a listing of a
|
|
+dos floppy. Remove the disk, insert a new one, and "ls" will now list
|
|
+the new contents. Remove the disk altogether, and "ls" will give you
|
|
+an I/O error. Put in a new disk, and "ls" starts working again. It
|
|
+is NOT an error to remove a supermounted disk which is acting as the
|
|
+current working directory for one or more processes!
|
|
+
|
|
+
|
|
+The Superfilesystem and Subfilesystem concepts
|
|
+----------------------------------------------
|
|
+
|
|
+Normally, when you mount a filesystem, you create a direct connection
|
|
+between a mount point in the directory tree and a filesystem on a
|
|
+block device. Supermount adds an extra layer in between; with
|
|
+supermount, you explicitly mount the pseudo-filesystem (the
|
|
+"superfilesystem") on the mount point, and supermount then
|
|
+automatically mounts the real filesystem (the "subfilesystem") on the
|
|
+block device when needed.
|
|
+
|
|
+Running supermount
|
|
+------------------
|
|
+
|
|
+To run supermount, compile and install a kernel with the supermount
|
|
+patches and select "Y" to the question
|
|
+
|
|
+ Dynamic mounting of removable media?
|
|
+
|
|
+when you run "make config". You set up a supermount filesystem with
|
|
+the normal mount command, using the syntax:
|
|
+
|
|
+ mount -o <superfs-options>,--,<subfs-options> <dev> <mount-point>
|
|
+
|
|
+<dev> can be anything you want. Using supermount, the block device
|
|
+you are using is not physically mounted until there is a filesystem
|
|
+access to the mount point, so the device specified on the command line
|
|
+is ignored. It is convenient just to specify the mount point as the
|
|
+device as well, so that you give the mount point twice on the command
|
|
+line. Doing this reduces the chance that the mount program will
|
|
+confuse the mount point with some other mount point defined in
|
|
+/etc/fstab.
|
|
+
|
|
+The way you specify the location of the block device you want to mount
|
|
+is by providing the <superfs-options> field, where the following
|
|
+options are currently recognised:
|
|
+
|
|
+* subfs=<filesystem-type> [default is "msdos"]
|
|
+
|
|
+ Specify the subfilesystem type. "msdos" and "iso9660" have
|
|
+been tested, but any block-device filesystem should work with one
|
|
+important restriction: the filesystem must NOT try to write to the
|
|
+device when you unmount it. This is because supermount doesn't know
|
|
+in advance when it will have to unmount the subfs, so it doesn't try
|
|
+to do so until it detects that the media has been changed. By this
|
|
+time it is too late to write to the device!
|
|
+
|
|
+ If you mount supermount as a readonly filesystem ("mount -r"
|
|
+or "mount -o ro"), then you won't have this problem. Otherwise, you
|
|
+will not be able to use the ext2fs or minix filesystems with
|
|
+supermount. This will hopefully be addressed in a future release of
|
|
+supermount.
|
|
+
|
|
+* dev=<block-device> [default is "/dev/fd0"]
|
|
+
|
|
+ Specify the block device on which the subfs is to be mounted.
|
|
+
|
|
+* debug
|
|
+
|
|
+ Enable debugging code in the supermount filesystem, if
|
|
+the debug option was enabled at compile time. By default, debugging
|
|
+code is compiled into the kernel but is disabled until a debug mount
|
|
+option is seen.
|
|
+
|
|
+* '--'
|
|
+
|
|
+ All options after the option string '--' will be passed
|
|
+directly to the subfilesystem when it gets mounted.
|
|
+
|
|
+
|
|
+Here is an example of supermount options, taken directly out of my
|
|
+current /etc/fstab:
|
|
+
|
|
+/floppy /floppy supermount --,gid=51,conv=binary 0 0
|
|
+/cd /cd supermount ro,fs=iso9660,dev=/dev/hdd,--,conv=binary 0 0
|
|
+
|
|
+This tells supermount to manage a msdos filesystem on /dev/fd0 mounted
|
|
+at /floppy (msdos and /dev/fd0 are defaults for supermount), with the
|
|
+msdos filesystem getting the options "gid=51,conv=binary". My cdrom
|
|
+on /dev/hdd is similarly mounted on /cd.
|
|
+
|
|
+
|
|
+Caveats and Provisos
|
|
+--------------------
|
|
+
|
|
+There are still some limitations to the current version of
|
|
+supermount. I hope to overcome these shortly in future releases, but
|
|
+for now, be aware that:
|
|
+
|
|
+* You can only specify one filesystem type on the mount command line.
|
|
+ Supermount cannot yet autodetect the type of filesystem you supply.
|
|
+
|
|
+* With the 2.0 kernel, CDROM door locking has been made much more
|
|
+ aggressive. You will probably find that once supermount has mounted
|
|
+ your disk, you cannot unmount it again. Not helpful!
|
|
+
|
|
+* The only filesystem which is supported read/write with supermount is
|
|
+ msdos. The msdos filesystem has the special characteristic that it
|
|
+ never has to access the disk when you unmount it, so supermount can
|
|
+ safely defer the unmounting until after the disk is removed. That
|
|
+ doesn't work so well for filesystems such as ext2fs which try to
|
|
+ write to the filesystem when it is unmounted.
|
|
+
|
|
+Problems 2) and 3) are being solved by a development patch to support
|
|
+unmount-on-timeout, which will do a full unmount of the media after
|
|
+half a second or so of inactivity, releasing the volume for removal.
|
|
+Problem 1) has been addressed by a contributed patch which I hope to
|
|
+integrate shortly. As usual, watch this space, and anybody who I've
|
|
+got on my list of supermount users will be emailed with further
|
|
+developments!
|
|
+
|
|
+
|
|
+Enjoy supermount. I hope you find it useful --- I certainly find it
|
|
+extremely convenient. Send any comments, bug-fixes or bug-reports,
|
|
+suggestions and success stories to sct@dcs.ed.ac.uk. Flames to
|
|
+/dev/null, please!
|
|
+
|
|
+Cheers,
|
|
+ Stephen.
|
|
+--
|
|
+
|
|
+================================================================
|
|
+Changes for v0.4c:
|
|
+Works against linux-2.0.23.
|
|
+Updated documentation.
|
|
+Fixed problem with default root inode mode.
|
|
+
|
|
+Changes for v0.4:
|
|
+Performance tuning only. Read-only operations like "find" should now
|
|
+be MUCH faster.
|
|
+
|
|
+Changes for v0.3:
|
|
+Fixed supermount_create bug; now returns a properly attached
|
|
+superinode.
|
|
+
|
|
+Changes for v0.2:
|
|
+Improved device invalidation code, so CD-ROMs work now.
|
|
+
|
|
Index: linux/fs/Config.in
|
|
diff -u linux/fs/Config.in:1.5 linux/fs/Config.in:1.5.2.1
|
|
--- linux/fs/Config.in:1.5 Wed Nov 6 23:16:50 1996
|
|
+++ linux/fs/Config.in Sat Nov 9 17:26:20 1996
|
|
@@ -6,6 +6,7 @@
|
|
|
|
bool 'Quota support' CONFIG_QUOTA
|
|
bool 'Mandatory lock support' CONFIG_LOCK_MANDATORY
|
|
+bool 'Supermount removable media support' CONFIG_SUPERMOUNT
|
|
tristate 'Minix fs support' CONFIG_MINIX_FS
|
|
tristate 'Extended fs support' CONFIG_EXT_FS
|
|
tristate 'Second extended fs support' CONFIG_EXT2_FS
|
|
Index: linux/fs/Makefile
|
|
diff -u linux/fs/Makefile:1.4 linux/fs/Makefile:1.4.4.1
|
|
--- linux/fs/Makefile:1.4 Wed May 15 14:12:18 1996
|
|
+++ linux/fs/Makefile Sat Nov 9 17:26:21 1996
|
|
@@ -17,7 +17,7 @@
|
|
|
|
MOD_LIST_NAME := FS_MODULES
|
|
ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \
|
|
- hpfs sysv smbfs ncpfs ufs affs
|
|
+ hpfs sysv smbfs ncpfs ufs affs supermount
|
|
|
|
ifeq ($(CONFIG_QUOTA),y)
|
|
O_OBJS += dquot.o
|
|
@@ -139,6 +139,14 @@
|
|
ifeq ($(CONFIG_HPFS_FS),m)
|
|
MOD_SUB_DIRS += hpfs
|
|
endif
|
|
+endif
|
|
+
|
|
+ifeq ($(CONFIG_SUPERMOUNT),y)
|
|
+SUB_DIRS += supermount
|
|
+#else
|
|
+# ifeq ($(CONFIG_SUPERMOUNT),m)
|
|
+# MOD_SUB_DIRS += supermount
|
|
+# endif
|
|
endif
|
|
|
|
ifeq ($(CONFIG_UFS_FS),y)
|
|
Index: linux/fs/devices.c
|
|
diff -u linux/fs/devices.c:1.3 linux/fs/devices.c:1.3.4.1
|
|
--- linux/fs/devices.c:1.3 Wed May 15 14:12:20 1996
|
|
+++ linux/fs/devices.c Sat Nov 9 17:26:22 1996
|
|
@@ -187,15 +187,14 @@
|
|
}
|
|
|
|
/*
|
|
- * This routine checks whether a removable media has been changed,
|
|
- * and invalidates all buffer-cache-entries in that case. This
|
|
- * is a relatively slow routine, so we have to try to minimize using
|
|
- * it. Thus it is called only upon a 'mount' or 'open'. This
|
|
- * is the best way of combining speed and utility, I think.
|
|
- * People changing diskettes in the middle of an operation deserve
|
|
- * to loose :-)
|
|
- */
|
|
-int check_disk_change(kdev_t dev)
|
|
+ * These routines checks whether a removable media has been changed,
|
|
+ * and (for check_disk_change only) invalidate all
|
|
+ * buffer-cache-entries in that case. This is a relatively slow
|
|
+ * routine, so we have to try to minimize using it. Thus it is called
|
|
+ * only upon a 'mount' or 'open'. This is the best way of combining
|
|
+ * speed and utility, I think. People changing diskettes in the
|
|
+ * middle of an operation deserve to loose :-) */
|
|
+int query_disk_change(kdev_t dev)
|
|
{
|
|
int i;
|
|
struct file_operations * fops;
|
|
@@ -208,17 +207,37 @@
|
|
if (!fops->check_media_change(dev))
|
|
return 0;
|
|
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+int check_disk_change(kdev_t dev)
|
|
+{
|
|
+ if (!query_disk_change(dev))
|
|
+ return 0;
|
|
printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
|
|
kdevname(dev));
|
|
+ invalidate_media(dev);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+void invalidate_media(kdev_t dev)
|
|
+{
|
|
+ int i;
|
|
+ struct file_operations * fops;
|
|
+
|
|
+ i = MAJOR(dev);
|
|
+ if (i >= MAX_BLKDEV)
|
|
+ return;
|
|
+ fops = blkdevs[i].fops;
|
|
for (i=0 ; i<NR_SUPER ; i++)
|
|
if (super_blocks[i].s_dev == dev)
|
|
put_super(super_blocks[i].s_dev);
|
|
invalidate_inodes(dev);
|
|
invalidate_buffers(dev);
|
|
|
|
- if (fops->revalidate)
|
|
+ if (fops && fops->revalidate)
|
|
fops->revalidate(dev);
|
|
- return 1;
|
|
+ return;
|
|
}
|
|
|
|
/*
|
|
Index: linux/fs/filesystems.c
|
|
diff -u linux/fs/filesystems.c:1.3 linux/fs/filesystems.c:1.3.4.1
|
|
--- linux/fs/filesystems.c:1.3 Sat Apr 27 17:06:29 1996
|
|
+++ linux/fs/filesystems.c Sat Nov 9 17:26:22 1996
|
|
@@ -9,6 +9,7 @@
|
|
#include <linux/config.h>
|
|
#include <linux/fs.h>
|
|
|
|
+#include <linux/supermount_fs.h>
|
|
#include <linux/minix_fs.h>
|
|
#include <linux/ext_fs.h>
|
|
#include <linux/ext2_fs.h>
|
|
@@ -39,6 +40,11 @@
|
|
callable = 0;
|
|
|
|
device_setup();
|
|
+
|
|
+#ifdef CONFIG_SUPERMOUNT
|
|
+ register_filesystem(&(struct file_system_type)
|
|
+ {supermount_read_super, "supermount", 0, NULL});
|
|
+#endif
|
|
|
|
binfmt_setup();
|
|
|
|
Index: linux/fs/inode.c
|
|
diff -u linux/fs/inode.c:1.5 linux/fs/inode.c:1.5.2.1
|
|
--- linux/fs/inode.c:1.5 Wed Nov 6 23:16:52 1996
|
|
+++ linux/fs/inode.c Sat Nov 9 17:26:22 1996
|
|
@@ -219,6 +219,8 @@
|
|
if (inode == mount_root && inode->i_count ==
|
|
(inode->i_mount != inode ? 1 : 2))
|
|
continue;
|
|
+ if (IS_UNBOUND(inode))
|
|
+ continue;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
@@ -254,6 +256,9 @@
|
|
inode->i_lock = 1;
|
|
inode->i_sb->s_op->write_inode(inode);
|
|
unlock_inode(inode);
|
|
+ if (inode->i_shadow && inode->i_shadow->i_shadow_op &&
|
|
+ inode->i_shadow->i_shadow_op->write)
|
|
+ inode->i_shadow->i_shadow_op->write(inode->i_shadow);
|
|
}
|
|
|
|
static inline void read_inode(struct inode * inode)
|
|
@@ -414,15 +419,24 @@
|
|
}
|
|
}
|
|
|
|
+static inline void release_shadow(struct inode * inode) {
|
|
+ /* Shadow-release should be atomic. */
|
|
+ struct inode * tmp;
|
|
+ tmp = inode->i_shadow;
|
|
+ inode->i_shadow = 0;
|
|
+}
|
|
+
|
|
void iput(struct inode * inode)
|
|
{
|
|
+ struct inode * shadow;
|
|
+
|
|
if (!inode)
|
|
return;
|
|
wait_on_inode(inode);
|
|
if (!inode->i_count) {
|
|
printk("VFS: iput: trying to free free inode\n");
|
|
printk("VFS: device %s, inode %lu, mode=0%07o\n",
|
|
- kdevname(inode->i_rdev), inode->i_ino, inode->i_mode);
|
|
+ kdevname(inode->i_dev), inode->i_ino, inode->i_mode);
|
|
return;
|
|
}
|
|
if (inode->i_pipe)
|
|
@@ -441,9 +455,22 @@
|
|
}
|
|
|
|
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
|
|
+ shadow = inode->i_shadow;
|
|
inode->i_sb->s_op->put_inode(inode);
|
|
- if (!inode->i_nlink)
|
|
+ if (!inode->i_nlink) {
|
|
+ /* The inode should have been cleared, so we
|
|
+ don't reset inode->i_shadow here. */
|
|
+ if (shadow) {
|
|
+ if (shadow->i_shadow_op &&
|
|
+ shadow->i_shadow_op->release)
|
|
+ shadow->i_shadow_op->release(shadow);
|
|
+ iput (shadow);
|
|
+ }
|
|
+ /* put_inode should do a clear_inode() if the
|
|
+ inode is unlinked, so don't bother falling
|
|
+ through... */
|
|
return;
|
|
+ }
|
|
}
|
|
|
|
if (inode->i_dirt) {
|
|
@@ -473,6 +500,14 @@
|
|
}
|
|
|
|
nr_free_inodes++;
|
|
+ shadow = inode->i_shadow;
|
|
+ inode->i_shadow = 0;
|
|
+ if (shadow) {
|
|
+ if (shadow->i_shadow_op &&
|
|
+ shadow->i_shadow_op->release)
|
|
+ shadow->i_shadow_op->release(shadow);
|
|
+ iput (shadow);
|
|
+ }
|
|
return;
|
|
}
|
|
|
|
Index: linux/fs/open.c
|
|
diff -u linux/fs/open.c:1.4 linux/fs/open.c:1.4.2.1
|
|
--- linux/fs/open.c:1.4 Wed Nov 6 23:16:53 1996
|
|
+++ linux/fs/open.c Sat Nov 9 17:26:22 1996
|
|
@@ -523,6 +523,10 @@
|
|
goto cleanup_inode;
|
|
}
|
|
|
|
+ if (inode->i_shadow && inode->i_shadow->i_shadow_op &&
|
|
+ inode->i_shadow->i_shadow_op->open)
|
|
+ inode->i_shadow->i_shadow_op->open(inode->i_shadow, flag);
|
|
+
|
|
f->f_inode = inode;
|
|
f->f_pos = 0;
|
|
f->f_reada = 0;
|
|
Index: linux/fs/super.c
|
|
diff -u linux/fs/super.c:1.9 linux/fs/super.c:1.9.2.1
|
|
--- linux/fs/super.c:1.9 Wed Nov 6 23:16:54 1996
|
|
+++ linux/fs/super.c Sat Nov 9 17:26:23 1996
|
|
@@ -628,21 +628,12 @@
|
|
* functions, they should be faked here. -- jrs
|
|
*/
|
|
|
|
-asmlinkage int sys_umount(char * name)
|
|
+int do_umounti(struct inode * inode)
|
|
{
|
|
- struct inode * inode;
|
|
kdev_t dev;
|
|
int retval;
|
|
struct inode dummy_inode;
|
|
|
|
- if (!suser())
|
|
- return -EPERM;
|
|
- retval = namei(name, &inode);
|
|
- if (retval) {
|
|
- retval = lnamei(name, &inode);
|
|
- if (retval)
|
|
- return retval;
|
|
- }
|
|
if (S_ISBLK(inode->i_mode)) {
|
|
dev = inode->i_rdev;
|
|
if (IS_NODEV(inode)) {
|
|
@@ -681,50 +672,55 @@
|
|
return 0;
|
|
}
|
|
|
|
-/*
|
|
- * do_mount() does the actual mounting after sys_mount has done the ugly
|
|
- * parameter parsing. When enough time has gone by, and everything uses the
|
|
- * new mount() parameters, sys_mount() can then be cleaned up.
|
|
+asmlinkage int sys_umount(char * name)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int retval;
|
|
+
|
|
+ if (!suser())
|
|
+ return -EPERM;
|
|
+ retval = namei(name,&inode);
|
|
+ if (retval) {
|
|
+ retval = lnamei(name,&inode);
|
|
+ if (retval)
|
|
+ return retval;
|
|
+ }
|
|
+ return do_umounti(inode);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * do_mountdev() does the actual mounting after sys_mount has done the
|
|
+ * ugly parameter parsing. When enough time has gone by, and
|
|
+ * everything uses the new mount() parameters, sys_mount() can then be
|
|
+ * cleaned up.
|
|
*
|
|
* We cannot mount a filesystem if it has active, used, or dirty inodes.
|
|
* We also have to flush all inode-data for this device, as the new mount
|
|
- * might need new info.
|
|
+ * might need new info.
|
|
*/
|
|
|
|
-int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
|
|
+int do_mountdev(kdev_t dev,
|
|
+ struct inode *dir_i,
|
|
+ const char * dev_name,
|
|
+ const char * dir_name,
|
|
+ const char * type,
|
|
+ int flags,
|
|
+ void * data)
|
|
{
|
|
- struct inode * dir_i;
|
|
struct super_block * sb;
|
|
struct vfsmount *vfsmnt;
|
|
- int error;
|
|
|
|
- if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
|
|
- return -EACCES;
|
|
- /*flags |= MS_RDONLY;*/
|
|
- error = namei(dir_name, &dir_i);
|
|
- if (error)
|
|
- return error;
|
|
- if (dir_i->i_count != 1 || dir_i->i_mount) {
|
|
- iput(dir_i);
|
|
+ if (dir_i->i_count != 1 || dir_i->i_mount)
|
|
return -EBUSY;
|
|
- }
|
|
- if (!S_ISDIR(dir_i->i_mode)) {
|
|
- iput(dir_i);
|
|
+ if (!S_ISDIR(dir_i->i_mode))
|
|
return -ENOTDIR;
|
|
- }
|
|
- if (!fs_may_mount(dev)) {
|
|
- iput(dir_i);
|
|
+ if (!fs_may_mount(dev))
|
|
return -EBUSY;
|
|
- }
|
|
sb = read_super(dev,type,flags,data,0);
|
|
- if (!sb) {
|
|
- iput(dir_i);
|
|
+ if (!sb)
|
|
return -EINVAL;
|
|
- }
|
|
- if (sb->s_covered) {
|
|
- iput(dir_i);
|
|
+ if (sb->s_covered)
|
|
return -EBUSY;
|
|
- }
|
|
vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
|
|
if (vfsmnt) {
|
|
vfsmnt->mnt_sb = sb;
|
|
@@ -736,6 +732,26 @@
|
|
}
|
|
|
|
|
|
+int do_mount(kdev_t dev,
|
|
+ const char * dev_name,
|
|
+ const char * dir_name,
|
|
+ const char * type,
|
|
+ int flags,
|
|
+ void * data)
|
|
+{
|
|
+ int error;
|
|
+ struct inode * dir_i;
|
|
+
|
|
+ error = namei(dir_name, &dir_i);
|
|
+ if (error)
|
|
+ return error;
|
|
+ error = do_mountdev(dev, dir_i, dev_name, dir_name, type, flags, data);
|
|
+ if (error)
|
|
+ iput(dir_i);
|
|
+ return error;
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
* Alters the mount flags of a mounted file system. Only the mount point
|
|
* is used as a reference - file system type and the device are ignored.
|
|
@@ -794,14 +810,23 @@
|
|
if (!data)
|
|
return 0;
|
|
|
|
- vma = find_vma(current->mm, (unsigned long) data);
|
|
- if (!vma || (unsigned long) data < vma->vm_start)
|
|
- return -EFAULT;
|
|
- if (!(vma->vm_flags & VM_READ))
|
|
- return -EFAULT;
|
|
- i = vma->vm_end - (unsigned long) data;
|
|
- if (PAGE_SIZE <= (unsigned long) i)
|
|
+ /*
|
|
+ * Supermount calls the mount code from kernel space, so don't
|
|
+ * validate the mount data if it is already in kernel address
|
|
+ * space.
|
|
+ */
|
|
+ if (get_fs() != get_ds()) {
|
|
+ vma = find_vma(current->mm, (unsigned long) data);
|
|
+ if (!vma || (unsigned long) data < vma->vm_start)
|
|
+ return -EFAULT;
|
|
+ if (!(vma->vm_flags & VM_READ))
|
|
+ return -EFAULT;
|
|
+ i = vma->vm_end - (unsigned long) data;
|
|
+ if (PAGE_SIZE <= (unsigned long) i)
|
|
+ i = PAGE_SIZE-1;
|
|
+ } else {
|
|
i = PAGE_SIZE-1;
|
|
+ }
|
|
if (!(page = __get_free_page(GFP_KERNEL))) {
|
|
return -ENOMEM;
|
|
}
|
|
@@ -825,15 +850,10 @@
|
|
* version that didn't understand them.
|
|
*/
|
|
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
|
|
- unsigned long new_flags, void * data)
|
|
+ unsigned long new_flags, void * data)
|
|
{
|
|
- struct file_system_type * fstype;
|
|
- struct inode * inode;
|
|
- struct file_operations * fops;
|
|
- kdev_t dev;
|
|
+ struct inode * dir_inode;
|
|
int retval;
|
|
- const char * t;
|
|
- unsigned long flags = 0;
|
|
unsigned long page = 0;
|
|
|
|
if (!suser())
|
|
@@ -849,6 +869,29 @@
|
|
free_page(page);
|
|
return retval;
|
|
}
|
|
+ retval = namei(dir_name, &dir_inode);
|
|
+ if (retval)
|
|
+ return retval;
|
|
+ retval = do_mounti(dir_inode,dir_name,dev_name,type,new_flags,data);
|
|
+ if (retval)
|
|
+ iput(dir_inode);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/* Mount on a given inode. Don't iput() the mount point! */
|
|
+int do_mounti(struct inode * dir_inode, const char * dir_name,
|
|
+ const char * dev_name, const char * type,
|
|
+ unsigned long new_flags, const void * data)
|
|
+{
|
|
+ struct file_system_type * fstype;
|
|
+ struct inode * inode;
|
|
+ struct file_operations * fops;
|
|
+ dev_t dev;
|
|
+ int retval;
|
|
+ const char * t;
|
|
+ unsigned long flags = 0;
|
|
+ unsigned long page = 0;
|
|
+
|
|
retval = copy_mount_options (type, &page);
|
|
if (retval < 0)
|
|
return retval;
|
|
@@ -906,7 +949,8 @@
|
|
return retval;
|
|
}
|
|
}
|
|
- retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
|
|
+ retval = do_mountdev(dev,dir_inode,dev_name,dir_name,
|
|
+ t,flags,(void *) page);
|
|
free_page(page);
|
|
if (retval && fops && fops->release)
|
|
fops->release(inode, NULL);
|
|
Index: linux/fs/supermount/Makefile
|
|
diff -u linux/fs/supermount/Makefile:1.1 linux/fs/supermount/Makefile:1.1.6.1
|
|
--- linux/fs/supermount/Makefile:1.1 Mon Feb 26 17:55:15 1996
|
|
+++ linux/fs/supermount/Makefile Sat Nov 9 17:27:24 1996
|
|
@@ -0,0 +1,14 @@
|
|
+#
|
|
+# Makefile for the linux supermounting routines.
|
|
+#
|
|
+# Note! Dependencies are done automagically by 'make dep', which also
|
|
+# removes any old dependencies. DON'T put your own dependencies here
|
|
+# unless it's something special (ie not a .c file).
|
|
+#
|
|
+# Note 2! The CFLAGS definitions are now in the main makefile...
|
|
+
|
|
+O_TARGET := supermount.o
|
|
+O_OBJS := dir.o inode.o namei.o super.o
|
|
+M_OBJS := $(O_TARGET)
|
|
+
|
|
+include $(TOPDIR)/Rules.make
|
|
Index: linux/fs/supermount/TODO
|
|
diff -u linux/fs/supermount/TODO:1.1 linux/fs/supermount/TODO:1.1.6.1
|
|
--- linux/fs/supermount/TODO:1.1 Mon Feb 26 17:55:15 1996
|
|
+++ linux/fs/supermount/TODO Sat Nov 9 17:27:24 1996
|
|
@@ -0,0 +1,40 @@
|
|
+Notes:
|
|
+
|
|
+TODO:
|
|
+
|
|
+ Supermount directory inodes do auto-remount as root of the subfs. Make
|
|
+ a mount option to restrict this behaviour to the root?
|
|
+
|
|
+ Make supermount_attach a special case of read_hidden_inode, not the other
|
|
+ way around.
|
|
+
|
|
+ Replace shadow inodes with shadow superblock? Do release that way?
|
|
+
|
|
+ Unmount on suspend? OK iff inode numbers on open directories will
|
|
+ be the same next time around! (Normally true.) Bad for performance, but
|
|
+ maybe necessary for ext2fs, for example.
|
|
+
|
|
+Done:::
|
|
+
|
|
+ Sigh. We can't rely on the one-to-one mapping of superinode to
|
|
+ subinode i_ino numbers any more. Why not? Well, what happens if we
|
|
+ remove and remount a medium? We can end up with one process holding
|
|
+ a handle to an old, obsolete superinode, and a new process opening a
|
|
+ subinode with the same i_ino. Well, we can do a quadratic hash on
|
|
+ the superinode numbers to avoid collisions. Think about this!
|
|
+
|
|
+ * What happens when we do get an inode collision? We rehash to make
|
|
+ another superinode the current one; the old inode remains as a
|
|
+ placeholder. But then, what if the old inode becomes released? A
|
|
+ subsequent attach may place the subinode under that old inode
|
|
+ instead of the new superinode.
|
|
+
|
|
+ OK: There is only ever one hidden/shadow connection between super
|
|
+ and sub inodes. If that is broken, we can reestablish it from any
|
|
+ superinode we want to. Previously valid superinodes will have to
|
|
+ rely on i_subino to get to their subinode (the subinode i_ino will
|
|
+ NOT change behind our backs, hopefully). Such mappings should
|
|
+ only ever be one way, from superinode to subinode, done by
|
|
+ subiget().
|
|
+
|
|
+ Special handling of root directory to do auto remount.
|
|
Index: linux/fs/supermount/dir.c
|
|
diff -u linux/fs/supermount/dir.c:1.1 linux/fs/supermount/dir.c:1.1.6.1
|
|
--- linux/fs/supermount/dir.c:1.1 Mon Feb 26 17:55:15 1996
|
|
+++ linux/fs/supermount/dir.c Sat Nov 9 17:27:24 1996
|
|
@@ -0,0 +1,97 @@
|
|
+/*
|
|
+ * linux/fs/supermount/dir.c
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ * from
|
|
+ *
|
|
+ * linux/fs/minix/dir.c
|
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
|
+ *
|
|
+ * and
|
|
+ *
|
|
+ * linux/fs/ext2/dir.c
|
|
+ * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
|
|
+ */
|
|
+
|
|
+#include <asm/segment.h>
|
|
+
|
|
+#include <linux/errno.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/supermount_fs.h>
|
|
+#include <linux/stat.h>
|
|
+
|
|
+static int supermount_dir_open (struct inode *, struct file *);
|
|
+
|
|
+static struct file_operations supermount_dir_operations = {
|
|
+ NULL, /* lseek - default */
|
|
+ NULL, /* read */
|
|
+ NULL, /* write - bad */
|
|
+ NULL, /* readdir */
|
|
+ NULL, /* select - default */
|
|
+ NULL, /* ioctl */
|
|
+ NULL, /* mmap */
|
|
+ supermount_dir_open, /* Redirect to the subfs readdir() code */
|
|
+ NULL, /* no special release code */
|
|
+ NULL, /* fsync */
|
|
+ NULL, /* fasync */
|
|
+ NULL, /* check_media_change */
|
|
+ NULL /* revalidate */
|
|
+};
|
|
+
|
|
+/*
|
|
+ * directories can handle most operations... supermount/namei.c just
|
|
+ * passes them through to the underlying subfs, except for lookup().
|
|
+ */
|
|
+struct inode_operations supermount_dir_iops = {
|
|
+ &supermount_dir_operations, /* default directory file-ops */
|
|
+ supermount_create, /* create */
|
|
+ supermount_lookup, /* lookup */
|
|
+ supermount_link, /* link */
|
|
+ supermount_unlink, /* unlink */
|
|
+ supermount_symlink, /* symlink */
|
|
+ supermount_mkdir, /* mkdir */
|
|
+ supermount_rmdir, /* rmdir */
|
|
+ supermount_mknod, /* mknod */
|
|
+ supermount_rename, /* rename */
|
|
+ NULL, /* readlink */
|
|
+ NULL, /* follow_link */
|
|
+ NULL, /* bmap */
|
|
+ NULL, /* truncate */
|
|
+ supermount_permission, /* permission */
|
|
+ NULL /* smap */
|
|
+};
|
|
+
|
|
+
|
|
+/* When we open() a directory (for readdir), just rewrite the file
|
|
+ struct to point to the subfs inode, and let it handle all the
|
|
+ work. */
|
|
+static int supermount_dir_open (struct inode * inode, struct file * file)
|
|
+{
|
|
+ struct inode * subi;
|
|
+ int rc;
|
|
+
|
|
+ if (file->f_mode & 2)
|
|
+ return -EPERM;
|
|
+
|
|
+ supermount_debug ("dir_open inode %ld\n", inode->i_ino);
|
|
+
|
|
+ subi = subiget(inode);
|
|
+ if (!subi)
|
|
+ return -ENOENT;
|
|
+
|
|
+ file->f_inode = subi;
|
|
+ file->f_op = subi->i_op ? subi->i_op->default_file_ops : NULL;
|
|
+ if (file->f_op && file->f_op->open) {
|
|
+ rc = file->f_op->open(subi, file);
|
|
+ if (rc) {
|
|
+ iput(subi);
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+ iput(inode);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
Index: linux/fs/supermount/file.c
|
|
diff -u linux/fs/supermount/file.c:1.1 linux/fs/supermount/file.c:1.1.6.1
|
|
--- linux/fs/supermount/file.c:1.1 Mon Feb 26 17:55:15 1996
|
|
+++ linux/fs/supermount/file.c Sat Nov 9 17:27:25 1996
|
|
@@ -0,0 +1,21 @@
|
|
+/*
|
|
+ * linux/fs/supermount/file.c
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <asm/segment.h>
|
|
+#include <asm/system.h>
|
|
+
|
|
+#include <linux/errno.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/supermount_fs.h>
|
|
+#include <linux/fcntl.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/locks.h>
|
|
+
|
|
+static void supermount_inode_release (struct inode *);
|
|
+
|
|
Index: linux/fs/supermount/inode.c
|
|
diff -u linux/fs/supermount/inode.c:1.1 linux/fs/supermount/inode.c:1.1.6.1
|
|
--- linux/fs/supermount/inode.c:1.1 Mon Feb 26 17:55:16 1996
|
|
+++ linux/fs/supermount/inode.c Sat Nov 9 17:27:25 1996
|
|
@@ -0,0 +1,380 @@
|
|
+/*
|
|
+ * linux/fs/supermount/inode.c
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ * from
|
|
+ *
|
|
+ * linux/fs/minix/inode.c
|
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
|
+ *
|
|
+ * and
|
|
+ *
|
|
+ * linux/fs/ext2/inode.c
|
|
+ * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
|
|
+ * and 1993 Stephen Tweedie
|
|
+ */
|
|
+
|
|
+#include <asm/segment.h>
|
|
+#include <asm/system.h>
|
|
+
|
|
+#include <linux/errno.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/supermount_fs.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/locks.h>
|
|
+#include <linux/mm.h>
|
|
+
|
|
+static void read_hidden_inode (struct inode *);
|
|
+static void supermount_inode_open (struct inode *, int);
|
|
+static void supermount_inode_write (struct inode *);
|
|
+static void supermount_inode_release (struct inode *);
|
|
+
|
|
+/* Deal with the shadow interface. Whenever a subfs inode is
|
|
+ released, break the bi-directional link between them, and close and
|
|
+ iput the supermount inode. */
|
|
+
|
|
+struct inode_shadow_operations supermount_shadow_iops = {
|
|
+ supermount_inode_open,
|
|
+ supermount_inode_write,
|
|
+ supermount_inode_release,
|
|
+};
|
|
+
|
|
+void supermount_inode_open (struct inode *inode, int flag)
|
|
+{
|
|
+ if (flag & 2)
|
|
+ mark_subfs_dirty(inode->i_sb);
|
|
+}
|
|
+
|
|
+void supermount_inode_write (struct inode *inode)
|
|
+{
|
|
+ mark_subfs_dirty(inode->i_sb);
|
|
+}
|
|
+
|
|
+void supermount_inode_release (struct inode *inode)
|
|
+{
|
|
+ supermount_debug ("inode = %ld\n", inode->i_ino);
|
|
+ if (inode->u.supermount_i.i_hidden)
|
|
+ supermount_debug("subinode = %ld\n",
|
|
+ inode->u.supermount_i.i_hidden->i_ino);
|
|
+
|
|
+ inode->u.supermount_i.i_hidden = NULL;
|
|
+ supermount_iclose(inode);
|
|
+}
|
|
+
|
|
+
|
|
+/* Do an iget on the appropriate subfs inode */
|
|
+struct inode * subiget(struct inode * inode)
|
|
+{
|
|
+ struct inode * tmp;
|
|
+ supermount_debug("subiget inode %ld\n", inode->i_ino);
|
|
+
|
|
+ if (!S_ISDIR(inode->i_mode))
|
|
+ return 0;
|
|
+ if (supermount_media_check(inode->i_sb)) {
|
|
+ supermount_debug("media is invalid\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (inode_is_obsolete(inode)) {
|
|
+ /* For obsolete directory with new mounted media ---
|
|
+ return the new root subinode. */
|
|
+ if (inode->u.supermount_i.i_hidden)
|
|
+ supermount_panic (inode->i_sb, "subiget",
|
|
+ "Hidden inode on obsolete inode %ld",
|
|
+ inode->i_ino);
|
|
+ tmp = inode->i_sb->u.supermount_sb.s_subfs->s_mounted;
|
|
+ inode->u.supermount_i.i_subino = tmp->i_ino;
|
|
+ tmp->i_count++;
|
|
+ supermount_debug("mapping obsolete inode %ld to "
|
|
+ "subroot inode %ld\n",
|
|
+ inode->i_ino, tmp->i_ino);
|
|
+ return tmp;
|
|
+ }
|
|
+
|
|
+ if (inode->u.supermount_i.i_hidden) {
|
|
+ inode->u.supermount_i.i_hidden->i_count++;
|
|
+ supermount_debug("inode %ld/%ld, found hidden, "
|
|
+ "count now %d/%d\n",
|
|
+ inode->i_ino,
|
|
+ inode->u.supermount_i.i_hidden->i_ino,
|
|
+ inode->i_count,
|
|
+ inode->u.supermount_i.i_hidden->i_count);
|
|
+ return inode->u.supermount_i.i_hidden;
|
|
+ }
|
|
+ read_hidden_inode(inode);
|
|
+ if (!inode->u.supermount_i.i_hidden) {
|
|
+ supermount_debug("inode %ld, no subinode, count=%d\n",
|
|
+ inode->i_ino, inode->i_count);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ supermount_debug("inode %ld/%ld, found new, "
|
|
+ "count now %d/%d\n",
|
|
+ inode->i_ino,
|
|
+ inode->u.supermount_i.i_hidden->i_ino,
|
|
+ inode->i_count,
|
|
+ inode->u.supermount_i.i_hidden->i_count);
|
|
+ return inode->u.supermount_i.i_hidden;
|
|
+}
|
|
+
|
|
+/* We sometimes do a lookup on a subinode and want to get back a
|
|
+ superinode in return, with a single iget() outstanding on both (not
|
|
+ counting the i_shadow reference). supermount_attach generates the
|
|
+ superinode for a given subinode. */
|
|
+struct inode * supermount_attach(struct super_block *sb, struct inode *inode)
|
|
+{
|
|
+ struct inode *tmp;
|
|
+ unsigned long new_ino, incr=1237;
|
|
+
|
|
+ supermount_debug ("inode = %ld\n", inode->i_ino);
|
|
+
|
|
+ if (inode->i_shadow) {
|
|
+ supermount_debug ("return existing shadow %ld, count %d/%d\n",
|
|
+ inode->i_shadow->i_ino,
|
|
+ inode->i_shadow->i_count, inode->i_count);
|
|
+ inode->i_shadow->i_count++;
|
|
+ return inode->i_shadow;
|
|
+ }
|
|
+
|
|
+ /* The rules are a little different at the root. */
|
|
+ if (inode == sb->u.supermount_sb.s_subfs->s_mounted) {
|
|
+ tmp = sb->s_mounted;
|
|
+ supermount_debug ("return existing superfs root %ld, "
|
|
+ "count %d/%d\n",
|
|
+ tmp->i_ino, tmp->i_count, inode->i_count);
|
|
+ tmp->i_count++;
|
|
+ return tmp;
|
|
+ }
|
|
+
|
|
+ /* Find a new superinode, avoiding collisions with old
|
|
+ obsolete superinodes by a quadratic hash. */
|
|
+ new_ino = inode->i_ino;
|
|
+ for ( ; (tmp = iget(sb, new_ino)) && tmp->i_count > 1 &&
|
|
+ inode_is_obsolete(tmp); ) {
|
|
+ iput(tmp);
|
|
+ new_ino += incr;
|
|
+ new_ino &= 0xffffff;
|
|
+ incr <<= 1; incr++;
|
|
+ }
|
|
+
|
|
+ tmp->u.supermount_i.i_subino = inode->i_ino;
|
|
+ /* If we found a previously obsolete inode which is now no
|
|
+ longer used, we can safely remove the obsolesence flag. */
|
|
+ if (inode_is_obsolete(tmp)) {
|
|
+ tmp->u.supermount_i.i_sb_version =
|
|
+ tmp->i_sb->u.supermount_sb.s_version;
|
|
+ }
|
|
+
|
|
+ /* We have now done iget() on superi and subi. Doing the
|
|
+ attachment may incur another iget() on the subinode. */
|
|
+ if (!tmp->u.supermount_i.i_hidden) {
|
|
+ read_hidden_inode(tmp);
|
|
+ iput(inode);
|
|
+ }
|
|
+ return tmp;
|
|
+}
|
|
+
|
|
+/* Supermount open/close inode. These functions maintain the
|
|
+ superblock reference counts of active inodes; the subfs is
|
|
+ suspended when that count reaches zero.
|
|
+
|
|
+ Files are opened on any significant reference, and are not closed
|
|
+ until they become fully dereferenced (during the last iput).
|
|
+ Directories, on the other hand, are always closed unless they are
|
|
+ active and opened; a directory referenced as CWD is not open.
|
|
+
|
|
+ The difference is in the way the application gets given inodes.
|
|
+ For dirs and symlinks, it will be given the superinode to deal
|
|
+ with; for other file types, we return the subinode. */
|
|
+
|
|
+
|
|
+void supermount_iopen(struct inode * inode)
|
|
+{
|
|
+ supermount_debug ("inode %ld, count %d\n",
|
|
+ inode->i_ino, inode->i_count);
|
|
+ if (inode->i_sb->u.supermount_sb.s_state == SUPERMOUNT_UNMOUNTED)
|
|
+ supermount_panic (inode->i_sb, "supermount_iopen",
|
|
+ "opening inode on unmounted subfs");
|
|
+ if (!inode->u.supermount_i.i_counted) {
|
|
+ supermount_debug("Opened inode %ld\n", inode->i_ino);
|
|
+ inode->u.supermount_i.i_counted = 1;
|
|
+ if (!subfs_is_active(inode->i_sb)) {
|
|
+ supermount_debug ("going online.\n");
|
|
+ inode->i_sb->u.supermount_sb.s_state =
|
|
+ SUPERMOUNT_ONLINE;
|
|
+ }
|
|
+ inode->i_sb->u.supermount_sb.s_opencount++;
|
|
+ }
|
|
+}
|
|
+
|
|
+void supermount_iclose(struct inode * inode)
|
|
+{
|
|
+ supermount_debug ("inode %ld, count %d\n",
|
|
+ inode->i_ino, inode->i_count);
|
|
+ if (inode->u.supermount_i.i_counted) {
|
|
+ supermount_debug("Closed inode %ld\n", inode->i_ino);
|
|
+ inode->u.supermount_i.i_counted = 0;
|
|
+ inode->i_sb->u.supermount_sb.s_opencount--;
|
|
+ if (!subfs_is_active(inode->i_sb))
|
|
+ supermount_go_inactive(inode->i_sb);
|
|
+ }
|
|
+}
|
|
+
|
|
+void supermount_go_inactive(struct super_block *sb)
|
|
+{
|
|
+ supermount_debug("Checking state\n");
|
|
+ if (!subfs_is_active(sb)) {
|
|
+ supermount_debug("going offline.\n");
|
|
+ sb->u.supermount_sb.s_state =
|
|
+ SUPERMOUNT_SUSPENDED;
|
|
+ if (subfs_is_dirty(sb)) {
|
|
+ mark_subfs_clean(sb);
|
|
+ fsync_dev(sb->u.supermount_sb.s_subfs->s_dev);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void read_hidden_inode (struct inode * inode)
|
|
+{
|
|
+ struct super_block * sb;
|
|
+ struct inode * tmp;
|
|
+
|
|
+ supermount_debug("inode = %ld\n", inode->i_ino);
|
|
+ supermount_media_check(inode->i_sb);
|
|
+
|
|
+ if (inode->i_sb->u.supermount_sb.s_state ==
|
|
+ SUPERMOUNT_UNMOUNTED) {
|
|
+ supermount_panic (inode->i_sb, "read_hidden_inode",
|
|
+ "Trying to read inode on unmounted media");
|
|
+ }
|
|
+ sb=inode->i_sb->u.supermount_sb.s_subfs;
|
|
+ /* The root inode is a bit special. For that one, the
|
|
+ subinode is the root of the subfs, and we can't guarantee
|
|
+ its inode number in advance. */
|
|
+ if (inode->i_ino == SUPERMOUNT_ROOT_INO) {
|
|
+ tmp = sb->s_mounted;
|
|
+ tmp->i_count++;
|
|
+ } else {
|
|
+ if (!inode->u.supermount_i.i_subino)
|
|
+ inode->u.supermount_i.i_subino = inode->i_ino;
|
|
+ tmp = iget(sb, inode->u.supermount_i.i_subino);
|
|
+ }
|
|
+ if (!tmp)
|
|
+ return;
|
|
+
|
|
+ /* If the inode is already linked to its superinode, don't do
|
|
+ any further processing. Also, don't bother trying to
|
|
+ attach to the superinode if we are reading from an obsolete
|
|
+ superinode. */
|
|
+ if (tmp->i_shadow || inode_is_obsolete(inode))
|
|
+ return;
|
|
+ tmp->i_shadow = inode;
|
|
+ inode->u.supermount_i.i_hidden = tmp;
|
|
+ inode->i_count++;
|
|
+ supermount_iopen(inode);
|
|
+
|
|
+ inode->i_mode = tmp->i_mode;
|
|
+ inode->i_uid = tmp->i_uid;
|
|
+ inode->i_gid = tmp->i_gid;
|
|
+ inode->i_nlink = tmp->i_nlink;
|
|
+ inode->i_size = tmp->i_size;
|
|
+ inode->i_atime = tmp->i_atime;
|
|
+ inode->i_ctime = tmp->i_ctime;
|
|
+ inode->i_mtime = tmp->i_mtime;
|
|
+ inode->i_blksize = tmp->i_blksize;
|
|
+ inode->i_blocks = tmp->i_blocks;
|
|
+ inode->i_rdev = tmp->i_rdev;
|
|
+ inode->i_version = ++event;
|
|
+
|
|
+ if (S_ISDIR(inode->i_mode))
|
|
+ inode->i_op = &supermount_dir_iops;
|
|
+ else
|
|
+ inode->i_op = NULL;
|
|
+}
|
|
+
|
|
+void supermount_read_inode (struct inode * inode)
|
|
+{
|
|
+ supermount_debug ("inode = %ld\n", inode->i_ino);
|
|
+
|
|
+ inode->i_shadow_op = &supermount_shadow_iops;
|
|
+ inode->u.supermount_i.i_sb_version =
|
|
+ inode->i_sb->u.supermount_sb.s_version;
|
|
+
|
|
+ switch (inode->i_ino) {
|
|
+ case SUPERMOUNT_ROOT_INO:
|
|
+ if (inode->i_sb->u.supermount_sb.s_state !=
|
|
+ SUPERMOUNT_UNMOUNTED) {
|
|
+ supermount_panic (inode->i_sb, "supermount_read_inode",
|
|
+ "Help - trying to read root while "
|
|
+ "already mounted!");
|
|
+ }
|
|
+ /* Fall through */
|
|
+ case SUPERMOUNT_HIDDEN_INO:
|
|
+ inode->i_mode = inode->i_sb->u.supermount_sb.s_default_mode;
|
|
+ inode->i_uid = 0;
|
|
+ inode->i_gid = 0;
|
|
+ inode->i_nlink = 1;
|
|
+ inode->i_size = 0;
|
|
+ inode->i_atime = CURRENT_TIME;
|
|
+ inode->i_ctime = CURRENT_TIME;
|
|
+ inode->i_mtime = CURRENT_TIME;
|
|
+ inode->i_blksize = inode->i_sb->s_blocksize;
|
|
+ inode->i_blocks = 0;
|
|
+ inode->i_version = ++event;
|
|
+ inode->i_op = (inode->i_ino == SUPERMOUNT_ROOT_INO)
|
|
+ ? &supermount_dir_iops : NULL;
|
|
+ return;
|
|
+ default:
|
|
+ ;
|
|
+ }
|
|
+}
|
|
+
|
|
+void supermount_write_inode (struct inode * inode)
|
|
+{
|
|
+ struct super_block *tmp;
|
|
+ tmp = inode->i_sb->u.supermount_sb.s_subfs;
|
|
+
|
|
+ if (inode->u.supermount_i.i_hidden &&
|
|
+ tmp && tmp->s_op && tmp->s_op->write_inode)
|
|
+ tmp->s_op->write_inode(inode->u.supermount_i.i_hidden);
|
|
+
|
|
+ mark_subfs_dirty(inode->i_sb);
|
|
+}
|
|
+
|
|
+int supermount_permission (struct inode * inode, int mask)
|
|
+{
|
|
+ unsigned short mode;
|
|
+ struct inode *subi;
|
|
+
|
|
+ supermount_debug("inode %ld, mask 0%o\n", inode->i_ino, mask);
|
|
+
|
|
+ subi = subiget(inode);
|
|
+ if (!subi)
|
|
+ return -EIO;
|
|
+ if (subi->i_op && subi->i_op->permission) {
|
|
+ int rc = subi->i_op->permission(subi, mask);
|
|
+ iput(subi);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ mode = inode->i_mode;
|
|
+ /*
|
|
+ * Special case, access is always granted for root
|
|
+ */
|
|
+ if (fsuser()) {
|
|
+ iput(subi);
|
|
+ return 0;
|
|
+ } else if (current->fsuid == inode->i_uid)
|
|
+ mode >>= 6;
|
|
+ else if (in_group_p (inode->i_gid))
|
|
+ mode >>= 3;
|
|
+ iput(subi);
|
|
+ if (((mode & mask & S_IRWXO) == mask))
|
|
+ return 0;
|
|
+ else
|
|
+ return -EACCES;
|
|
+}
|
|
Index: linux/fs/supermount/namei.c
|
|
diff -u linux/fs/supermount/namei.c:1.1 linux/fs/supermount/namei.c:1.1.6.1
|
|
--- linux/fs/supermount/namei.c:1.1 Mon Feb 26 17:55:16 1996
|
|
+++ linux/fs/supermount/namei.c Sat Nov 9 17:27:25 1996
|
|
@@ -0,0 +1,348 @@
|
|
+/*
|
|
+ * linux/fs/supermount/namei.c
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ * from
|
|
+ *
|
|
+ * linux/fs/minix/namei.c
|
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
|
+ *
|
|
+ * and
|
|
+ *
|
|
+ * linux/fs/ext2/namei.c
|
|
+ * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
|
|
+ */
|
|
+
|
|
+/* This file handles almost all of the normal filesystem running of
|
|
+ supermount. We don't have to deal to much with the subfs
|
|
+ interface, since we just pass subinodes out to the application on
|
|
+ demand. */
|
|
+
|
|
+#include <asm/segment.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/supermount_fs.h>
|
|
+#include <linux/fcntl.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/locks.h>
|
|
+
|
|
+/* Attach a superinode to a subinode, and prepare a result for the
|
|
+ upper VFS layers. We return the superinode for directories, and
|
|
+ the subinode for other file types.
|
|
+ */
|
|
+static void attach_and_prepare(struct super_block *sb,
|
|
+ struct inode *subi, struct inode **result)
|
|
+{
|
|
+ struct inode *superi;
|
|
+ superi = supermount_attach(sb, subi);
|
|
+ /* We have now done iget() on superi and subi. */
|
|
+
|
|
+ /* If the subfs inode is a directory or a symlink, then we
|
|
+ need to deal with it ourselves, and only give back the
|
|
+ superinode to the application. Otherwise, we can just
|
|
+ return the subfs inode. */
|
|
+ if (S_ISDIR(subi->i_mode)) {
|
|
+ superi->i_op = &supermount_dir_iops;
|
|
+ iput(subi);
|
|
+ *result = superi;
|
|
+ return;
|
|
+ } else {
|
|
+ /* Not a directory-related inode, so we return the
|
|
+ subfs inode to the upper layers. We still need the
|
|
+ supermount inode in that case, though, to maintain
|
|
+ reference counts in the supermount superblock. */
|
|
+
|
|
+ iput(superi);
|
|
+ *result = subi;
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+int supermount_lookup (struct inode * dir, const char * name, int len,
|
|
+ struct inode ** result)
|
|
+{
|
|
+ struct inode *subi, *subdir;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s\n",
|
|
+ dir->i_ino, len, name);
|
|
+
|
|
+ *result = NULL;
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ if (!S_ISDIR(dir->i_mode)) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!(subdir = subiget(dir))) {
|
|
+ /* This now becomes the *easy* case. :-) */
|
|
+ iput (dir);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ rc = subdir->i_op->lookup(subdir, name, len, &subi);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput (dir);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ /* It worked, so now create a shadow supermount inode for the
|
|
+ result... */
|
|
+ attach_and_prepare(dir->i_sb, subi, result);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int supermount_create (struct inode * dir,const char * name, int len, int mode,
|
|
+ struct inode ** result)
|
|
+{
|
|
+ struct inode * inode, * subi;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
|
|
+ dir->i_ino, len, name, mode);
|
|
+
|
|
+ *result = NULL;
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->create) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->create(inode, name, len, mode, &subi);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ attach_and_prepare(dir->i_sb, subi, result);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int supermount_mknod (struct inode * dir, const char * name, int len, int mode,
|
|
+ int rdev)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
|
|
+ dir->i_ino, len, name, mode);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->mknod) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->mknod(inode, name, len, mode, rdev);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int supermount_mkdir (struct inode * dir, const char * name, int len, int mode)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s, mode = %o\n",
|
|
+ dir->i_ino, len, name, mode);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->mkdir) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->mkdir(inode, name, len, mode);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int supermount_rmdir (struct inode * dir, const char * name, int len)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s\n",
|
|
+ dir->i_ino, len, name);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->rmdir) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->rmdir(inode, name, len);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int supermount_unlink (struct inode * dir, const char * name, int len)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s\n",
|
|
+ dir->i_ino, len, name);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->unlink) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->unlink(inode, name, len);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int supermount_symlink (struct inode * dir, const char * name, int len,
|
|
+ const char * symname)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s, link = %s\n",
|
|
+ dir->i_ino, len, name, symname);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->symlink) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->symlink(inode, name, len, symname);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/* This probably won't work because higher levels will complain about
|
|
+ cross-device links. */
|
|
+int supermount_link (struct inode * oldinode, struct inode * dir,
|
|
+ const char * name, int len)
|
|
+{
|
|
+ struct inode * inode;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("inode = %ld, name = %*s, link to inode %ld\n",
|
|
+ dir->i_ino, len, name, oldinode->i_ino);
|
|
+
|
|
+ if (!dir)
|
|
+ return -ENOENT;
|
|
+ inode = subiget(dir);
|
|
+ if (!inode) {
|
|
+ iput(dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ if (!inode->i_op || !inode->i_op->link) {
|
|
+ iput(dir);
|
|
+ iput(inode);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = inode->i_op->link(oldinode, inode, name, len);
|
|
+ mark_subfs_dirty(dir->i_sb);
|
|
+ supermount_go_inactive(dir->i_sb);
|
|
+ iput(dir);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int supermount_rename (struct inode * old_dir, const char * old_name,
|
|
+ int old_len,
|
|
+ struct inode * new_dir, const char * new_name,
|
|
+ int new_len, int must_be_dir)
|
|
+{
|
|
+ struct inode * old_subi, * new_subi;
|
|
+ int rc;
|
|
+
|
|
+ supermount_debug ("from inode %ld, %*s to inode %ld, %*s\n",
|
|
+ old_dir->i_ino, old_len, old_name,
|
|
+ new_dir->i_ino, new_len, new_name);
|
|
+
|
|
+ if (!old_dir || !new_dir)
|
|
+ return -ENOENT;
|
|
+ old_subi = subiget(old_dir);
|
|
+ if (!old_subi) {
|
|
+ iput(old_dir);
|
|
+ iput(new_dir);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+ new_subi = subiget(new_dir);
|
|
+ if (!new_subi) {
|
|
+ iput(old_dir);
|
|
+ iput(new_dir);
|
|
+ iput(old_subi);
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ if (!old_subi->i_op || !old_subi->i_op->rename) {
|
|
+ iput(old_dir);
|
|
+ iput(new_dir);
|
|
+ iput(old_subi);
|
|
+ iput(new_subi);
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ rc = old_subi->i_op->rename(old_subi, old_name, old_len,
|
|
+ new_subi, new_name, new_len,
|
|
+ must_be_dir);
|
|
+ mark_subfs_dirty(old_dir->i_sb);
|
|
+ supermount_go_inactive(old_dir->i_sb);
|
|
+ iput(old_dir);
|
|
+ iput(new_dir);
|
|
+ return rc;
|
|
+}
|
|
Index: linux/fs/supermount/super.c
|
|
diff -u linux/fs/supermount/super.c:1.1 linux/fs/supermount/super.c:1.1.6.2
|
|
--- linux/fs/supermount/super.c:1.1 Mon Feb 26 17:55:16 1996
|
|
+++ linux/fs/supermount/super.c Sat Nov 9 19:57:42 1996
|
|
@@ -0,0 +1,431 @@
|
|
+/*
|
|
+ * linux/fs/supermount/super.c
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ * from
|
|
+ *
|
|
+ * linux/fs/minix/inode.c
|
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
|
+ *
|
|
+ * and
|
|
+ *
|
|
+ * linux/fs/ext2/super.c
|
|
+ * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
|
|
+ */
|
|
+
|
|
+#include <stdarg.h>
|
|
+
|
|
+#include <asm/segment.h>
|
|
+#include <asm/system.h>
|
|
+
|
|
+#include <linux/errno.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/supermount_fs.h>
|
|
+#include <linux/malloc.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/stat.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/locks.h>
|
|
+#include <linux/major.h>
|
|
+
|
|
+/* From fs/super.c */
|
|
+extern int do_umount(kdev_t);
|
|
+
|
|
+#ifdef SUPERMOUNT_DEBUG
|
|
+char supermount_debug_enable = 0;
|
|
+#endif
|
|
+
|
|
+static struct super_operations supermount_sops = {
|
|
+ supermount_read_inode,
|
|
+ NULL,
|
|
+ supermount_write_inode,
|
|
+ NULL, /* put_inode */
|
|
+ supermount_put_super,
|
|
+ supermount_write_super,
|
|
+ supermount_statfs,
|
|
+ NULL, /* supermount_remount */
|
|
+};
|
|
+
|
|
+static char error_buf[1024];
|
|
+
|
|
+/* Mount and mount the hidden fs */
|
|
+static void umount_subfs(struct super_block *);
|
|
+
|
|
+void supermount_error (struct super_block * sb, const char * function,
|
|
+ const char * fmt, ...)
|
|
+{
|
|
+ va_list args;
|
|
+
|
|
+ va_start (args, fmt);
|
|
+ vsprintf (error_buf, fmt, args);
|
|
+ va_end (args);
|
|
+ printk (KERN_CRIT "SUPERMOUNT error (device %d/%d): %s: %s\n",
|
|
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
|
|
+ /* @@ Do we want to do any special error handling here? */
|
|
+}
|
|
+
|
|
+NORET_TYPE void supermount_panic (struct super_block * sb,
|
|
+ const char * function,
|
|
+ const char * fmt, ...)
|
|
+{
|
|
+ va_list args;
|
|
+
|
|
+ va_start (args, fmt);
|
|
+ vsprintf (error_buf, fmt, args);
|
|
+ va_end (args);
|
|
+ panic ("SUPERMOUNT panic (device %d/%d): %s: %s\n",
|
|
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
|
|
+}
|
|
+
|
|
+void supermount_warning (struct super_block * sb, const char * function,
|
|
+ const char * fmt, ...)
|
|
+{
|
|
+ va_list args;
|
|
+
|
|
+ va_start (args, fmt);
|
|
+ vsprintf (error_buf, fmt, args);
|
|
+ va_end (args);
|
|
+ printk (KERN_WARNING "SUPERMOUNT-fs warning (device %d/%d): %s: %s\n",
|
|
+ MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf);
|
|
+}
|
|
+
|
|
+/* Release the superblock and any resources it has reserved */
|
|
+void supermount_put_super (struct super_block * sb)
|
|
+{
|
|
+ lock_super (sb);
|
|
+ if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED)
|
|
+ umount_subfs (sb);
|
|
+ sb->s_dev = 0;
|
|
+ unlock_super (sb);
|
|
+}
|
|
+
|
|
+
|
|
+static int copy_option(const char **option, const char *val)
|
|
+{
|
|
+ char *tmp;
|
|
+ supermount_debug ("assigning value \"%s\"\n", val);
|
|
+ if (!val || !*val)
|
|
+ return -EINVAL;
|
|
+ tmp = (char *) kmalloc(1 + strlen(val), GFP_KERNEL);
|
|
+ if (!tmp)
|
|
+ return -ENOMEM;
|
|
+ strcpy(tmp, val);
|
|
+ *option = tmp;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This function has been shamelessly adapted from the msdos fs
|
|
+ */
|
|
+static int parse_options (char * options, struct super_block *sb)
|
|
+{
|
|
+ char * this_char;
|
|
+ char * value;
|
|
+ int rc;
|
|
+
|
|
+ if (!options)
|
|
+ return 0;
|
|
+ while ((this_char = options)) {
|
|
+ if (!strncmp(this_char, "--,", 3))
|
|
+ this_char += 2;
|
|
+ if (*this_char == ',') {
|
|
+ /* An empty option, or the option "--",
|
|
+ introduces options to be passed through to
|
|
+ the subfs */
|
|
+ supermount_debug ("assigning remainder\n");
|
|
+ return copy_option(&sb->u.supermount_sb.s_data,
|
|
+ ++this_char);
|
|
+ }
|
|
+ if ((options = strchr (this_char, ',')))
|
|
+ *options++ = 0;
|
|
+
|
|
+ if ((value = strchr (this_char, '=')) != NULL)
|
|
+ *value++ = 0;
|
|
+
|
|
+ supermount_debug ("parsing option \"%s\"\n", this_char);
|
|
+ if (!strcmp (this_char, "fs")) {
|
|
+ rc = copy_option(&sb->u.supermount_sb.s_type, value);
|
|
+ if (rc) return rc;
|
|
+ } else if (!strcmp (this_char, "dev")) {
|
|
+ rc = copy_option(&sb->u.supermount_sb.s_devname,
|
|
+ value);
|
|
+ if (rc) return rc;
|
|
+ } else if (!strcmp (this_char, "debug")) {
|
|
+ supermount_debug_enable = 1;
|
|
+ } else {
|
|
+ printk ("supermount: "
|
|
+ "Unrecognized mount option %s\n", this_char);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* read_super: the main mount() entry point into the VFS layer. */
|
|
+struct super_block * supermount_read_super (struct super_block * sb,
|
|
+ void * data,
|
|
+ int silent)
|
|
+{
|
|
+ sb->s_blocksize = 1024;
|
|
+ sb->s_blocksize_bits = 10;
|
|
+ sb->s_magic = SUPERMOUNT_SUPER_MAGIC;
|
|
+ sb->s_op = &supermount_sops;
|
|
+ unlock_super(sb);
|
|
+ sb->u.supermount_sb.s_state = SUPERMOUNT_UNMOUNTED;
|
|
+ sb->u.supermount_sb.s_default_mode = 0777 | S_IFDIR;
|
|
+ sb->u.supermount_sb.s_mflags = sb->s_flags & (MS_REMOUNT - 1);
|
|
+ sb->u.supermount_sb.s_data = NULL;
|
|
+ sb->u.supermount_sb.s_undermount = NULL;
|
|
+ sb->u.supermount_sb.s_subfs = NULL;
|
|
+ sb->u.supermount_sb.s_opencount = 0;
|
|
+ sb->u.supermount_sb.s_dirty = 0;
|
|
+ sb->u.supermount_sb.s_type = NULL;
|
|
+ sb->u.supermount_sb.s_devname = NULL;
|
|
+
|
|
+ if (parse_options ((char *) data, sb)) {
|
|
+ sb->s_dev = 0;
|
|
+ return NULL;
|
|
+ }
|
|
+ if (!sb->u.supermount_sb.s_type)
|
|
+ copy_option(&sb->u.supermount_sb.s_type, "msdos");
|
|
+ if (!sb->u.supermount_sb.s_devname)
|
|
+ copy_option(&sb->u.supermount_sb.s_devname, "/dev/fd0");
|
|
+
|
|
+ sb->s_flags = sb->u.supermount_sb.s_mflags;
|
|
+ if (!(sb->s_mounted = iget(sb, SUPERMOUNT_ROOT_INO))) {
|
|
+ sb->s_dev = 0;
|
|
+ supermount_error (sb, "supermount_read_super",
|
|
+ "get root inode failed\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ return sb;
|
|
+}
|
|
+
|
|
+void supermount_write_super (struct super_block * sb)
|
|
+{
|
|
+ supermount_media_check(sb);
|
|
+ if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
|
|
+ struct super_block *tmp = sb->u.supermount_sb.s_subfs;
|
|
+ if (tmp && tmp->s_op && tmp->s_op->write_super)
|
|
+ tmp->s_op->write_super(tmp);
|
|
+ }
|
|
+ sb->s_dirt = 0;
|
|
+}
|
|
+
|
|
+#if 0
|
|
+int supermount_remount (struct super_block * sb, int * flags, char * data)
|
|
+{
|
|
+}
|
|
+#endif /* 0 */
|
|
+
|
|
+void supermount_statfs (struct super_block * sb, struct statfs * buf,
|
|
+ int bufsize)
|
|
+{
|
|
+ unsigned short fs;
|
|
+ struct statfs tmp;
|
|
+ supermount_media_check(sb);
|
|
+
|
|
+ if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
|
|
+ struct super_block * tmpsb =
|
|
+ sb->u.supermount_sb.s_undermount->i_mount->i_sb;
|
|
+ fs = get_fs();
|
|
+ set_fs(KERNEL_DS);
|
|
+ if (tmpsb->s_op && tmpsb->s_op->statfs)
|
|
+ tmpsb->s_op->statfs(tmpsb, &tmp, sizeof(tmp));
|
|
+ set_fs(fs);
|
|
+ } else {
|
|
+ tmp.f_bsize = sb->s_blocksize;
|
|
+ tmp.f_blocks = 0;
|
|
+ tmp.f_bfree = 0;
|
|
+ tmp.f_bavail = 0;
|
|
+ tmp.f_files = 0;
|
|
+ tmp.f_ffree = 0;
|
|
+ tmp.f_namelen = 0;
|
|
+ }
|
|
+ tmp.f_type = SUPERMOUNT_SUPER_MAGIC;
|
|
+ memcpy_tofs(buf, &tmp, bufsize);
|
|
+}
|
|
+
|
|
+/* Check for media change, but without invalidating buffers and inodes */
|
|
+static int just_check_disk_change(dev_t dev)
|
|
+{
|
|
+ if (!query_disk_change(dev))
|
|
+ return 0;
|
|
+ supermount_debug("Disk change detected on device %d/%d\n",
|
|
+ MAJOR(dev), MINOR(dev));
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static void umount_subfs(struct super_block *sb)
|
|
+{
|
|
+ int retval;
|
|
+ struct inode *inode, *subi;
|
|
+
|
|
+ supermount_debug("Trying to unmount device %s.\n",
|
|
+ sb->u.supermount_sb.s_devname);
|
|
+
|
|
+ /* Detach the subfs from the supermount root inode */
|
|
+ inode = sb->s_mounted;
|
|
+ /* Inode may not be set if we are currently unmounting the superfs */
|
|
+ if (inode) {
|
|
+ subi = inode->u.supermount_i.i_hidden;
|
|
+ if (subi) {
|
|
+ subi->i_shadow = 0;
|
|
+ inode->u.supermount_i.i_hidden = 0;
|
|
+ iput(inode);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (sb->u.supermount_sb.s_subfs->s_mounted->i_count != 1)
|
|
+ supermount_panic (sb, "umount_subfs",
|
|
+ "subfs root i_count = %d, should be 1\n",
|
|
+ sb->u.supermount_sb.s_subfs->s_mounted->i_count);
|
|
+ if (sb->u.supermount_sb.s_undermount->i_count != 1)
|
|
+ supermount_panic (sb, "umount_subfs",
|
|
+ "undermount i_count = %d, should be 1\n",
|
|
+ sb->u.supermount_sb.s_subfs->s_mounted->i_count);
|
|
+
|
|
+ sb->u.supermount_sb.s_subfs->s_mounted->i_count++;
|
|
+ sb->u.supermount_sb.s_state = SUPERMOUNT_UNMOUNTED;
|
|
+ retval = do_umounti(sb->u.supermount_sb.s_subfs->s_mounted);
|
|
+ if (retval)
|
|
+ supermount_panic (sb, "umount_subfs",
|
|
+ "Help - can't umount subfs!!!");
|
|
+ supermount_debug("subfs is unmounted.\n");
|
|
+ sb->u.supermount_sb.s_undermount = 0;
|
|
+ sb->u.supermount_sb.s_version = ++event;
|
|
+ sb->u.supermount_sb.s_subfs = 0;
|
|
+ sb->s_flags = sb->u.supermount_sb.s_mflags;
|
|
+ if (inode)
|
|
+ inode->i_mode = sb->u.supermount_sb.s_default_mode;
|
|
+}
|
|
+
|
|
+/* Return 0 (OK) if medium is valid. */
|
|
+int supermount_media_check(struct super_block * sb)
|
|
+{
|
|
+ int retval;
|
|
+ unsigned short fs;
|
|
+
|
|
+ /* If there are still files open, we never bother checking the
|
|
+ medium. */
|
|
+ if (sb->u.supermount_sb.s_subfs &&
|
|
+ subfs_is_active(sb)) {
|
|
+ supermount_debug ("subfs is active.\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ supermount_debug ("starting (%sactive now)\n",
|
|
+ (sb->u.supermount_sb.s_subfs &&
|
|
+ subfs_is_active(sb)) ?
|
|
+ "" : "not ");
|
|
+
|
|
+ lock_super(sb);
|
|
+
|
|
+ /* Are we checking for mount or unmount/remount? */
|
|
+ if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
|
|
+ /* Already mounted --- check for disk change or
|
|
+ disk not present */
|
|
+ int dev = sb->u.supermount_sb.s_subfs->s_dev;
|
|
+ if (!just_check_disk_change(dev)) {
|
|
+ unlock_super(sb);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* We have a disk change! Unmount the subfs */
|
|
+ supermount_debug ("trying to unmount\n");
|
|
+ umount_subfs(sb);
|
|
+ /* The call to just_check_disk_change may clear the media-
|
|
+ changed flag on the device, so we need to force a media
|
|
+ invalidation. We don't want to do this before unmounting
|
|
+ the subfs, naturally! */
|
|
+ invalidate_media(dev);
|
|
+ /* Now we are unmounted; fall through to the next check. */
|
|
+ }
|
|
+
|
|
+ if (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED) {
|
|
+ unlock_super(sb);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* OK, we're unmounted now --- can we remount? Please? */
|
|
+ if (!sb->u.supermount_sb.s_undermount) {
|
|
+ sb->u.supermount_sb.s_undermount =
|
|
+ iget(sb, SUPERMOUNT_HIDDEN_INO);
|
|
+ if (!sb->u.supermount_sb.s_undermount)
|
|
+ supermount_panic (sb, "supermount_media_check",
|
|
+ "Can't get root hidden inode!");
|
|
+ sb->u.supermount_sb.s_undermount->i_flags |= S_UNBOUND;
|
|
+ }
|
|
+
|
|
+ sb->u.supermount_sb.s_version = ++event;
|
|
+ sb->s_mounted->u.supermount_i.i_sb_version = event;
|
|
+ supermount_debug ("trying to mount\n");
|
|
+ supermount_debug ("fs=%s, dev=%s, data=%s, flags=%08lx\n",
|
|
+ sb->u.supermount_sb.s_type,
|
|
+ sb->u.supermount_sb.s_devname,
|
|
+ sb->u.supermount_sb.s_data,
|
|
+ sb->s_flags);
|
|
+ fs = get_fs();
|
|
+ set_fs(KERNEL_DS);
|
|
+ sb->s_flags = sb->u.supermount_sb.s_mflags,
|
|
+ retval = do_mounti(sb->u.supermount_sb.s_undermount,
|
|
+ "<supermount>",
|
|
+ sb->u.supermount_sb.s_devname,
|
|
+ sb->u.supermount_sb.s_type,
|
|
+ sb->s_flags | MS_MGC_VAL,
|
|
+ sb->u.supermount_sb.s_data);
|
|
+ if (retval == -EROFS && !(sb->u.supermount_sb.s_mflags & MS_RDONLY)) {
|
|
+ /* OK, that failed, so try it readonly */
|
|
+ sb->s_flags |= MS_RDONLY;
|
|
+ retval = do_mounti(sb->u.supermount_sb.s_undermount,
|
|
+ "<supermount>",
|
|
+ sb->u.supermount_sb.s_devname,
|
|
+ sb->u.supermount_sb.s_type,
|
|
+ sb->s_flags | MS_MGC_VAL,
|
|
+ sb->u.supermount_sb.s_data);
|
|
+ }
|
|
+ set_fs(fs);
|
|
+
|
|
+ unlock_super(sb);
|
|
+ if (retval) {
|
|
+ sb->s_flags = sb->u.supermount_sb.s_mflags;
|
|
+ iput(sb->u.supermount_sb.s_undermount);
|
|
+ sb->u.supermount_sb.s_undermount = 0;
|
|
+ supermount_debug ("Mount failed, errno %d\n", -retval);
|
|
+ return 1;
|
|
+ }
|
|
+ /* Hey --- success!!! */
|
|
+ sb->u.supermount_sb.s_subfs = sb->u.supermount_sb.s_undermount
|
|
+ ->i_mount->i_sb;
|
|
+ if (!sb->u.supermount_sb.s_subfs->s_mounted)
|
|
+ supermount_panic (sb, "supermount_media_check",
|
|
+ "Mounted subfs has no root inode!");
|
|
+ sb->u.supermount_sb.s_state = SUPERMOUNT_SUSPENDED;
|
|
+ supermount_debug ("Mount succeeded!\n");
|
|
+ /* For counting open inodes on the subfs, we rely on the fact
|
|
+ that the root inode is always exactly one count. So make
|
|
+ sure we guarantee it is always open! */
|
|
+ supermount_iopen(sb->s_mounted);
|
|
+ sb->s_mounted->i_flags |= S_UNBOUND;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Check whether an inode still belongs to valid medium. */
|
|
+int supermount_check_inode(struct inode * inode)
|
|
+{
|
|
+ supermount_debug ("inode = %ld\n", inode->i_ino);
|
|
+
|
|
+ if (supermount_media_check(inode->i_sb))
|
|
+ return 1;
|
|
+ if (inode_is_obsolete(inode)) {
|
|
+ /* What happens if we remount an old disk, and get
|
|
+ back the same superinode number? subiget() will
|
|
+ handle it through the i_subino field, and
|
|
+ supermount_attach will avoid reusing the old
|
|
+ inode. */
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
Index: linux/include/linux/fs.h
|
|
diff -u linux/include/linux/fs.h:1.12 linux/include/linux/fs.h:1.12.2.1
|
|
--- linux/include/linux/fs.h:1.12 Wed Nov 6 23:17:37 1996
|
|
+++ linux/include/linux/fs.h Sat Nov 9 17:26:30 1996
|
|
@@ -74,6 +74,10 @@
|
|
#define S_WRITE 128 /* Write on file/directory/symlink */
|
|
#define S_APPEND 256 /* Append-only file */
|
|
#define S_IMMUTABLE 512 /* Immutable file */
|
|
+#define S_UNBOUND 1024 /* inode is not bound to user space,
|
|
+ and so the filesystem may be
|
|
+ unmounted even if this inode is in
|
|
+ use. */
|
|
|
|
/*
|
|
* Flags that can be altered by MS_REMOUNT
|
|
@@ -103,6 +107,7 @@
|
|
#define IS_WRITABLE(inode) ((inode)->i_flags & S_WRITE)
|
|
#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
|
|
#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
|
|
+#define IS_UNBOUND(inode) ((inode)->i_flags & S_UNBOUND)
|
|
|
|
/* the read-only stuff doesn't really belong here, but any other place is
|
|
probably as bad and I don't want to create yet another include file. */
|
|
@@ -216,6 +221,7 @@
|
|
}
|
|
|
|
#include <linux/pipe_fs_i.h>
|
|
+#include <linux/supermount_fs_i.h>
|
|
#include <linux/minix_fs_i.h>
|
|
#include <linux/ext_fs_i.h>
|
|
#include <linux/ext2_fs_i.h>
|
|
@@ -284,6 +290,8 @@
|
|
unsigned long i_nrpages;
|
|
struct semaphore i_sem;
|
|
struct inode_operations *i_op;
|
|
+ struct inode * i_shadow;
|
|
+ struct inode_shadow_operations * i_shadow_op;
|
|
struct super_block *i_sb;
|
|
struct wait_queue *i_wait;
|
|
struct file_lock *i_flock;
|
|
@@ -305,6 +313,7 @@
|
|
unsigned short i_writecount;
|
|
union {
|
|
struct pipe_inode_info pipe_i;
|
|
+ struct supermount_inode_info supermount_i;
|
|
struct minix_inode_info minix_i;
|
|
struct ext_inode_info ext_i;
|
|
struct ext2_inode_info ext2_i;
|
|
@@ -402,6 +411,7 @@
|
|
|
|
extern int fasync_helper(struct inode *, struct file *, int, struct fasync_struct **);
|
|
|
|
+#include <linux/supermount_fs_sb.h>
|
|
#include <linux/minix_fs_sb.h>
|
|
#include <linux/ext_fs_sb.h>
|
|
#include <linux/ext2_fs_sb.h>
|
|
@@ -431,6 +441,7 @@
|
|
struct inode * s_mounted;
|
|
struct wait_queue * s_wait;
|
|
union {
|
|
+ struct supermount_sb_info supermount_sb;
|
|
struct minix_sb_info minix_sb;
|
|
struct ext_sb_info ext_sb;
|
|
struct ext2_sb_info ext2_sb;
|
|
@@ -491,6 +502,12 @@
|
|
int (*smap) (struct inode *,int);
|
|
};
|
|
|
|
+struct inode_shadow_operations {
|
|
+ void (*open) (struct inode *, int);
|
|
+ void (*write) (struct inode *);
|
|
+ void (*release) (struct inode *);
|
|
+};
|
|
+
|
|
struct super_operations {
|
|
void (*read_inode) (struct inode *);
|
|
int (*notify_change) (struct inode *, struct iattr *);
|
|
@@ -600,9 +617,11 @@
|
|
}
|
|
|
|
extern int check_disk_change(kdev_t dev);
|
|
+extern int query_disk_change(kdev_t dev);
|
|
extern void invalidate_inodes(kdev_t dev);
|
|
extern void invalidate_inode_pages(struct inode *);
|
|
extern void invalidate_buffers(kdev_t dev);
|
|
+extern void invalidate_media(kdev_t dev);
|
|
extern int floppy_is_wp(int minor);
|
|
extern void sync_inodes(kdev_t dev);
|
|
extern void sync_dev(kdev_t dev);
|
|
@@ -663,6 +682,9 @@
|
|
|
|
extern void show_buffers(void);
|
|
extern void mount_root(void);
|
|
+extern int do_mounti(struct inode *_inode, const char *, const char *,
|
|
+ const char *, unsigned long, const void *);
|
|
+extern int do_umounti(struct inode *);
|
|
|
|
#ifdef CONFIG_BLK_DEV_INITRD
|
|
extern kdev_t real_root_dev;
|
|
Index: linux/include/linux/supermount_fs.h
|
|
diff -u linux/include/linux/supermount_fs.h:1.1 linux/include/linux/supermount_fs.h:1.1.4.1
|
|
--- linux/include/linux/supermount_fs.h:1.1 Mon Feb 26 17:55:21 1996
|
|
+++ linux/include/linux/supermount_fs.h Sat Nov 9 17:27:49 1996
|
|
@@ -0,0 +1,165 @@
|
|
+/*
|
|
+ * linux/include/linux/supermount_fs.h
|
|
+ *
|
|
+ * Defines and strutures for the dynamic remounting of removable media
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ * from
|
|
+ *
|
|
+ * linux/include/linux/minix_fs.h
|
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
|
+ *
|
|
+ * and
|
|
+ *
|
|
+ * linux/include/linux/ext2_fs.h
|
|
+ * Copyright (C) 1992, 1993, 1994, 1995 Remy Card
|
|
+ */
|
|
+
|
|
+#ifndef _LINUX_SUPERMOUNT_FS_H
|
|
+#define _LINUX_SUPERMOUNT_FS_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+#define SUPERMOUNT_DEBUG
|
|
+
|
|
+#define SUPERMOUNT_VERSION "0.4"
|
|
+
|
|
+/*
|
|
+ * Debug code
|
|
+ */
|
|
+#ifdef SUPERMOUNT_DEBUG
|
|
+ extern char supermount_debug_enable;
|
|
+
|
|
+ #define supermount_debug(f, a...) \
|
|
+ { \
|
|
+ if (supermount_debug_enable) { \
|
|
+ printk ("SUPERMOUNT DEBUG (%s, %d): %s: ", \
|
|
+ __FILE__, __LINE__, __FUNCTION__); \
|
|
+ printk (f, ## a); \
|
|
+ } \
|
|
+ }
|
|
+#else
|
|
+ #define supermount_debug(f, a...) /**/
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Special inodes numbers
|
|
+ */
|
|
+#define SUPERMOUNT_HIDDEN_INO 0 /* Hidden inode for
|
|
+ sub-mounting */
|
|
+#define SUPERMOUNT_ROOT_INO 1 /* Root inode */
|
|
+
|
|
+/*
|
|
+ * The supermount superblock magic number
|
|
+ */
|
|
+#define SUPERMOUNT_SUPER_MAGIC 0x9fa1
|
|
+
|
|
+#ifdef __KERNEL__
|
|
+/*
|
|
+ * Function prototypes
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
|
|
+ * supermount source programs needs to include it so they are duplicated here.
|
|
+ */
|
|
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
|
|
+# define NORET_TYPE __volatile__
|
|
+# define ATTRIB_NORET /**/
|
|
+# define NORET_AND /**/
|
|
+#else
|
|
+# define NORET_TYPE /**/
|
|
+# define ATTRIB_NORET __attribute__((noreturn))
|
|
+# define NORET_AND noreturn,
|
|
+#endif
|
|
+
|
|
+/* How to test if a supermount filesystem is active or not: */
|
|
+static inline int subfs_is_active(struct super_block *sb)
|
|
+{
|
|
+ /* The subfs is deemed inactive iff only the root is open, and
|
|
+ the its i_count is one. */
|
|
+ return (sb->u.supermount_sb.s_state != SUPERMOUNT_UNMOUNTED &&
|
|
+ (sb->u.supermount_sb.s_opencount > 1 ||
|
|
+ sb->u.supermount_sb.s_undermount->i_mount->i_count > 1));
|
|
+}
|
|
+
|
|
+/* How to test if an inode is obsolete: */
|
|
+static inline int inode_is_obsolete(struct inode *inode)
|
|
+{
|
|
+ return (inode->u.supermount_i.i_sb_version !=
|
|
+ inode->i_sb->u.supermount_sb.s_version);
|
|
+}
|
|
+
|
|
+/* Manage the subfs dirty flag */
|
|
+static inline void mark_subfs_dirty(struct super_block *sb)
|
|
+{
|
|
+ sb->u.supermount_sb.s_dirty = 1;
|
|
+}
|
|
+static inline void mark_subfs_clean(struct super_block *sb)
|
|
+{
|
|
+ sb->u.supermount_sb.s_dirty = 0;
|
|
+}
|
|
+static inline int subfs_is_dirty(struct super_block *sb)
|
|
+{
|
|
+ return (sb->u.supermount_sb.s_dirty);
|
|
+}
|
|
+
|
|
+/* inode.c */
|
|
+extern struct inode * subiget(struct inode *);
|
|
+extern void supermount_iopen(struct inode *);
|
|
+extern void supermount_iclose(struct inode *);
|
|
+extern void supermount_go_inactive(struct super_block *);
|
|
+extern struct inode * supermount_attach(struct super_block *, struct inode *);
|
|
+extern void supermount_read_inode (struct inode *);
|
|
+extern void supermount_write_inode (struct inode *);
|
|
+extern void supermount_put_inode (struct inode *);
|
|
+extern int supermount_permission (struct inode *, int mask);
|
|
+
|
|
+/* namei.c */
|
|
+extern void supermount_release (struct inode *, struct file *);
|
|
+extern int supermount_lookup (struct inode *,const char *, int, struct inode **);
|
|
+extern int supermount_create (struct inode *,const char *, int, int,
|
|
+ struct inode **);
|
|
+extern int supermount_mkdir (struct inode *, const char *, int, int);
|
|
+extern int supermount_rmdir (struct inode *, const char *, int);
|
|
+extern int supermount_unlink (struct inode *, const char *, int);
|
|
+extern int supermount_symlink (struct inode *, const char *, int, const char *);
|
|
+extern int supermount_link (struct inode *, struct inode *, const char *, int);
|
|
+extern int supermount_mknod (struct inode *, const char *, int, int, int);
|
|
+extern int supermount_rename (struct inode *, const char *, int,
|
|
+ struct inode *, const char *, int, int);
|
|
+
|
|
+/* super.c */
|
|
+extern void supermount_error (struct super_block *, const char *, const char *, ...)
|
|
+ __attribute__ ((format (printf, 3, 4)));
|
|
+extern NORET_TYPE void supermount_panic (struct super_block *, const char *,
|
|
+ const char *, ...)
|
|
+ __attribute__ ((NORET_AND format (printf, 3, 4)));
|
|
+extern void supermount_warning (struct super_block *, const char *, const char *, ...)
|
|
+ __attribute__ ((format (printf, 3, 4)));
|
|
+extern void supermount_put_super (struct super_block *);
|
|
+extern void supermount_write_super (struct super_block *);
|
|
+extern int supermount_remount (struct super_block *, int *, char *);
|
|
+extern struct super_block * supermount_read_super (struct super_block *,void *,int);
|
|
+extern void supermount_statfs (struct super_block *, struct statfs *, int);
|
|
+extern int supermount_media_check (struct super_block *);
|
|
+extern int supermount_check_inode (struct inode *);
|
|
+
|
|
+/* dir.c */
|
|
+extern struct inode_operations supermount_dir_iops;
|
|
+extern struct inode_operations supermount_root_iops;
|
|
+
|
|
+/* inode.c */
|
|
+extern struct inode_shadow_operations supermount_shadow_iops;
|
|
+
|
|
+/* file.c */
|
|
+/* extern struct inode_operations supermount_shadow_file_iops; */
|
|
+
|
|
+/* symlink.c */
|
|
+extern struct inode_operations supermount_symlink_iops;
|
|
+
|
|
+#endif /* __KERNEL__ */
|
|
+
|
|
+#endif /* _LINUX_SUPERMOUNT_FS_H */
|
|
Index: linux/include/linux/supermount_fs_i.h
|
|
diff -u linux/include/linux/supermount_fs_i.h:1.1 linux/include/linux/supermount_fs_i.h:1.1.4.1
|
|
--- linux/include/linux/supermount_fs_i.h:1.1 Mon Feb 26 17:55:22 1996
|
|
+++ linux/include/linux/supermount_fs_i.h Sat Nov 9 17:27:49 1996
|
|
@@ -0,0 +1,23 @@
|
|
+/*
|
|
+ * linux/include/linux/supermount_fs.h
|
|
+ *
|
|
+ * In-core inode structure for the dynamic remounting of removable media
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _LINUX_SUPERMOUNT_FS_I_H
|
|
+#define _LINUX_SUPERMOUNT_FS_I_H
|
|
+
|
|
+struct supermount_inode_info {
|
|
+ struct inode * i_hidden;
|
|
+ int i_sb_version;
|
|
+ int i_subino;
|
|
+ int i_counted;/* Has this inode been counted in
|
|
+ the superblock reference counts
|
|
+ yet? */
|
|
+};
|
|
+
|
|
+#endif /* _LINUX_SUPERMOUNT_FS_I_H */
|
|
Index: linux/include/linux/supermount_fs_sb.h
|
|
diff -u linux/include/linux/supermount_fs_sb.h:1.1 linux/include/linux/supermount_fs_sb.h:1.1.4.1
|
|
--- linux/include/linux/supermount_fs_sb.h:1.1 Mon Feb 26 17:55:22 1996
|
|
+++ linux/include/linux/supermount_fs_sb.h Sat Nov 9 17:27:49 1996
|
|
@@ -0,0 +1,44 @@
|
|
+/*
|
|
+ * linux/include/linux/supermount_sb_fs.h
|
|
+ *
|
|
+ * In-core superblock struct for the dynamic remounting of removable media
|
|
+ *
|
|
+ * Copyright (C) 1995
|
|
+ * Stephen Tweedie (sct@dcs.ed.ac.uk)
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _LINUX_SUPERMOUNT_FS_SB_H
|
|
+#define _LINUX_SUPERMOUNT_FS_SB_H
|
|
+
|
|
+typedef enum {
|
|
+ SUPERMOUNT_UNMOUNTED, /* No media mounted */
|
|
+ SUPERMOUNT_SUSPENDED, /* Mounted but suspended because
|
|
+ no files open */
|
|
+ SUPERMOUNT_ONLINE, /* Mounted and active */
|
|
+} sm_state_t;
|
|
+
|
|
+/*
|
|
+ * supermount super-block data in memory
|
|
+ */
|
|
+struct supermount_sb_info {
|
|
+ sm_state_t s_state;
|
|
+ int s_version; /* Used to indicate obsolete inodes */
|
|
+ mode_t s_default_mode; /* Default mode for supermount root */
|
|
+
|
|
+ const char * s_type; /* Type of fs to be sub-mounted */
|
|
+ const char * s_devname; /* Where to mount the subfs */
|
|
+ int s_mflags; /* Flags to pass when mounting subfs */
|
|
+ const char * s_data; /* Data to pass when mounting subfs */
|
|
+
|
|
+ struct inode * s_undermount; /* Mount point for subfs */
|
|
+ struct super_block * s_subfs; /* The submounted fs sb */
|
|
+ int s_opencount; /* Refcount of opened inodes
|
|
+ (an inode in use as cwd
|
|
+ does not count as open) */
|
|
+
|
|
+ /* Flags */
|
|
+ int s_dirty : 1; /* Do we need to fsync() the subfs? */
|
|
+};
|
|
+
|
|
+#endif /* _LINUX_SUPERMOUNT_FS_SB_H */
|