--- linux/drivers/scsi/sg.c.or Sun Apr 26 07:15:22 1998 +++ linux/drivers/scsi/sg.c Fri Jul 31 08:29:06 1998 @@ -5,6 +5,14 @@ * Development Sponsored by Killy Corp. NY NY * * Borrows code from st driver. + * + * Heiko Eißfeldt, 08.01.1998 + * Changed buffer allocation to a lazy kmalloc scheme in order to allow + * multiple requests in parallel on different devices. For example reading + * from a cdrom and writing on a cd burner. + * + * NOTE: SG_BIG_BUFF is kept for compatibility, but has no effect anymore. + * The corresponding sysctl entry is gone. */ #include @@ -28,8 +36,6 @@ #include #include -int sg_big_buff = SG_BIG_BUFF; /* for now, sg_big_buff is read-only through sysctl */ - static int sg_init(void); static int sg_attach(Scsi_Device *); static int sg_detect(Scsi_Device *); @@ -41,12 +47,6 @@ sg_detect, sg_init, NULL, sg_attach, sg_detach}; -#ifdef SG_BIG_BUFF -static char *big_buff = NULL; -static struct wait_queue *big_wait; /* wait for buffer available */ -static int big_inuse=0; -#endif - struct scsi_generic { Scsi_Device *device; @@ -64,7 +64,6 @@ }; static struct scsi_generic *scsi_generics=NULL; -static void sg_free(char *buff,int size); static int sg_ioctl(struct inode * inode,struct file * file, unsigned int cmd_in, unsigned long arg) @@ -109,6 +108,47 @@ } } +static char *sg_lazy_malloc(int bsize, int *buff_len, + const struct scsi_generic *s_dev) +{ + void * retval; + int chunksize; + + /* if we have enough space in last buffer, recycle buffer */ + if (s_dev->buff != NULL && *buff_len >= bsize) + return s_dev->buff; + + /* we don't have enough space. Forget the old buffer, + then get a bigger one */ + if (s_dev->buff != NULL) + kfree(s_dev->buff); + + /* quantify block size: 32K or 64K or 128K or more, if possible */ + if (bsize <= 32 * 1024) { + chunksize = 32 * 1024; + } else if (bsize <= 64 * 1024) { + chunksize = 64 * 1024; + } else if (bsize <= 128 * 1024) { + chunksize = 128 * 1024; + } else { + /* for future extensions */ + chunksize = bsize; + } + + /* alloc a new block */ + retval = kmalloc(chunksize, GFP_KERNEL | GFP_DMA); + + /* if the kmalloc failed, let the size be zero */ + if (retval == NULL) { + chunksize = 0; + } + + /* register size of allocated block */ + *buff_len = chunksize; + + return (char *) retval; +} + static int sg_open(struct inode * inode, struct file * filp) { int dev=MINOR(inode->i_rdev); @@ -127,6 +167,9 @@ /* * If we want exclusive access, then wait until the device is not * busy, and then set the flag to prevent anyone else from using it. + * + * FIXME (HE): The device can be used through another driver! + * This goes currently unnoticed. Add a check for this. */ if (flags & O_EXCL) { @@ -164,7 +207,7 @@ && scsi_generics[dev].complete) { if (scsi_generics[dev].buff != NULL) - sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len); + kfree(scsi_generics[dev].buff); scsi_generics[dev].buff=NULL; scsi_generics[dev].pending=0; } @@ -181,6 +224,10 @@ static int sg_close(struct inode * inode, struct file * filp) { int dev=MINOR(inode->i_rdev); + if (scsi_generics[dev].buff != NULL) { + kfree(scsi_generics[dev].buff); + scsi_generics[dev].buff = NULL; + } scsi_generics[dev].users--; if (scsi_generics[dev].device->host->hostt->module) __MOD_DEC_USE_COUNT(scsi_generics[dev].device->host->hostt->module); @@ -191,38 +238,6 @@ return 0; } -static char *sg_malloc(int size) -{ - if (size<=4096) - return (char *) scsi_malloc(size); -#ifdef SG_BIG_BUFF - if (size<=SG_BIG_BUFF) - { - while(big_inuse) - { - interruptible_sleep_on(&big_wait); - if (signal_pending(current)) - return NULL; - } - big_inuse=1; - return big_buff; - } -#endif - return NULL; -} - -static void sg_free(char *buff,int size) -{ -#ifdef SG_BIG_BUFF - if (buff==big_buff) - { - big_inuse=0; - wake_up(&big_wait); - return; - } -#endif - scsi_free(buff,size); -} /* * Read back the results of a previous command. We use the pending and @@ -293,8 +308,6 @@ * Clean up, and release the device so that we can send another * command. */ - sg_free(device->buff,device->buff_len); - device->buff = NULL; device->pending=0; wake_up(&device->write_wait); return count; @@ -466,18 +479,17 @@ /* * Allocate a buffer that is large enough to hold the data - * that has been requested. Round up to an even number of sectors, - * since scsi_malloc allocates in chunks of 512 bytes. + * that has been requested. */ amt=bsize; if (!bsize) bsize++; - bsize=(bsize+511) & ~511; /* * If we cannot allocate the buffer, report an error. */ - if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize))) + if ((bsize<0) + || !(device->buff=sg_lazy_malloc(bsize, &device->buff_len, device))) { device->pending=0; wake_up(&device->write_wait); @@ -496,8 +508,6 @@ { device->pending=0; wake_up(&device->write_wait); - sg_free(device->buff,device->buff_len); - device->buff = NULL; return -EAGAIN; } #ifdef DEBUG @@ -620,10 +630,6 @@ printk("sg: Init generic device.\n"); #endif -#ifdef SG_BIG_BUFF - big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA); -#endif - scsi_generics = (struct scsi_generic *) scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS) * sizeof(struct scsi_generic), GFP_ATOMIC); @@ -703,10 +709,6 @@ * sizeof(struct scsi_generic)); } sg_template.dev_max = 0; -#ifdef SG_BIG_BUFF - if(big_buff != NULL) - scsi_init_free(big_buff, SG_BIG_BUFF); -#endif } #endif /* MODULE */ --- linux/kernel/sysctl.c.or Tue Jul 21 01:22:09 1998 +++ linux/kernel/sysctl.c Wed Jul 29 09:59:06 1998 @@ -44,9 +44,6 @@ #ifdef CONFIG_KMOD extern char modprobe_path[]; #endif -#ifdef CONFIG_CHR_DEV_SG -extern int sg_big_buff; -#endif #ifdef __sparc__ extern char reboot_command []; @@ -180,10 +177,6 @@ #ifdef CONFIG_KMOD {KERN_MODPROBE, "modprobe", &modprobe_path, 256, 0644, NULL, &proc_dostring, &sysctl_string }, -#endif -#ifdef CONFIG_CHR_DEV_SG - {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int), - 0444, NULL, &proc_dointvec}, #endif {0} };