From: almesber@nessie.cs.id.ethz.ch (Werner Almesberger)
Subject: Re: mrphmpmmmph shoelace and partitions
Organization: Swiss Federal Institute of Technology (ETH), Zurich, CH
Date: Sat, 25 Jul 1992 21:00:10 GMT

In article <1992Jul24.143547.23391@crd.ge.com> davidsen@crd.ge.com (bill davidsen) writes:
>In article <1992Jul24.021543.24526@sol.UVic.CA>, pmacdona@sanjuan (Peter MacDonald) writes:
>
>| One solution is to implement quotas, but I think Linus may
>| have said nay to that already.  Another would be to
>| allow mounting of files as file systems?  Comments? Catcalls?

I've had this sitting around for a long time. A patch I've originally
made for 0.96c-pl1 and that seems to work unmodified for 0.96c-pl2 is
at the end of this posting.

Usage example:

  # a floppy with a Minix FS (e.g. the rootimage) is in drive A:
  dd if=/dev/fd0 of=/file bs=256k
  mount /file /mnt

A few remarks:
  - files that reside on an MS-DOS FS can only be mounted if that FS
    supports bmap. Hard disk and 3.5" floppy file systems usually
    don't.
  - newer umounts may refuse to unmount a mounted file. Hacking umount
    to accept files is left as an exercise to the reader ;-)
  - recursion (mounting a file from an FS that is a mounted file,
    etc.) is possible.

>   Well, I like the basic idea, because it solves a bunch of problems.
> But it needs a bit of support before it really works; namely support in
> fsck and mkfs to support it.

Last time I've checked (early June, 0.96a-pl2), fsck and mkfs were able
to operate on files.

Enjoy,
- Werner

---------------------------------- cut here -----------------------------------

diff -cr +new-files linux.orig/fs/Makefile linux/fs/Makefile
*** linux.orig/fs/Makefile	Fri Jul 17 08:56:13 1992
--- linux/fs/Makefile	Fri Jul 17 09:55:19 1992
***************
*** 18,24 ****
  
  OBJS=	open.o read_write.o inode.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o
  
  all: fs.o subdirs
  
--- 18,24 ----
  
  OBJS=	open.o read_write.o inode.o file_table.o buffer.o super.o \
  	block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \
! 	select.o fifo.o loop.o
  
  all: fs.o subdirs
  
diff -cr +new-files linux.orig/fs/buffer.c linux/fs/buffer.c
*** linux.orig/fs/buffer.c	Fri Jul 17 08:56:13 1992
--- linux/fs/buffer.c	Fri Jul 17 09:35:30 1992
***************
*** 23,28 ****
--- 23,29 ----
  #include <linux/config.h>
  #include <linux/sched.h>
  #include <linux/kernel.h>
+ #include <linux/loop.h>
  #include <asm/system.h>
  #include <asm/io.h>
  
***************
*** 261,266 ****
--- 262,269 ----
  	struct buffer_head * bh, * tmp;
  	int buffers;
  
+ 	while (MAJOR(dev) == LOOP_MAJOR)
+ 		if (loop_trans(&dev,&block)) break;
  repeat:
  	if (bh = get_hash_table(dev,block))
  		return bh;
diff -cr +new-files linux.orig/fs/loop.c linux/fs/loop.c
*** linux.orig/fs/loop.c
--- linux/fs/loop.c	Fri Jul 17 09:35:31 1992
***************
*** 0 ****
--- 1,73 ----
+ /* Loop devices. They're used to mount files as FS'. */
+ /* Written 1992 by Werner Almesberger */
+ 
+ #include <asm/segment.h>
+ #include <linux/kernel.h>
+ #include <linux/fs.h>
+ #include <linux/loop.h>
+ #include <errno.h>
+ 
+ 
+ static int first_use = 1;
+ static struct inode *loops[MAX_LOOPS];
+ 
+ 
+ int loop_getdev(struct inode *inode)
+ {
+ 	int count;
+ 
+ 	if (first_use) {
+ 		for (count = 0; count < MAX_LOOPS; count++) loops[count] = NULL;
+ 		first_use = 0;
+ 	}
+ 	if (inode->i_op == NULL || inode->i_op->bmap == NULL) return -EINVAL;
+ 	for (count = 0; count < MAX_LOOPS; count++)
+ 		if (loops[count] == inode) return -EBUSY;
+ 	for (count = 0; count < MAX_LOOPS; count++)
+ 		if (loops[count] == NULL) {
+ 			loops[count] = inode;
+ 			return (LOOP_MAJOR << 8) | count;
+ 		}
+ 	return -ENODEV;
+ }
+ 
+ 
+ int loop_finddev(struct inode *inode)
+ {
+ 	int count;
+ 
+ 	for (count = 0; count < MAX_LOOPS; count++)
+ 		if (loops[count] == inode) return (LOOP_MAJOR << 8) | count;
+ 	return -ENODEV;
+ }
+ 
+ 
+ void loop_dropdev(int dev)
+ {
+ 	int loop;
+ 
+ 	if (MAJOR(dev) != LOOP_MAJOR) panic("loop_dropdev: bad major number");
+ 	loop = MINOR(dev);
+ 	if (loop < 0 || loop >= MAX_LOOPS || loops[loop] == NULL)
+ 		panic("loop_dropdev: bad minor number");
+ 	iput(loops[loop]);
+ 	loops[loop] = NULL;
+ }
+ 
+ 
+ int loop_trans(int *dev,int *block)
+ {
+ 	int loop,this;
+ 
+ 	if (MAJOR(*dev) != LOOP_MAJOR) panic("loop_trans: bad major number");
+ 	loop = MINOR(*dev);
+ 	if (loop < 0 || loop >= MAX_LOOPS || loops[loop] == NULL)
+ 		panic("loop_trans: bad minor number");
+ 	if (*block < 0 || *block >= ((loops[loop]->i_size+BLOCK_SIZE-1) >>
+ 	    BLOCK_SIZE_BITS)) return -1;
+ /* makes a lot of noise when failing, but it's better than a panic. */
+ 	if (!(this = bmap(loops[loop],*block))) return -1;
+ 	*block = this;
+ 	*dev = loops[loop]->i_dev;
+ 	return 0;
+ }
diff -cr +new-files linux.orig/fs/super.c linux/fs/super.c
*** linux.orig/fs/super.c	Fri Jul 17 08:56:14 1992
--- linux/fs/super.c	Fri Jul 17 10:05:33 1992
***************
*** 13,18 ****
--- 13,19 ----
  #include <linux/ext_fs.h>
  #include <linux/msdos_fs.h>
  #include <linux/kernel.h>
+ #include <linux/loop.h>
  #include <linux/stat.h>
  #include <asm/system.h>
  #include <asm/segment.h>
***************
*** 158,167 ****
  		return -EPERM;
  	if (!(inode = namei(dev_name)))
  		return -ENOENT;
! 	dev = inode->i_rdev;
! 	if (!S_ISBLK(inode->i_mode)) {
! 		iput(inode);
! 		return -ENOTBLK;
  	}
  	iput(inode);
  	if (dev==ROOT_DEV)
--- 159,176 ----
  		return -EPERM;
  	if (!(inode = namei(dev_name)))
  		return -ENOENT;
! 	if (S_ISBLK(inode->i_mode)) dev = inode->i_rdev;
! 	else {
! 		if (S_ISREG(inode->i_mode)) {
! 			if ((dev = loop_finddev(inode)) < 0) {
! 				iput(inode);
! 				return dev;
! 			}
! 		}
! 		else {
! 			iput(inode);
! 			return -ENOTBLK;
! 		}
  	}
  	iput(inode);
  	if (dev==ROOT_DEV)
***************
*** 185,190 ****
--- 194,200 ----
  		sb->s_op->write_super (sb);
          put_super(dev);
          sync_dev(dev);
+ 	if (MAJOR(dev) == LOOP_MAJOR) loop_dropdev(dev);
  	return 0;
  }
  
***************
*** 248,254 ****
  	unsigned long new_flags, void *data)
  {
  	struct inode * inode;
! 	int dev;
  	int retval = 0;
  	char tmp[100],*t;
  	int i;
--- 258,264 ----
  	unsigned long new_flags, void *data)
  {
  	struct inode * inode;
! 	int dev = 0; /* to make GCC happy ... */
  	int retval = 0;
  	char tmp[100],*t;
  	int i;
***************
*** 259,269 ****
  		return -EPERM;
  	if (!(inode = namei(dev_name)))
  		return -ENOENT;
! 	dev = inode->i_rdev;
! 	if (!S_ISBLK(inode->i_mode))
! 		retval = -EPERM;
! 	else if (IS_NODEV(inode))
! 		retval = -EACCES;
  	iput(inode);
  	if (retval)
  		return retval;
--- 269,282 ----
  		return -EPERM;
  	if (!(inode = namei(dev_name)))
  		return -ENOENT;
! 	if (S_ISBLK(inode->i_mode)) {
! 		if (IS_NODEV(inode)) retval = -EACCES;
! 		else dev = inode->i_rdev;
! 	}
! 	else {
! 		if (!S_ISREG(inode->i_mode)) retval = -EPERM;
! 		else if ((dev = loop_getdev(inode)) < 0) retval = dev;
!   	}
  	iput(inode);
  	if (retval)
  		return retval;
***************
*** 285,291 ****
  		t = tmp;
  	} else
  		t = "minix";
! 	retval = do_mount(dev,dir_name,t,flags,(void *) page);
  	free_page(page);
  	return retval;
  }
--- 298,305 ----
  		t = tmp;
  	} else
  		t = "minix";
! 	if ((retval = do_mount(dev,dir_name,t,flags,(void *) page)) < 0 &&
! 	    MAJOR(dev) == LOOP_MAJOR) loop_dropdev(dev);
  	free_page(page);
  	return retval;
  }
diff -cr +new-files linux.orig/include/linux/loop.h linux/include/linux/loop.h
*** linux.orig/include/linux/loop.h
--- linux/include/linux/loop.h	Fri Jul 17 09:35:32 1992
***************
*** 0 ****
--- 1,12 ----
+ #ifndef _LOOP_H
+ #define _LOOP_H
+ 
+ #define LOOP_MAJOR 10	/* loop device major number */
+ #define MAX_LOOPS   8   /* max. number of loop devices */
+ 
+ int loop_getdev(struct inode *inode); /* create loop device */
+ int loop_finddev(struct inode *inode); /* find loop device */
+ void loop_dropdev(int dev); /* remove loop device */
+ int loop_trans(int *dev,int *block); /* translate to real params */
+ 
+ #endif
diff -cr +new-files linux.orig/kernel/blk_drv/blk.h linux/kernel/blk_drv/blk.h
*** linux.orig/kernel/blk_drv/blk.h	Fri Jul 17 08:56:46 1992
--- linux/kernel/blk_drv/blk.h	Fri Jul 17 09:35:32 1992
***************
*** 1,7 ****
  #ifndef _BLK_H
  #define _BLK_H
  
! #define NR_BLK_DEV	10
  /*
   * NR_REQUEST is the number of entries in the request-queue.
   * NOTE that writes may use only the low 2/3 of these: reads
--- 1,7 ----
  #ifndef _BLK_H
  #define _BLK_H
  
! #define NR_BLK_DEV	11
  /*
   * NR_REQUEST is the number of entries in the request-queue.
   * NOTE that writes may use only the low 2/3 of these: reads
diff -cr +new-files linux.orig/kernel/blk_drv/ll_rw_blk.c linux/kernel/blk_drv/ll_rw_blk.c
*** linux.orig/kernel/blk_drv/ll_rw_blk.c	Fri Jul 17 08:56:45 1992
--- linux/kernel/blk_drv/ll_rw_blk.c	Fri Jul 17 09:35:32 1992
***************
*** 42,48 ****
  	{ NULL, NULL },		/* dev lp */
  	{ NULL, NULL },		/* dev pipes */
  	{ NULL, NULL },		/* dev sd */
! 	{ NULL, NULL }		/* dev st */
  };
  
  /*
--- 42,49 ----
  	{ NULL, NULL },		/* dev lp */
  	{ NULL, NULL },		/* dev pipes */
  	{ NULL, NULL },		/* dev sd */
! 	{ NULL, NULL },		/* dev st */
! 	{ NULL, NULL }		/* dev loop */
  };
  
  /*
-- 
   _________________________________________________________________________
  / Werner Almesberger, ETH Zuerich, CH      almesber@nessie.cs.id.ethz.ch /
 / IFW A44  Tel. +41 1 254 7213                 almesberger@rzvax.ethz.ch /
/_BITNET:_ALMESBER@CZHETH5A__HEPNET/CHADNET:_[20579::]57414::ALMESBERGER_/
Newsgroups: comp.os.linux