📄 st.c
字号:
__MOD_DEC_USE_COUNT(STp->device->host->hostt->module); return retval;}/* Flush the tape buffer before close */static int st_flush(struct file *filp){ int result = 0, result2; unsigned char cmd[MAX_COMMAND_SIZE]; Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; struct inode *inode = filp->f_dentry->d_inode; kdev_t devt = inode->i_rdev; int dev; if (file_count(filp) > 1) return 0; dev = TAPE_NR(devt); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { result = flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out; } if (STp->can_partitions && (result2 = update_partition(STp)) < 0) { DEBC(printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev)); if (result == 0) result = result2; goto out; } if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", dev, (long) (filp->f_pos)); printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n", dev, STp->nbr_waits, STp->nbr_finished); ) memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE); if (!SRpnt) { result = (STp->buffer)->syscall_result; goto out; } if ((STp->buffer)->syscall_result != 0 && ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 || (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 || ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 && (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] | SRpnt->sr_sense_buffer[5] | SRpnt->sr_sense_buffer[6]) != 0))) { /* Filter out successful write at EOM */ scsi_release_request(SRpnt); SRpnt = NULL; printk(KERN_ERR "st%d: Error on write filemark.\n", dev); if (result == 0) result = (-EIO); } else { scsi_release_request(SRpnt); SRpnt = NULL; if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; if (STp->two_fm) cross_eof(STp, FALSE); STps->eof = ST_FM; } DEBC(printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n", dev, cmd[4])); } else if (!STp->rew_at_close) { STps = &(STp->ps[STp->partition]); if (!STm->sysv || STps->rw != ST_READING) { if (STp->can_bsr) result = flush_buffer(STp, 0); else if (STps->eof == ST_FM_HIT) { result = cross_eof(STp, FALSE); if (result) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; STps->eof = ST_FM; } else STps->eof = ST_NOEOF; } } else if ((STps->eof == ST_NOEOF && !(result = cross_eof(STp, TRUE))) || STps->eof == ST_FM_HIT) { if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; STps->eof = ST_FM; } } out: if (STp->rew_at_close) { result2 = st_int_ioctl(STp, MTREW, 1); if (result == 0) result = result2; } return result;}/* Close the device and release it. BKL is not needed: this is the only thread accessing this tape. */static int st_release(struct inode *inode, struct file *filp){ int result = 0; Scsi_Tape *STp; unsigned long flags; kdev_t devt = inode->i_rdev; int dev; dev = TAPE_NR(devt); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); if (STp->door_locked == ST_LOCKED_AUTO) st_int_ioctl(STp, MTUNLOCK, 0); if (STp->buffer != NULL) { normalize_buffer(STp->buffer); write_lock_irqsave(&st_dev_arr_lock, flags); (STp->buffer)->in_use = 0; STp->buffer = NULL; } else { write_lock_irqsave(&st_dev_arr_lock, flags); } STp->in_use = 0; write_unlock_irqrestore(&st_dev_arr_lock, flags); if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); return result;}/* Write command */static ssize_t st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos){ struct inode *inode = filp->f_dentry->d_inode; ssize_t total; ssize_t i, do_count, blks, transfer; ssize_t retval = 0; int write_threshold; int doing_write = 0; unsigned char cmd[MAX_COMMAND_SIZE]; const char *b_point; Scsi_Request *SRpnt = NULL; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; int dev = TAPE_NR(inode->i_rdev); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); if (down_interruptible(&STp->lock)) return -ERESTARTSYS; /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto out; } if (ppos != &filp->f_pos) { /* "A request was outside the capabilities of the device." */ retval = (-ENXIO); goto out; } if (STp->ready != ST_READY) { if (STp->ready == ST_NO_TAPE) retval = (-ENOMEDIUM); else retval = (-EIO); goto out; } STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { retval = (-ENXIO); goto out; } if (count == 0) goto out; /* * If there was a bus reset, block further access * to this device. */ if (STp->device->was_reset) { retval = (-EIO); goto out; } DEB( if (!STp->in_use) { printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev); retval = (-EIO); goto out; } ) /* end DEB */ /* Write must be integral number of blocks */ if (STp->block_size != 0 && (count % STp->block_size) != 0) { printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n", dev); retval = (-EINVAL); goto out; } if (STp->can_partitions && (retval = update_partition(STp)) < 0) goto out; STps = &(STp->ps[STp->partition]); if (STp->write_prot) { retval = (-EACCES); goto out; } if (STp->block_size == 0) { if (STp->max_block > 0 && (count < STp->min_block || count > STp->max_block)) { retval = (-EINVAL); goto out; } if (count > (STp->buffer)->buffer_size && !enlarge_buffer(STp->buffer, count, STp->restr_dma)) { retval = (-EOVERFLOW); goto out; } } if ((STp->buffer)->buffer_blocks < 1) { /* Fixed block mode with too small buffer */ if (!enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { retval = (-EOVERFLOW); goto out; } (STp->buffer)->buffer_blocks = 1; } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !st_int_ioctl(STp, MTLOCK, 0)) STp->door_locked = ST_LOCKED_AUTO; if (STps->rw == ST_READING) { retval = flush_buffer(STp, 0); if (retval) goto out; STps->rw = ST_WRITING; } else if (STps->rw != ST_WRITING && STps->drv_file == 0 && STps->drv_block == 0) { if ((retval = set_mode_densblk(STp, STm)) < 0) goto out; if (STm->default_compression != ST_DONT_TOUCH && !(STp->compression_changed)) { if (st_compression(STp, (STm->default_compression == ST_YES))) { printk(KERN_WARNING "st%d: Can't set default compression.\n", dev); if (modes_defined) { retval = (-EINVAL); goto out; } } } } if ((STp->buffer)->writing) { write_behind_check(STp); if ((STp->buffer)->syscall_result) { DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev, (STp->buffer)->midlevel_result)); if ((STp->buffer)->midlevel_result == INT_MAX) STps->eof = ST_EOM_OK; else STps->eof = ST_EOM_ERROR; } } if (STps->eof == ST_EOM_OK) { retval = (-ENOSPC); goto out; } else if (STps->eof == ST_EOM_ERROR) { retval = (-EIO); goto out; } /* Check the buffer readability in cases where copy_user might catch the problems after some tape movement. */ if (STp->block_size != 0 && (copy_from_user(&i, buf, 1) != 0 || copy_from_user(&i, buf + count - 1, 1) != 0)) { retval = (-EFAULT); goto out; } if (!STm->do_buffer_writes) {#if 0 if (STp->block_size != 0 && (count % STp->block_size) != 0) { retval = (-EINVAL); /* Write must be integral number of blocks */ goto out; }#endif write_threshold = 1; } else write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; if (!STm->do_async_writes) write_threshold--; total = count; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = (STp->block_size != 0); STps->rw = ST_WRITING; b_point = buf; while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) || (STp->block_size != 0 && (STp->buffer)->buffer_bytes + count > write_threshold)) { doing_write = 1; if (STp->block_size == 0) do_count = count; else { do_count = (STp->buffer)->buffer_blocks * STp->block_size - (STp->buffer)->buffer_bytes; if (do_count > count) do_count = count; } i = append_to_buffer(b_point, STp->buffer, do_count); if (i) { retval = i; goto out; } if (STp->block_size == 0) blks = transfer = do_count; else { blks = (STp->buffer)->buffer_bytes / STp->block_size; transfer = blks * STp->block_size; } cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, TRUE); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto out; } if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev)); if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x40)) { if (STp->block_size != 0 && (SRpnt->sr_sense_buffer[0] & 0x80) != 0) transfer = (SRpnt->sr_sense_buffer[3] << 24) | (SRpnt->sr_sense_buffer[4] << 16) | (SRpnt->sr_sense_buffer[5] << 8) | SRpnt->sr_sense_buffer[6]; else if (STp->block_size == 0 && (SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) transfer = do_count; else transfer = 0; if (STp->block_size != 0) transfer *= STp->block_size; if (transfer <= do_count) { filp->f_pos += do_count - transfer; count -= do_count - transfer; if (STps->drv_block >= 0) { if (STp->block_size == 0 && transfer < do_count) STps->drv_block++; else if (STp->block_size != 0) STps->drv_block += (do_count - transfer) / STp->block_size; } STps->eof = ST_EOM_OK; retval = (-ENOSPC); /* EOM within current request */ DEBC(printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n", dev, transfer)); } else { STps->eof = ST_EOM_ERROR; STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); /* EOM for old data */ DEBC(printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev)); } } else { STps->drv_block = (-1); /* Too cautious? */ retval = (-EIO); } scsi_release_request(SRpnt); SRpnt = NULL; (STp->buffer)->buffer_bytes = 0; STp->dirty = 0; if (count < total) retval = total - count; goto out; } filp->f_pos += do_count; b_point += do_count; count -= do_count; if (STps->drv_block >= 0) { if (STp->block_size == 0) STps->drv_block++; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -