linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Chih-Chung Chang <b4506055@csie.ntu.edu.tw>
To: linux-kernel@vger.kernel.org
Subject: [PATCH] VCD support for isofs
Date: Tue, 7 Nov 2000 08:25:42 +0800 (CST)	[thread overview]
Message-ID: <Pine.GSO.4.10.10011070822030.6214-300000@ntucsa> (raw)

[-- Attachment #1: Type: TEXT/PLAIN, Size: 78 bytes --]


Attached patches add VCD support in isofs.
Against 2.2.16 and 2.4.0-test10.


[-- Attachment #2: Type: TEXT/PLAIN, Size: 8506 bytes --]

diff -ur isofs.orig/file.c isofs/file.c
--- isofs.orig/file.c	Mon Mar  8 07:25:23 1999
+++ isofs/file.c	Tue Nov  7 08:07:57 2000
@@ -54,3 +54,24 @@
 	NULL,	       		/* truncate */
 	NULL			/* permission */
 };
+
+extern int readpage_form2(struct file *, struct page *);
+struct inode_operations isofs_file_inode_operations_form2 = {
+	&isofs_file_operations,	/* default file operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	readpage_form2,		/* readpage */
+	NULL,			/* writepage */
+	isofs_bmap,		/* bmap */
+	NULL,	       		/* truncate */
+	NULL			/* permission */
+};
diff -ur isofs.orig/inode.c isofs/inode.c
--- isofs.orig/inode.c	Wed Aug 23 03:24:10 2000
+++ isofs/inode.c	Tue Nov  7 08:08:02 2000
@@ -1085,6 +1085,231 @@
 	goto out;
 }
 
+int cd_ioctl(struct super_block *s, int request, unsigned long arg)
+{
+	extern struct file_operations * get_blkfops(unsigned int);
+	kdev_t dev = s->s_dev;
+	struct file_operations *fops = get_blkfops(MAJOR(dev));
+	int ret = -1;
+	if(fops && fops->ioctl)
+	{
+		struct inode inode_fake;
+		mm_segment_t old_fs=get_fs();
+		set_fs(KERNEL_DS);
+		inode_fake.i_rdev=dev;
+		ret = fops->ioctl(&inode_fake,NULL,request,arg);
+		set_fs(old_fs);
+	}
+	return ret;
+}
+
+static char *last_buf;
+unsigned char* cd_read_raw_sector(struct inode *inode, int sector_nr)
+{
+	static struct semaphore last_buf_sem = MUTEX;
+	static struct inode* last_inode;
+	static int last_sector_nr = -1;
+	unsigned char *buf;
+	struct cdrom_msf *msf;
+	int lba;
+
+	buf = kmalloc(CD_FRAMESIZE_RAW,GFP_KERNEL);
+	if(buf == NULL) return NULL;
+
+	down(&last_buf_sem);
+
+	if(sector_nr == last_sector_nr && inode == last_inode)
+	// how to do the right check/invalidate?
+	{
+		memcpy(buf,last_buf,CD_FRAMESIZE_RAW);
+		goto out;
+	}
+
+	lba = isofs_bmap(inode,0) + 150 + sector_nr;
+	msf = (struct cdrom_msf *)buf;
+	msf->cdmsf_min0 = lba/75/60;
+	msf->cdmsf_sec0 = (lba/75)%60;
+	msf->cdmsf_frame0 = lba%75;
+	if(cd_ioctl(inode->i_sb,CDROMREADRAW,(unsigned long)msf) < 0)
+	{
+		kfree(buf);
+		buf = NULL;
+	}
+	else
+	{
+		last_inode = inode;
+		last_sector_nr = sector_nr;
+		memcpy(last_buf,buf,CD_FRAMESIZE_RAW);
+	}
+out:
+	up(&last_buf_sem);
+	return buf;
+}
+
+#define FORM2_DATA_SIZE 2324
+static int kisofsd_pid;
+static int kisofsd_running = 0;
+static spinlock_t kisofsd_req_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(kisofsd_req_list);	/* List of requests needing servicing */
+static struct wait_queue *kisofsd_wait;
+
+struct kisofsd_req {
+	struct list_head req_list;
+	struct inode *inode;
+	struct page *page;
+};
+
+static int kisofsd_add_request(struct inode* inode, struct page *page)
+{
+	struct kisofsd_req *req = kmalloc(sizeof(struct kisofsd_req),
+						GFP_KERNEL);
+	if(req == NULL) return -ENOMEM;
+
+	set_bit(PG_locked, &page->flags);
+	clear_bit(PG_uptodate, &page->flags);
+	clear_bit(PG_error, &page->flags);
+
+	INIT_LIST_HEAD(&req->req_list);
+	req->inode = inode;
+	req->page = page;
+
+	spin_lock(&kisofsd_req_lock);
+	list_add(&req->req_list,kisofsd_req_list.prev);
+	wake_up(&kisofsd_wait);
+	spin_unlock(&kisofsd_req_lock);
+
+	return 0;
+}
+
+static void readpage_form2_real(struct inode* inode, struct page* page)
+{
+	char *buf = (char *)page_address(page);
+	int start_sector, start_byte;
+	int stop_sector, stop_byte;
+	int sector;
+	int offset = page->offset;
+	
+	// the code is adapted from cdXA.c of cdfs-0.41
+
+	start_sector = offset / FORM2_DATA_SIZE;
+	start_byte = offset % FORM2_DATA_SIZE;
+	stop_sector = (offset + PAGE_SIZE) / FORM2_DATA_SIZE;
+	stop_byte = (offset + PAGE_SIZE) % FORM2_DATA_SIZE;
+	
+	if(stop_byte == 0)
+	{
+		--stop_sector;
+		stop_byte = FORM2_DATA_SIZE;
+	}
+
+	for(sector = start_sector; sector <= stop_sector; sector++)
+	{
+		int copy_length;
+		unsigned char *data;
+		unsigned char *raw_sector = cd_read_raw_sector(inode,sector);
+		if(raw_sector == NULL) break;
+
+		data = raw_sector + 24;
+		if(sector == start_sector)
+		{
+			data += start_byte;
+			if(sector != stop_sector)
+				copy_length = FORM2_DATA_SIZE - start_byte;
+			else
+				copy_length = stop_byte - start_byte;
+		} 
+		else if (sector == stop_sector)
+			copy_length = stop_byte;
+		else
+			copy_length = FORM2_DATA_SIZE;
+		
+		memcpy(buf,data,copy_length);
+		buf += copy_length;
+		kfree(raw_sector);
+	}
+
+	if(sector > stop_sector)
+		set_bit(PG_uptodate, &page->flags);
+	else
+		set_bit(PG_error, &page->flags);
+	clear_bit(PG_locked, &page->flags);
+	wake_up(&page->wait);
+}
+
+static void kisofsd_process_request(void)
+{
+	spin_lock(&kisofsd_req_lock);
+	while(!list_empty(&kisofsd_req_list))
+	{
+		struct list_head * tmp;
+		struct kisofsd_req * req;
+		
+		tmp = kisofsd_req_list.next;
+		list_del(tmp);
+
+		spin_unlock(&kisofsd_req_lock);
+		req = list_entry(tmp, struct kisofsd_req, req_list);
+		readpage_form2_real(req->inode, req->page);
+		kfree(req);
+		spin_lock(&kisofsd_req_lock);
+	}
+	spin_unlock(&kisofsd_req_lock);
+}
+
+static void daemonize(void)
+{
+	struct fs_struct *fs;
+
+	/*
+	 * If we were started as result of loading a module, close all of the
+	 * user space pages.  We don't need them, and if we didn't close them
+	 * they would be locked into memory.
+	 */
+	exit_mm(current);
+
+	current->session = 1;
+	current->pgrp = 1;
+
+	/* Become as one with the init task */
+
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
+
+}
+
+static int kisofsd_thread(void *unused)
+{
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources
+	 */
+	exit_files(current);  /* daemonize doesn't do exit_files */
+	daemonize();
+
+	/* Setup a nice name */
+	strcpy(current->comm, "kisofsd");
+
+	/* Send me a signal to get me die (for debugging) */
+	do {
+		kisofsd_process_request();
+		wait_event_interruptible(kisofsd_wait,!list_empty(&kisofsd_req_list));
+	} while (!signal_pending(current));
+
+	kisofsd_running = 0;
+	return 0;
+}
+
+int readpage_form2(struct file *file, struct page *page)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	if(kisofsd_running)
+		return kisofsd_add_request(inode, page);
+	else
+		return -EIO;
+}
+
 void isofs_read_inode(struct inode * inode)
 {
 	struct super_block *sb = inode->i_sb;
@@ -1233,7 +1458,22 @@
 #endif IGNORE_WRONG_MULTI_VOLUME_SPECS
 	{
 	  if (S_ISREG(inode->i_mode))
+	  {
+	    extern struct inode_operations isofs_file_inode_operations_form2;
+	    unsigned char *buf;
 	    inode->i_op = &isofs_file_inode_operations;
+	    buf = cd_read_raw_sector(inode,0);
+	    if(buf)
+	    {
+		    if(buf[15] == 2 && (buf[18]&(1<<5)))
+		    {
+			inode->i_op = &isofs_file_inode_operations_form2;
+			inode->i_size = (inode->i_size/2048)*FORM2_DATA_SIZE+
+					(inode->i_size%2048);
+		    }
+		    kfree(buf);
+	    }
+	  }
 	  else if (S_ISDIR(inode->i_mode))
 	    inode->i_op = &isofs_dir_inode_operations;
 	  else if (S_ISLNK(inode->i_mode))
@@ -1436,7 +1676,24 @@
 
 __initfunc(int init_iso9660_fs(void))
 {
-        return register_filesystem(&iso9660_fs_type);
+	int err;
+        err = register_filesystem(&iso9660_fs_type);
+        if(err < 0) return err;
+
+	last_buf = kmalloc(CD_FRAMESIZE_RAW,GFP_KERNEL);
+	if(last_buf == NULL) return -ENOMEM;
+
+	kisofsd_pid = kernel_thread(kisofsd_thread, NULL, 
+			CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if(kisofsd_pid > 0) 
+	{
+		kisofsd_running = 1;
+		return 0;
+	}
+
+	printk("init_iso9660_fs: kernel_thread failed.\n");
+	unregister_filesystem(&iso9660_fs_type);
+	return -1;
 }
 
 #ifdef MODULE
@@ -1449,7 +1706,21 @@
 
 void cleanup_module(void)
 {
+	int ret;
+	ret = kill_proc(kisofsd_pid, SIGTERM, 1);
+	if(!ret) {
+		/* Wait 10 seconds */
+		int count = 10 * 100;
+		while (kisofsd_running && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+
+		if(!count)
+			printk("Giving up on killing kisofsd !");
+	}
 	unregister_filesystem(&iso9660_fs_type);
+	kfree(last_buf);
 }
 
 #endif

[-- Attachment #3: Type: TEXT/PLAIN, Size: 7195 bytes --]

diff -ur isofs.orig/inode.c isofs/inode.c
--- isofs.orig/inode.c	Thu Oct 19 16:48:42 2000
+++ isofs/inode.c	Tue Nov  7 08:06:22 2000
@@ -985,6 +985,12 @@
 	sync_page: block_sync_page,
 	bmap: _isofs_bmap
 };
+int readpage_form2(struct file *file, struct page *page);
+static struct address_space_operations isofs_aops_form2 = {
+	readpage: readpage_form2,
+	sync_page: block_sync_page,
+	bmap: _isofs_bmap
+};
 
 static inline void test_and_set_uid(uid_t *p, uid_t value)
 {
@@ -1092,6 +1098,196 @@
 	goto out;
 }
 
+int cd_ioctl(struct super_block *s, int request, unsigned long arg)
+{
+	return ioctl_by_bdev(s->s_bdev,request,arg);
+}
+
+static char *last_buf;
+unsigned char* cd_read_raw_sector(struct inode *inode, int sector_nr)
+{
+	static DECLARE_MUTEX(last_buf_sem);
+	static struct inode* last_inode;
+	static int last_sector_nr = -1;
+	unsigned char *buf;
+	struct cdrom_msf *msf;
+	int lba;
+
+	buf = kmalloc(CD_FRAMESIZE_RAW,GFP_KERNEL);
+	if(buf == NULL) return NULL;
+
+	down(&last_buf_sem);
+
+	if(sector_nr == last_sector_nr && inode == last_inode)
+	// how to do the right check/invalidate?
+	{
+		memcpy(buf,last_buf,CD_FRAMESIZE_RAW);
+		goto out;
+	}
+
+	lba = isofs_bmap(inode,0) + 150 + sector_nr;
+	msf = (struct cdrom_msf *)buf;
+	msf->cdmsf_min0 = lba/75/60;
+	msf->cdmsf_sec0 = (lba/75)%60;
+	msf->cdmsf_frame0 = lba%75;
+	if(cd_ioctl(inode->i_sb,CDROMREADRAW,(unsigned long)msf) < 0)
+	{
+		kfree(buf);
+		buf = NULL;
+	}
+	else
+	{
+		last_inode = inode;
+		last_sector_nr = sector_nr;
+		memcpy(last_buf,buf,CD_FRAMESIZE_RAW);
+	}
+out:
+	up(&last_buf_sem);
+	return buf;
+}
+
+#define FORM2_DATA_SIZE 2324
+static int kisofsd_pid;
+static int kisofsd_running = 0;
+static spinlock_t kisofsd_req_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(kisofsd_req_list);	/* List of requests needing servicing */
+static DECLARE_WAIT_QUEUE_HEAD(kisofsd_wait);
+
+struct kisofsd_req {
+	struct list_head req_list;
+	struct inode *inode;
+	struct page *page;
+};
+
+static int kisofsd_add_request(struct inode* inode, struct page *page)
+{
+	struct kisofsd_req *req = kmalloc(sizeof(struct kisofsd_req),
+						GFP_KERNEL);
+	if(req == NULL) return -ENOMEM;
+
+	if (!PageLocked(page))
+		PAGE_BUG(page);
+	clear_bit(PG_uptodate, &page->flags);
+	clear_bit(PG_error, &page->flags);
+
+	INIT_LIST_HEAD(&req->req_list);
+	req->inode = inode;
+	req->page = page;
+
+	spin_lock(&kisofsd_req_lock);
+	list_add(&req->req_list,kisofsd_req_list.prev);
+	wake_up(&kisofsd_wait);
+	spin_unlock(&kisofsd_req_lock);
+
+	return 0;
+}
+
+static void readpage_form2_real(struct inode* inode, struct page* page)
+{
+	char *buf = (char *)page_address(page);
+	int start_sector, start_byte;
+	int stop_sector, stop_byte;
+	int sector;
+	int offset = page->index << PAGE_CACHE_SHIFT;;
+	
+	// the code is adapted from cdXA.c of cdfs-0.41
+
+	start_sector = offset / FORM2_DATA_SIZE;
+	start_byte = offset % FORM2_DATA_SIZE;
+	stop_sector = (offset + PAGE_SIZE) / FORM2_DATA_SIZE;
+	stop_byte = (offset + PAGE_SIZE) % FORM2_DATA_SIZE;
+	
+	if(stop_byte == 0)
+	{
+		--stop_sector;
+		stop_byte = FORM2_DATA_SIZE;
+	}
+
+	for(sector = start_sector; sector <= stop_sector; sector++)
+	{
+		int copy_length;
+		unsigned char *data;
+		unsigned char *raw_sector = cd_read_raw_sector(inode,sector);
+		if(raw_sector == NULL) break;
+
+		data = raw_sector + 24;
+		if(sector == start_sector)
+		{
+			data += start_byte;
+			if(sector != stop_sector)
+				copy_length = FORM2_DATA_SIZE - start_byte;
+			else
+				copy_length = stop_byte - start_byte;
+		} 
+		else if (sector == stop_sector)
+			copy_length = stop_byte;
+		else
+			copy_length = FORM2_DATA_SIZE;
+		
+		memcpy(buf,data,copy_length);
+		buf += copy_length;
+		kfree(raw_sector);
+	}
+
+	if(sector > stop_sector)
+		set_bit(PG_uptodate, &page->flags);
+	else
+		set_bit(PG_error, &page->flags);
+	clear_bit(PG_locked, &page->flags);
+	wake_up(&page->wait);
+}
+
+static void kisofsd_process_request(void)
+{
+	spin_lock(&kisofsd_req_lock);
+	while(!list_empty(&kisofsd_req_list))
+	{
+		struct list_head * tmp;
+		struct kisofsd_req * req;
+		
+		tmp = kisofsd_req_list.next;
+		list_del(tmp);
+
+		spin_unlock(&kisofsd_req_lock);
+		req = list_entry(tmp, struct kisofsd_req, req_list);
+		readpage_form2_real(req->inode, req->page);
+		kfree(req);
+		spin_lock(&kisofsd_req_lock);
+	}
+	spin_unlock(&kisofsd_req_lock);
+}
+
+static int kisofsd_thread(void *unused)
+{
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources
+	 */
+	exit_files(current);  /* daemonize doesn't do exit_files */
+	daemonize();
+
+	/* Setup a nice name */
+	strcpy(current->comm, "kisofsd");
+
+	/* Send me a signal to get me die (for debugging) */
+	do {
+		kisofsd_process_request();
+		wait_event_interruptible(kisofsd_wait,!list_empty(&kisofsd_req_list));
+	} while (!signal_pending(current));
+
+	kisofsd_running = 0;
+	return 0;
+}
+
+int readpage_form2(struct file *file, struct page *page)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	if(kisofsd_running)
+		return kisofsd_add_request(inode, page);
+	else
+		return -EIO;
+}
+
 static void isofs_read_inode(struct inode * inode)
 {
 	struct super_block *sb = inode->i_sb;
@@ -1239,8 +1435,20 @@
 #endif IGNORE_WRONG_MULTI_VOLUME_SPECS
 	{
 	  if (S_ISREG(inode->i_mode)) {
+	    unsigned char *buf;
 	    inode->i_fop = &generic_ro_fops;
 	    inode->i_data.a_ops = &isofs_aops;
+	    buf = cd_read_raw_sector(inode,0);
+	    if(buf)
+	    {
+		    if(buf[15] == 2 && (buf[18]&(1<<5)))
+		    {
+			inode->i_data.a_ops = &isofs_aops_form2;
+			inode->i_size = (inode->i_size/2048)*FORM2_DATA_SIZE+
+					(inode->i_size%2048);
+		    }
+		    kfree(buf);
+	    }
 	  } else if (S_ISDIR(inode->i_mode)) {
 	    inode->i_op = &isofs_dir_inode_operations;
 	    inode->i_fop = &isofs_dir_operations;
@@ -1430,12 +1638,43 @@
 
 static int __init init_iso9660_fs(void)
 {
-        return register_filesystem(&iso9660_fs_type);
+	int err;
+        err = register_filesystem(&iso9660_fs_type);
+        if(err < 0) return err;
+
+	last_buf = kmalloc(CD_FRAMESIZE_RAW,GFP_KERNEL);
+	if(last_buf == NULL) return -ENOMEM;
+
+	kisofsd_pid = kernel_thread(kisofsd_thread, NULL, 
+			CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if(kisofsd_pid > 0) 
+	{
+		kisofsd_running = 1;
+		return 0;
+	}
+
+	printk("init_iso9660_fs: kernel_thread failed.\n");
+	unregister_filesystem(&iso9660_fs_type);
+	return -1;
 }
 
 static void __exit exit_iso9660_fs(void)
 {
-        unregister_filesystem(&iso9660_fs_type);
+	int ret;
+	ret = kill_proc(kisofsd_pid, SIGTERM, 1);
+	if(!ret) {
+		/* Wait 10 seconds */
+		int count = 10 * 100;
+		while (kisofsd_running && --count) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+
+		if(!count)
+			printk("Giving up on killing kisofsd !");
+	}
+	unregister_filesystem(&iso9660_fs_type);
+	kfree(last_buf);
 }
 
 EXPORT_NO_SYMBOLS;

                 reply	other threads:[~2000-11-07  0:26 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.GSO.4.10.10011070822030.6214-300000@ntucsa \
    --to=b4506055@csie.ntu.edu.tw \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).