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