From 886b8d1f81a0fee7a1c82f6d74c98b5ffcf3a0cd Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Wed, 27 Sep 2006 11:57:28 +0000 Subject: [PATCH] Disabled but did not discarded failed attempt to lock against growisofs --- cdrskin/cdrskin.c | 2 +- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 15 ++- libburn/libdax_msgs.h | 5 +- libburn/sg.c | 259 ++++++++++++++++++++++++++++++++---- libburn/sg.h | 7 + 6 files changed, 261 insertions(+), 29 deletions(-) diff --git a/cdrskin/cdrskin.c b/cdrskin/cdrskin.c index 6b0ecc1..28b4a81 100644 --- a/cdrskin/cdrskin.c +++ b/cdrskin/cdrskin.c @@ -1359,7 +1359,7 @@ int Cdrpreskin_queue_msgs(struct CdrpreskiN *o, int flag) if(o->verbosity>=Cdrskin_verbose_debuG) Cdrpreskin_set_severities(o,"DEBUG","NEVER",0); else - Cdrpreskin_set_severities(o,"NOTE","NEVER",0); + Cdrpreskin_set_severities(o,"SORRY","NEVER",0); queueing= 1; return(1); } diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index fa9f4b2..c2b0f98 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2006.09.27.082057" +#define Cdrskin_timestamP "2006.09.27.115919" diff --git a/libburn/drive.c b/libburn/drive.c index 1a559c2..299b5b9 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -37,7 +37,7 @@ void burn_drive_free(struct burn_drive *d) return; /* ts A60822 : close open fds before forgetting them */ if (burn_drive_is_open(d)) - sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0); + sg_close_drive(d); free((void *) d->idata); free((void *) d->mdata); free((void *) d->toc_entry); @@ -248,6 +248,18 @@ struct burn_drive *burn_drive_register(struct burn_drive *d) } + +/* unregister most recently registered drive */ +int burn_drive_unregister(struct burn_drive *d) +{ + if(d->global_index != drivetop) + return 0; + burn_drive_free(d); + drivetop--; + return 1; +} + + void burn_drive_release(struct burn_drive *d, int le) { if (d->released) @@ -711,7 +723,6 @@ int burn_drive_is_enumerable_adr(char *adr) return sg_is_enumerable_adr(adr); } - /* ts A60922 ticket 33 */ /* Try to find an enumerated address with the given stat.st_rdev number */ int burn_drive_resolve_link(char *path, char adr[]) diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index def4c33..efd10c6 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -292,7 +292,10 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x00020001 (SORRY,LOW) = Cannot open busy device 0x00020002 (SORRY,HIGH) = Encountered error when closing drive 0x00020003 (FATAL,HIGH) = Could not grab drive - + 0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling + 0x00020005 (FATAL,HIGH) = Failed to open device + 0x00020006 (FATAL,HIGH) = Too many scsi siblings + 0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings ------------------------------------------------------------------------------ diff --git a/libburn/sg.c b/libburn/sg.c index 4ee1a79..fcc7f52 100644 --- a/libburn/sg.c +++ b/libburn/sg.c @@ -89,6 +89,28 @@ int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry) } +/* ts A60924 */ +int sg_handle_busy_device(char *fname, int os_errno) +{ + char msg[4096]; + + /* ts A60814 : i saw no way to do this more nicely */ + if (burn_sg_open_abort_busy) { + fprintf(stderr, + "\nlibburn: FATAL : Application triggered abort on busy device '%s'\n", + fname); + assert("drive busy" == "non fatal"); + } + + /* ts A60924 : now reporting to libdax_msgs */ + sprintf(msg, "Cannot open busy device '%s'", fname); + libdax_msgs_submit(libdax_messenger, -1, 0x00020001, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_LOW, + msg, os_errno, 0); + return 1; +} + + /* ts A60922 ticket 33 */ /** Returns the next index number and the next enumerated drive address. @param idx An opaque number handle. Make no own theories about it. @@ -146,33 +168,155 @@ int sg_is_enumerable_adr(char *adr) } -/* ts A60924 */ -int sg_handle_busy_device(char *fname, int os_errno) +/* ts A60926 */ +int sg_release_siblings(int sibling_fds[], int *sibling_count) { - char msg[4096]; + int i; + char msg[81]; - /* ts A60814 : i saw no way to do this more nicely */ - if (burn_sg_open_abort_busy) { - fprintf(stderr, - "\nlibburn: FATAL : Application triggered abort on busy device '%s'\n", - fname); - assert("drive busy" == "non fatal"); + for(i= 0; i < *sibling_count; i++) + sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0); + if(*sibling_count > 0) { + sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count); + libdax_msgs_submit(libdax_messenger, -1, 0x00020007, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0); } - - /* ts A60924 : now reporting to libdax_msgs */ - sprintf(msg, "Cannot open busy device '%s'", fname); - libdax_msgs_submit(libdax_messenger, -1, 0x00020001, - LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_LOW, - msg, os_errno, 0); + *sibling_count = 0; return 1; } + +/* ts A60926 */ +int sg_open_drive_fd(char *fname, int scan_mode) +{ + int open_mode = O_RDWR, fd; + char msg[81]; + + /* ts A60813 + O_EXCL with block devices is an unpublished feature + of Linux kernels. Possibly introduced 2002. + Mentioned in "The Linux SCSI Generic (sg) HOWTO" */ + if(burn_sg_open_o_excl) + open_mode |= O_EXCL; + /* ts A60813 + O_NONBLOCK was already hardcoded in ata_ but not in sg_. + There must be some reason for this. So O_NONBLOCK is + default mode for both now. Disable on own risk. */ + if(burn_sg_open_o_nonblock) + open_mode |= O_NONBLOCK; + +/* <<< debugging + fprintf(stderr, + "\nlibburn: experimental: o_excl= %d , o_nonblock= %d, abort_on_busy= %d\n", + burn_sg_open_o_excl,burn_sg_open_o_nonblock,burn_sg_open_abort_busy); + fprintf(stderr, + "libburn: experimental: O_EXCL= %d , O_NONBLOCK= %d\n", + !!(open_mode&O_EXCL),!!(open_mode&O_NONBLOCK)); +*/ + + fd = open(fname, open_mode); + if (fd == -1) { +/* <<< debugging + fprintf(stderr, + "\nlibburn: experimental: fname= %s , errno= %d\n", + fname,errno); +*/ + if (errno == EBUSY) { + sg_handle_busy_device(fname, errno); + return -1; + + } + if (scan_mode) + return -1; + sprintf(msg, "Failed to open device '%s'",fname); + libdax_msgs_submit(libdax_messenger, -1, 0x00020005, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + msg, errno, 0); + return -1; + } + return fd; +} + + +/* ts A60926 */ +int sg_open_scsi_siblings(char *path, int driveno, + int sibling_fds[], int *sibling_count, + int host_no, int channel_no, int id_no, int lun_no) +{ + int tld, i, ret, fd; + int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1; + char msg[161], fname[81]; + + static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/st%d", ""}; + + if(host_no < 0 || id_no < 0 || channel_no < 0 || lun_no < 0) + return(2); + if(*sibling_count > 0) + sg_release_siblings(sibling_fds, sibling_count); + + for (tld = 0; tldev[tld][0] != 0; tld++) { + for (i = 0; i < 32; i++) { + sprintf(fname, tldev[tld], i); + ret = sg_obtain_scsi_adr(fname, &i_host_no, + &i_channel_no, &i_target_no, &i_lun_no); + if (ret <= 0) + continue; + if (i_host_no != host_no || i_channel_no != channel_no) + continue; + if (i_target_no != id_no || i_lun_no != lun_no) + continue; + + fd = sg_open_drive_fd(fname, 0); + if (fd < 0) + goto failed; + + if (*sibling_count>=LIBBURN_SG_MAX_SIBLINGS) { + sprintf(msg, "Too many scsi siblings of '%s'", + path); + libdax_msgs_submit(libdax_messenger, + driveno, 0x00020006, + LIBDAX_MSGS_SEV_FATAL, + LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0); + goto failed; + } + sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'", + fname, path); + libdax_msgs_submit(libdax_messenger, driveno, + 0x00020004, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, + msg, 0, 0); + sibling_fds[*sibling_count] = fd; + (*sibling_count)++; + } + } + return(1); +failed:; + sg_release_siblings(sibling_fds, sibling_count); + return 0; +} + + +/* ts A60926 */ +int sg_close_drive(struct burn_drive *d) +{ + int ret; + + if (!burn_drive_is_open(d)) + return 0; + sg_release_siblings(d->sibling_fds, &(d->sibling_count)); + ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0); + return ret; +} + void ata_enumerate(void) { struct hd_driveid tm; int i, fd; char fname[10]; + +#ifdef No_sg_open_drive_fD + /* ts A60813 */ int open_mode = O_RDWR; @@ -189,6 +333,9 @@ void ata_enumerate(void) if(burn_sg_open_o_nonblock) open_mode |= O_NONBLOCK; +#endif /* No_sg_open_drive_fD */ + + for (i = 0; i < 26; i++) { sprintf(fname, "/dev/hd%c", 'a' + i); /* open O_RDWR so we don't think read only drives are @@ -197,6 +344,8 @@ void ata_enumerate(void) /* ts A51221 */ if (burn_drive_is_banned(fname)) continue; + +#ifdef No_sg_open_drive_fD fd = open(fname, open_mode); if (fd == -1) { /* <<< debugging @@ -208,6 +357,12 @@ void ata_enumerate(void) sg_handle_busy_device(fname, errno); continue; } +#else + fd = sg_open_drive_fd(fname, 1); + if (fd == -1) + continue; +#endif /* ! No_sg_open_drive_fD */ + /* found a drive */ ioctl(fd, HDIO_GET_IDENTITY, &tm); @@ -232,9 +387,12 @@ void ata_enumerate(void) void sg_enumerate(void) { struct sg_scsi_id sid; - int i, fd; + int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret; char fname[10]; + +#ifdef No_sg_open_drive_fD + /* ts A60813 */ int open_mode = O_RDWR; @@ -261,6 +419,9 @@ void sg_enumerate(void) */ +#endif /* No_sg_open_drive_fD */ + + for (i = 0; i < 32; i++) { sprintf(fname, "/dev/sg%d", i); /* open RDWR so we don't accidentally think read only drives @@ -268,7 +429,10 @@ void sg_enumerate(void) */ /* ts A51221 */ if (burn_drive_is_banned(fname)) - continue; + continue; + +#ifdef No_sg_open_drive_fD + fd = open(fname, open_mode); if (fd == -1) { @@ -279,15 +443,38 @@ void sg_enumerate(void) */ if (errno == EBUSY) sg_handle_busy_device(fname, errno); - continue; + continue; } +#else + + fd = sg_open_drive_fd(fname, 1); + if (fd == -1) + continue; + +#endif /* ! No_sg_open_drive_fD */ + /* found a drive */ ioctl(fd, SG_GET_SCSI_ID, &sid); if (sg_close_drive_fd(fname, -1, &fd, sid.scsi_type == TYPE_ROM ) <= 0) - continue; + continue; if (sid.scsi_type != TYPE_ROM) - continue; + continue; + + /* ts A60927 : trying to do locking with growisofs */ + if(burn_sg_open_o_excl>1) { + ret = sg_open_scsi_siblings( + fname, -1, sibling_fds, &sibling_count, + sid.host_no, sid.channel, + sid.scsi_id, sid.lun); + if (ret<=0) { + sg_handle_busy_device(fname, 0); + continue; + } + /* the final occupation will be done in sg_grab() */ + sg_release_siblings(sibling_fds, &sibling_count); + } + enumerate_common(fname, sid.host_no, sid.channel, sid.scsi_id, sid.lun); } @@ -296,6 +483,7 @@ void sg_enumerate(void) static void enumerate_common(char *fname, int host_no, int channel_no, int target_no, int lun_no) { + int i; struct burn_drive *t; struct burn_drive out; @@ -307,6 +495,9 @@ static void enumerate_common(char *fname, int host_no, int channel_no, out.devname = burn_strdup(fname); out.fd = -1337; + out.sibling_count = 0; + for(i= 0; ireleased = 1; } else { burn_print(2, "unable to grab new located drive\n"); + burn_drive_unregister(t); } /* ts A60821 @@ -373,7 +565,7 @@ static void enumerate_common(char *fname, int host_no, int channel_no, */ int sg_grab(struct burn_drive *d) { - int fd, count, os_errno= 0; + int fd, count, os_errno= 0, ret; /* ts A60813 */ int open_mode = O_RDWR; @@ -409,6 +601,17 @@ int sg_grab(struct burn_drive *d) <<< debug: for tracing calls which might use open drive fds */ mmc_function_spy("sg_grab ----------- opening"); + /* ts A60926 */ + if(burn_sg_open_o_excl>1) { + fd = -1; + ret = sg_open_scsi_siblings(d->devname, + d->global_index,d->sibling_fds, + &(d->sibling_count), + d->host, d->channel, d->id, d->lun); + if(ret <= 0) + goto drive_is_in_use; + } + fd = open(d->devname, open_mode); os_errno = errno; } else @@ -420,19 +623,27 @@ int sg_grab(struct burn_drive *d) /* ts A60814: according to my experiments this test would work now ! */ -/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/ + /* ts A60926 : this was disabled */ + /* Tests with growisofs on kernel 2.4.21 yielded that this + does not help against blocking on busy drives. + */ +/* <<< the old dummy */ +/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/ count = 1; + if (1 == count) { d->fd = fd; fcntl(fd, F_SETOWN, getpid()); d->released = 0; return 1; } + +drive_is_in_use:; libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, "Could not grab drive - already in use", 0, 0); - sg_close_drive_fd(d->devname, d->global_index, &fd, 0); + sg_close_drive(d); d->fd = -1337; return 0; } @@ -462,7 +673,7 @@ int sg_release(struct burn_drive *d) <<< debug: for tracing calls which might use open drive fds */ mmc_function_spy("sg_release ----------- closing"); - sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0); + sg_close_drive(d); return 0; } diff --git a/libburn/sg.h b/libburn/sg.h index 40f19c3..ec92ecf 100644 --- a/libburn/sg.h +++ b/libburn/sg.h @@ -18,6 +18,13 @@ int sg_is_enumerable_adr(char *adr); int sg_obtain_scsi_adr(char *path, int *host_no, int *channel_no, int *target_no, int *lun_no); +/* ts A60926 : ticket 33 ++ */ +int sg_open_scsi_siblings(char *fname, int driveno, + int sibling_fds[], int *sibling_count, + int host_no, int channel_no, int id_no, int lun_no); +int sg_release_siblings(int sibling_fds[], int *sibling_count); +int sg_close_drive(struct burn_drive *d); + void sg_enumerate(void); void ata_enumerate(void); int sg_grab(struct burn_drive *);