Bug 61909

Summary: 5.2-Current fails to notice change of CD in drive
Product: Base System Reporter: Artem 'Zazoobr' Ignatjev <timon>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 5.2-CURRENT   
Hardware: Any   
OS: Any   

Description Artem 'Zazoobr' Ignatjev 2004-01-25 22:20:15 UTC
	When CD is changed in drive (or removed from it), kernel still maintains
	data from its TOC, like tracklist or CD ID. That confuses programs, i.e
	dagrab requests CDDB for previous CD in drive, and therefore gets wrong
	tracklist.
	Also stale files /dev/acdXtNN are kept in /dev
	
	One must force kernel to renew TOC, for example issuing a `cdcontrol 1'
	command.

Fix: 

Workaround: start playing from new cd (or mount it). After that you can do
	what you wanted to do.
How-To-Repeat: 	Insert some audio cd in drive
	Read it contents (use dagrab -CN to extract some audiotracks)
	Remove cd from drive.
	ls /dev/acd?t* ; cdcontrol info 
	- and see info about the cd you're holding in hands
Comment 1 Dorr H. Clark 2004-04-15 18:48:57 UTC
Proposed fix:

--- /usr/ports/audio/dagrab/work/dagrab-0.3.5/dagrab.c  Wed Mar  3
21:50:08 2004
+++ dagrab.c    Tue Mar 16 15:09:04 2004
@@ -243,6 +243,38 @@
   return ioctl(cdrom_fd,CDIOREADTOCENTRY,Te);
 }
 
+int force_read_check(struct cd_trk_list *tl)
+{
+  int num = opt_blocks;
+  int lba = tl->min;
+  int buf[opt_ibufsize];
+  int *p = buf;
+
+#if defined (__FreeBSD__) &&  (__FreeBSD_version >= 501106)
+        int bsize = CD_FRAMESIZE_RAW;
+        if(ioctl(cdrom_fd,CDRIOCSETBLOCKSIZE,&bsize) == -1) {
+                fprintf(stderr, "setblocksize");
+                return -1;
+        }
+
+        if (pread(cdrom_fd, (char *)p, num*bsize, lba*bsize) !=
num*bsize){
+               printf("Could not read media\n");
+#else
+        struct ioc_read_audio ra;
+
+        ra.address.lba=lba;
+        ra.address_format=CD_LBA_FORMAT;
+        ra.nframes=num;
+        ra.buffer=buf;
+        if(ioctl(cdrom_fd,CDIOCREADAUDIO,&ra)){
+               fprintf(stderr, "Could not read media\n");
+#endif
+               return -1;
+       }
+
+return 1;
+}
+
 void cd_read_audio(int lba,int num,char *buf)
        /* reads num CD_FRAMESIZE_RAW sized
           sectors in buf, starting from lba*/
@@ -251,7 +283,7 @@
 {
 /* CDIOCREADAUDIO has been removed in FreeBSD 5.1-CURRENT */
 #if defined (__FreeBSD__) &&  (__FreeBSD_version >= 501106)
-       int bsize = 2352;
+       int bsize = CD_FRAMESIZE_RAW;
         if(ioctl(cdrom_fd,CDRIOCSETBLOCKSIZE,&bsize) == -1) {
                fprintf(stderr, "setblocksize");
                exit(1);
@@ -699,6 +730,12 @@
        }
        tl->starts[tl->max-tl->min+1]=ntohl(Te.entry.addr.lba);
        tl->types[tl->max-tl->min+1]=Te.entry.control&CDROM_DATA_TRACK;
+
+        if(force_read_check(tl) == -1) {
+                fprintf(stderr,"%s: error reading from device
%s\n",progname,cd
_dev);
+                exit(1);
+        }
+
        
         i=cddb_main(tl);
        if(i==-1) {

{  NOTE: this patch presumes the FreeBSD patch has already been applied,
it does not directly apply to the original dagrab-0.3.5/dagrab.c  }

Problem Definition:

        The bug report describes the problem being that when a cd is
removed 
from the cdrom drive, the cd track information still exists until
another disk 
is entered into the drive.  This can confuse programs, such as dagrab, 
because some operations only look at the track information and will 
incorrectly report information about the contents of the cd drive.

Problem Analysis:

        The program dagrab was written for linux and ported to FreeBSD.  
Although the two operating systems are very similar with respect 
to cdrom I/O, there are some subtle differences between the two.  
FreeBSD only updates cd track information when a new cd is entered 
in the drive, an ioctl() call to obtain track information with no cd 
will return the contents of the file system cache.  In particular, when 
the cd is removed, the track listings /dev/acd0?t* remain intact 
and will not be replaced until a new cd is entered into the drive.  

        Linux also caches the cd track information, but only for as long 
as the cd is actually in the drive.  Once the cd is removed, any call 
to ioctl() will result in an IO failure unless a new cd has been
entered.

        Based on the FreeBSD philosophy that the file system should
cache 
this information, this bug has been improperly filed against the kernel
and should be moved to the ports section.

Solution:

        The only method I have found to determine if the cd is actually 
in the drive without getting a ghost image from the filesystem cache is 
to invoke a read operation on the cdrom drive.  Other types of access 
will return a result with an undetermined origin as they can be
satisfied
by the cache.  Similar programs, such as cdparanoia, also catch this 
condition (although based on their implementation, it may be
coincidence) 
by the same method of invoking a read operation on the cd.  The problem 
with this strategy of defeating the normal filesystem cache behavior 
is that it invalidates the cache performance gain because an actual 
read operation is a very slow operation.  However, by reading a small 
section of the disk as opposed to the whole table of contents this
minimizes the performance degradation.

Daniel Weeks, engineer
Dorr H. Clark, advisor
Graduate School of Engineering
Santa Clara University
Comment 2 Jaakko Heinonen freebsd_committer freebsd_triage 2011-02-20 18:53:49 UTC
State Changed
From-To: open->closed

Duplicate of kern/85975.