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

[PATCH] cloop: Add suspend feature



Hi,

the please find attached a patch, which implements the "suspend" feature.

It allows clean ejecting of the CD Knoppix is running on.

This enables the user to, for example, burn a CD, then put the Knoppix CD back in and continue using the whole CD.

Ok, enough easy speak lets get to the technical details. It works as follows:

# Make sure that everything you now need is cached by the kernel block layer
# It doesn't hurt it its not the case, as long as losetup, glibc and mount are available.
# Copy them to ram disk / unionfs?

cat /usr/bin/losetup /bin/mount /bin/ash >/dev/null

I think I had a minimal losetup assembly version somewhere for those purposes, but I don't remember ...

# /bin/ash # start a ash?
cloop_suspend /dev/cloop
umount /cdrom

# Put in other CD and do what you want to do

# Put in original CD again
mount /cdrom
# Resume cloop
losetup /dev/cloop /cdrom/KNOPPIX/KNOPPIX

# Now all blocked requests will be satisfied again and it all works again as before the suspend

If you do a:

cloop_suspend
cat /KNOPPIX/file_not_in_cache

the cat will simply sleep until the cloop is resumed.

I know that users already use this very carefully with umount -l, but that is a hacky solution, where data requested gets marked as 'bad blocks' while here it simply works again after resume.

There is just one small problem:

What if the Xserver or any other critical part blocks, because it is no longer in the kernel block cache ...

Well, I guess than you are really locked out unless we start a recovery console on tty1, which has all data copied to ram disk.

There should be always _some_ way out for the user.

Well that is a detail.

Ideas? Comments?

I still think the general functionality is useful.

cu

Fabian
--- compressed_loop.c.old	2007-02-02 03:41:36.000000000 +0100
+++ compressed_loop.c	2007-02-02 05:02:27.000000000 +0100
@@ -347,7 +347,7 @@
  cloop = &cloop_dev[cloop_num];
 #endif
 
- if (!cloop->backing_file)
+ if (!cloop->backing_file && !cloop->suspended)
   {
    DEBUGP("do_clo_request: not connected to a file\n");
    goto out;
@@ -464,6 +464,10 @@
 		   (unsigned)sizeof(struct cloop_head));
    error=-EBADF; goto error_release;
   }
+ 
+ /* In suspended mode, we have done all checks necessary - FF */
+ if (clo->suspended)
+   return error;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
  if(isblkdev)
@@ -679,6 +683,26 @@
  return 0;
 }
 
+static int clo_suspend_fd(int cloop_num)
+{
+ struct cloop_device *clo = &cloop_dev[cloop_num];
+ struct file *filp = clo->backing_file;
+
+ if(filp==NULL) return -EINVAL;
+ if (clo->suspended) return -EINVAL;
+ 
+ /* Suspend all running requests - FF */
+ clo->suspended=1;
+ down(&clo->clo_lock);
+
+ if(filp!=initial_file) fput(filp);
+ else { filp_close(initial_file,0); initial_file=NULL; }
+ clo->backing_file  = NULL;
+ clo->backing_inode = NULL;
+ memset(clo->backing_file_name, 0, LO_NAME_SIZE);
+ return 0;
+}
+
 static int clo_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
@@ -702,6 +726,12 @@
 #else
 	 err = clo_set_fd(cloop_num, file, inode->i_bdev, arg);
 #endif
+	 if (err == 0 && clo->suspended)
+	 {
+		/* Okay, we have again a backing file - get reqs again - FF */
+		clo->suspended=0;
+		up(&clo->clo_lock);
+	 }
 	 break;
 	case LOOP_CLR_FD:
 	 err = clo_clr_fd(cloop_num, inode->i_bdev);
@@ -737,6 +767,9 @@
 	  } else
 	    err = -ENXIO;
 	  break;
+	case CLOOP_SUSPEND:
+	  err = clo_suspend_fd(cloop_num);
+	  break;
 	default:
 	 err = -EINVAL;
 	}
--- compressed_loop.h.old	2007-02-02 03:43:54.000000000 +0100
+++ compressed_loop.h	2007-02-02 04:45:26.000000000 +0100
@@ -20,4 +20,6 @@
 /* data_index (num_blocks 64bit pointers, network order)...      */
 /* compressed data (gzip block compressed format)...             */
 
+#define CLOOP_SUSPEND LOOP_GET_STATUS+1
+
 #endif /*_COMPRESSED_LOOP_H*/
--- Makefile.old	2007-02-02 05:06:34.000000000 +0100
+++ Makefile	2007-02-02 05:07:13.000000000 +0100
@@ -64,6 +64,9 @@
 extract_compressed_fs: extract_compressed_fs.o
 	$(CC) -o $@ $< -lz
 
+cloop_suspend: cloop_suspend.o
+	$(CC) -o $@ $<
+
 clean:
 	rm -f $(KERNOBJ) create_compressed_fs extract_compressed_fs zoom *.o *.ko
 	$(MAKE) -C advancecomp-1.9_create_compressed_fs distclean
--- /dev/null	2004-05-02 02:57:33.000000000 +0200
+++ cloop_suspend.c	2007-02-02 05:12:32.000000000 +0100
@@ -0,0 +1,47 @@
+/* 
+ * cloop_suspend - Suspend a cloop device until losetup /dev/cloop <file> is 
+ *                 run again.
+ * 
+ * Copyright (c) 2007 by Fabian Franz.
+ *
+ * License: GPL, v2.
+ * 
+ */
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+/* We don't use the structure, so that define does not hurt */
+#define dev_t int
+#include <linux/loop.h>
+#include "compressed_loop.h"
+
+int main(int argc, char** argv)
+{
+	if (argc < 2)
+	{
+		fprintf(stderr, "syntax: cloop_suspend <device>\n");
+		return 1;
+	}
+	int fd = open(argv[1], O_RDONLY);
+
+	if (fd < 0)
+	{
+		perror(argv[1]);
+		return 1;
+	}
+
+	if (ioctl(fd, CLOOP_SUSPEND) < 0)
+	{
+		perror("ioctl: CLOOP_SUSPEND");
+		return 1;
+	}
+
+	close(fd);
+
+	return 0;
+}

Reply to: