Avoided open()-close() cycles during drive scan and grab on Linux

This commit is contained in:
Thomas Schmitt 2011-10-02 13:41:21 +00:00
parent 91e2256ffb
commit b81585e082
2 changed files with 107 additions and 36 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2011.09.27.124555" #define Cdrskin_timestamP "2011.10.02.134037"

View File

@ -252,9 +252,13 @@ int burn_drive_is_banned(char *device_address);
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static void enumerate_common(char *fname, int bus_no, int host_no, static void enumerate_common(char *fname, int fd_in, int bus_no, int host_no,
int channel_no, int target_no, int lun_no); int channel_no, int target_no, int lun_no);
static int sg_obtain_scsi_adr_fd(char *path, int fd_in,
int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no);
/* ts A60813 : storage objects are in libburn/init.c /* ts A60813 : storage objects are in libburn/init.c
whether to use O_EXCL with open(2) of devices whether to use O_EXCL with open(2) of devices
@ -757,12 +761,15 @@ failed:;
/* ts A80731 */ /* ts A80731 */
static int is_ata_drive(char *fname) static int is_ata_drive(char *fname, int fd_in)
{ {
int fd; int fd;
struct hd_driveid tm; struct hd_driveid tm;
fd = sg_open_drive_fd(fname, 1); if (fd_in >= 0)
fd = fd_in;
else
fd = sg_open_drive_fd(fname, 1);
if (fd == -1) { if (fd == -1) {
if (linux_ata_enumerate_verbous) if (linux_ata_enumerate_verbous)
fprintf(stderr,"open failed, errno=%d '%s'\n", fprintf(stderr,"open failed, errno=%d '%s'\n",
@ -777,7 +784,8 @@ static int is_ata_drive(char *fname)
if (!(tm.config & 0x8000) || (tm.config & 0x4000)) { if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
if (linux_ata_enumerate_verbous) if (linux_ata_enumerate_verbous)
fprintf(stderr, "not marked as ATAPI\n"); fprintf(stderr, "not marked as ATAPI\n");
sg_close_drive_fd(fname, -1, &fd, 0); if (fd_in < 0)
sg_close_drive_fd(fname, -1, &fd, 0);
return 0; return 0;
} }
@ -788,9 +796,12 @@ static int is_ata_drive(char *fname)
fprintf(stderr, fprintf(stderr,
"FATAL: sgio_test() failed: errno=%d '%s'\n", "FATAL: sgio_test() failed: errno=%d '%s'\n",
errno, strerror(errno)); errno, strerror(errno));
sg_close_drive_fd(fname, -1, &fd, 0); if (fd_in < 0)
sg_close_drive_fd(fname, -1, &fd, 0);
return 0; return 0;
} }
if (fd_in >= 0)
return 1;
if (sg_close_drive_fd(fname, -1, &fd, 1) <= 0) { if (sg_close_drive_fd(fname, -1, &fd, 1) <= 0) {
if (linux_ata_enumerate_verbous) if (linux_ata_enumerate_verbous)
fprintf(stderr, fprintf(stderr,
@ -802,7 +813,7 @@ static int is_ata_drive(char *fname)
} }
static int is_scsi_drive(char *fname, int *bus_no, int *host_no, static int is_scsi_drive(char *fname, int fd_in, int *bus_no, int *host_no,
int *channel_no, int *target_no, int *lun_no) int *channel_no, int *target_no, int *lun_no)
{ {
int fd, sid_ret = 0, ret; int fd, sid_ret = 0, ret;
@ -815,7 +826,10 @@ static int is_scsi_drive(char *fname, int *bus_no, int *host_no,
BURN_ALLOC_MEM(sibling_fnames, burn_sg_sibling_fname, BURN_ALLOC_MEM(sibling_fnames, burn_sg_sibling_fname,
BURN_OS_SG_MAX_SIBLINGS); BURN_OS_SG_MAX_SIBLINGS);
fd = sg_open_drive_fd(fname, 1); if (fd_in >= 0)
fd = fd_in;
else
fd = sg_open_drive_fd(fname, 1);
if (fd == -1) { if (fd == -1) {
if (linux_sg_enumerate_debug) if (linux_sg_enumerate_debug)
fprintf(stderr, "open failed, errno=%d '%s'\n", fprintf(stderr, "open failed, errno=%d '%s'\n",
@ -837,7 +851,8 @@ static int is_scsi_drive(char *fname, int *bus_no, int *host_no,
"FATAL: sgio_test() failed: errno=%d '%s'", "FATAL: sgio_test() failed: errno=%d '%s'",
errno, strerror(errno)); errno, strerror(errno));
sg_close_drive_fd(fname, -1, &fd, 0); if (fd_in < 0)
sg_close_drive_fd(fname, -1, &fd, 0);
{ret = 0; goto ex;} {ret = 0; goto ex;}
} }
@ -863,14 +878,19 @@ static int is_scsi_drive(char *fname, int *bus_no, int *host_no,
*bus_no = -1; *bus_no = -1;
#endif #endif
if (sg_close_drive_fd(fname, -1, &fd, /* >>> SINGLE_OPEN : close in label ex.
after re-using fd with sg_obtain_scsi_adr_fd() */
if (fd_in < 0) {
if (sg_close_drive_fd(fname, -1, &fd,
sid.scsi_type == TYPE_ROM ) <= 0) { sid.scsi_type == TYPE_ROM ) <= 0) {
if (linux_sg_enumerate_debug) if (linux_sg_enumerate_debug)
fprintf(stderr, fprintf(stderr,
"cannot close properly, errno=%d '%s'\n", "cannot close properly, errno=%d '%s'\n",
errno, strerror(errno)); errno, strerror(errno));
{ret = 0; goto ex;} {ret = 0; goto ex;}
}
} }
if ( (sid_ret == -1 || sid.scsi_type != TYPE_ROM) if ( (sid_ret == -1 || sid.scsi_type != TYPE_ROM)
&& !linux_sg_accept_any_type) { && !linux_sg_accept_any_type) {
if (linux_sg_enumerate_debug) if (linux_sg_enumerate_debug)
@ -881,7 +901,8 @@ static int is_scsi_drive(char *fname, int *bus_no, int *host_no,
if (sid_ret == -1 || sid.scsi_id < 0) { if (sid_ret == -1 || sid.scsi_id < 0) {
/* ts A61211 : employ a more general ioctl */ /* ts A61211 : employ a more general ioctl */
ret = sg_obtain_scsi_adr(fname, bus_no, host_no, /* ts B11001 : re-use fd if still open */
ret = sg_obtain_scsi_adr_fd(fname, fd, bus_no, host_no,
channel_no, target_no, lun_no); channel_no, target_no, lun_no);
if (ret>0) { if (ret>0) {
sid.host_no = *host_no; sid.host_no = *host_no;
@ -891,7 +912,7 @@ static int is_scsi_drive(char *fname, int *bus_no, int *host_no,
} else { } else {
if (linux_sg_enumerate_debug) if (linux_sg_enumerate_debug)
fprintf(stderr, fprintf(stderr,
"sg_obtain_scsi_adr() failed\n"); "sg_obtain_scsi_adr_fd() failed\n");
{ret = 0; goto ex;} {ret = 0; goto ex;}
} }
} }
@ -931,12 +952,26 @@ ex:;
} }
static int sg_open_for_enumeration(char *fname, int flag)
{
int fd;
fd = sg_open_drive_fd(fname, 1);
if (fd < 0) {
if (linux_sg_enumerate_debug || linux_ata_enumerate_verbous)
fprintf(stderr, "open failed, errno=%d '%s'\n",
errno, strerror(errno));
return -1;
}
return fd;
}
/** Speciality of GNU/Linux: detect non-SCSI ATAPI (EIDE) which will from /** Speciality of GNU/Linux: detect non-SCSI ATAPI (EIDE) which will from
then on used used via generic SCSI as is done with (emulated) SCSI drives */ then on used used via generic SCSI as is done with (emulated) SCSI drives */
static void ata_enumerate(void) static void ata_enumerate(void)
{ {
int ret; int ret, i, fd = -1;
int i;
char fname[10]; char fname[10];
if (linux_ata_enumerate_verbous) if (linux_ata_enumerate_verbous)
@ -957,14 +992,17 @@ static void ata_enumerate(void)
fprintf(stderr, "not in whitelist\n"); fprintf(stderr, "not in whitelist\n");
continue; continue;
} }
ret = is_ata_drive(fname); fd = sg_open_for_enumeration(fname, 0);
if (fd < 0)
continue;
ret = is_ata_drive(fname, fd);
if (ret < 0) if (ret < 0)
break; break;
if (ret == 0) if (ret == 0)
continue; continue;
if (linux_ata_enumerate_verbous) if (linux_ata_enumerate_verbous)
fprintf(stderr, "accepting as drive without SCSI address\n"); fprintf(stderr, "accepting as drive without SCSI address\n");
enumerate_common(fname, -1, -1, -1, -1, -1); enumerate_common(fname, fd, -1, -1, -1, -1, -1);
} }
} }
@ -972,7 +1010,7 @@ static void ata_enumerate(void)
/** Detects (probably emulated) SCSI drives */ /** Detects (probably emulated) SCSI drives */
static void sg_enumerate(void) static void sg_enumerate(void)
{ {
int i, ret; int i, ret, fd = -1;
int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1; int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
char fname[17]; char fname[17];
@ -1000,8 +1038,11 @@ static void sg_enumerate(void)
fprintf(stderr, "not in whitelist\n"); fprintf(stderr, "not in whitelist\n");
continue; continue;
} }
fd = sg_open_for_enumeration(fname, 0);
if (fd < 0)
continue;
ret = is_scsi_drive(fname, &bus_no, &host_no, &channel_no, ret = is_scsi_drive(fname, fd, &bus_no, &host_no, &channel_no,
&target_no, &lun_no); &target_no, &lun_no);
if (ret < 0) if (ret < 0)
break; break;
@ -1010,7 +1051,7 @@ static void sg_enumerate(void)
if (linux_sg_enumerate_debug) if (linux_sg_enumerate_debug)
fprintf(stderr, "accepting as SCSI %d,%d,%d,%d bus=%d\n", fprintf(stderr, "accepting as SCSI %d,%d,%d,%d bus=%d\n",
host_no, channel_no, target_no, lun_no, bus_no); host_no, channel_no, target_no, lun_no, bus_no);
enumerate_common(fname, bus_no, host_no, channel_no, enumerate_common(fname, fd, bus_no, host_no, channel_no,
target_no, lun_no); target_no, lun_no);
} }
@ -1059,7 +1100,7 @@ static int fname_drive_is_listed(char *fname, int flag)
*/ */
static int fname_enumerate(char *fname, int flag) static int fname_enumerate(char *fname, int flag)
{ {
int is_ata= 0, is_scsi= 0, ret; int is_ata= 0, is_scsi= 0, ret, fd = -1;
int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1; int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
char *msg = NULL; char *msg = NULL;
struct stat stbuf; struct stat stbuf;
@ -1077,13 +1118,16 @@ static int fname_enumerate(char *fname, int flag)
msg, 0, 0); msg, 0, 0);
{ret = -1; goto ex;} {ret = -1; goto ex;}
} }
is_ata = is_ata_drive(fname); fd = sg_open_for_enumeration(fname, 0);
if (fd < 0)
{ret = 0; goto ex;}
is_ata = is_ata_drive(fname, fd);
if (is_ata < 0) if (is_ata < 0)
{ret = -1; goto ex;} {ret = -1; goto ex;}
if (!is_ata) if (!is_ata)
is_scsi = is_scsi_drive(fname, &bus_no, &host_no, &channel_no, is_scsi = is_scsi_drive(fname, fd, &bus_no, &host_no,
&target_no, &lun_no); &channel_no, &target_no, &lun_no);
if (is_scsi < 0) if (is_scsi < 0)
{ret = -1; goto ex;} {ret = -1; goto ex;}
if (is_ata == 0 && is_scsi == 0) if (is_ata == 0 && is_scsi == 0)
@ -1093,7 +1137,8 @@ static int fname_enumerate(char *fname, int flag)
fprintf(stderr, fprintf(stderr,
"(single) accepting as SCSI %d,%d,%d,%d bus=%d\n", "(single) accepting as SCSI %d,%d,%d,%d bus=%d\n",
host_no, channel_no, target_no, lun_no, bus_no); host_no, channel_no, target_no, lun_no, bus_no);
enumerate_common(fname, bus_no, host_no, channel_no,
enumerate_common(fname, fd, bus_no, host_no, channel_no,
target_no, lun_no); target_no, lun_no);
ret = 1; ret = 1;
ex:; ex:;
@ -1246,7 +1291,7 @@ static int add_proc_info_drives(int flag)
*/ */
/* ts A60923 - A61005 : introduced new SCSI parameters */ /* ts A60923 - A61005 : introduced new SCSI parameters */
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */ /* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
static void enumerate_common(char *fname, int bus_no, int host_no, static void enumerate_common(char *fname, int fd_in, int bus_no, int host_no,
int channel_no, int target_no, int lun_no) int channel_no, int target_no, int lun_no)
{ {
int ret, i; int ret, i;
@ -1278,8 +1323,12 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
out.release = sg_release; out.release = sg_release;
out.drive_is_open= sg_drive_is_open; out.drive_is_open= sg_drive_is_open;
out.issue_command = sg_issue_command; out.issue_command = sg_issue_command;
if (fd_in >= 0)
out.fd = fd_in;
/* Finally register drive and inquire drive information */ /* Finally register drive and inquire drive information.
out is an invalid copy afterwards. Do not use it for anything.
*/
burn_drive_finish_enum(&out); burn_drive_finish_enum(&out);
} }
@ -1533,6 +1582,12 @@ int sg_grab(struct burn_drive *d)
if(! burn_drive_is_open(d)) { if(! burn_drive_is_open(d)) {
char msg[120]; char msg[120];
/* >>> SINGLE_OPEN : This case should be impossible now, since enumeration
transfers the fd from scanning to drive.
So if close-wait-open is desired, then it has to
be done unconditionally.
*/
#ifndef Libburn_udev_wait_useC #ifndef Libburn_udev_wait_useC
#define Libburn_udev_wait_useC 100000 #define Libburn_udev_wait_useC 100000
#endif #endif
@ -1577,7 +1632,6 @@ try_open:;
if(ret <= 0) if(ret <= 0)
goto drive_is_in_use; goto drive_is_in_use;
} }
fd = open(d->devname, open_mode); fd = open(d->devname, open_mode);
os_errno = errno; os_errno = errno;
@ -1820,12 +1874,13 @@ ex:;
} }
/* ts A60922 */ /* ts B11001 : outsourced from non-static sg_obtain_scsi_adr() */
/** Tries to obtain SCSI address parameters. /** Tries to obtain SCSI address parameters.
@return 1 is success , 0 is failure @return 1 is success , 0 is failure
*/ */
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no, static int sg_obtain_scsi_adr_fd(char *path, int fd_in,
int *target_no, int *lun_no) int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{ {
int fd, ret, l, open_mode = O_RDONLY; int fd, ret, l, open_mode = O_RDONLY;
struct my_scsi_idlun { struct my_scsi_idlun {
@ -1853,7 +1908,10 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
SuSE 9.0 (kernel 2.4) and SuSE 9.3 (kernel 2.6) */ SuSE 9.0 (kernel 2.4) and SuSE 9.3 (kernel 2.6) */
/* so skip it for now */; /* so skip it for now */;
} }
fd = open(path, open_mode); if (fd_in >= 0)
fd = fd_in;
else
fd = open(path, open_mode);
if(fd < 0) if(fd < 0)
return 0; return 0;
sg_fcntl_lock(&fd, path, F_RDLCK, 0); sg_fcntl_lock(&fd, path, F_RDLCK, 0);
@ -1869,7 +1927,8 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
/* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */ /* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun); ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
sg_close_drive_fd(path, -1, &fd, 0); if (fd_in < 0)
sg_close_drive_fd(path, -1, &fd, 0);
if (ret == -1) if (ret == -1)
return(0); return(0);
*host_no= (idlun.x>>24)&255; *host_no= (idlun.x>>24)&255;
@ -1886,6 +1945,18 @@ int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
} }
/* ts A60922 */
/** Tries to obtain SCSI address parameters.
@return 1 is success , 0 is failure
*/
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
return sg_obtain_scsi_adr_fd(path, -1, bus_no, host_no, channel_no,
target_no, lun_no);
}
/* ts A60922 ticket 33 : called from drive.c */ /* ts A60922 ticket 33 : called from drive.c */
/** Tells wether a text is a persistent address as listed by the enumeration /** Tells wether a text is a persistent address as listed by the enumeration
functions. functions.