/* * The internal buffer is meant to store obaque blobs of data, so it does * not know of higher level concepts like triggers. * It consists of a number of pages that are used as a ringbuffer. Each data * blob is stored in a simple record that consists of an integer, which * contains the size of the following data, and the data bytes themselfes. * * To allow for multiple independent readers we create one internal buffer * each time the device is opened and destroy the buffer when the file is * closed again. The number of pages used for this buffer is determined by * the module parmeter eer_pages. * * One record can be written to a buffer by using the functions * - dasd_eer_start_record (one time per record to write the size to the * buffer and reserve the space for the data) * - dasd_eer_write_buffer (one or more times per record to write the data) * The data can be written in several steps but you will have to compute * the total size up front for the invocation of dasd_eer_start_record. * If the ringbuffer is full, dasd_eer_start_record will remove the required * number of old records. * * A record is typically read in two steps, first read the integer that * specifies the size of the following data, then read the data. * Both can be done by * - dasd_eer_read_buffer * * For all mentioned functions you need to get the bufferlock first and keep * it until a complete record is written or read. * * All information necessary to keep track of an internal buffer is kept in * a struct eerbuffer. The buffer specific to a file pointer is strored in * the private_data field of that file. To be able to write data to all * existing buffers, each buffer is also added to the bufferlist. * If the user does not want to read a complete record in one go, we have to * keep track of the rest of the record. residual stores the number of bytes * that are still to deliver. If the rest of the record is invalidated between * two reads then residual will be set to -1 so that the next read will fail. * All entries in the eerbuffer structure are protected with the bufferlock. * To avoid races between writing to a buffer on the one side and creating * and destroying buffers on the other side, the bufferlock must also be used * to protect the bufferlist.
*/
/* * How many free bytes are available on the buffer. * Needs to be called with bufferlock held.
*/ staticint dasd_eer_get_free_bytes(struct eerbuffer *eerb)
{ if (eerb->head < eerb->tail) return eerb->tail - eerb->head - 1; return eerb->buffersize - eerb->head + eerb->tail -1;
}
/* * How many bytes of buffer space are used. * Needs to be called with bufferlock held.
*/ staticint dasd_eer_get_filled_bytes(struct eerbuffer *eerb)
{
/* * The dasd_eer_write_buffer function just copies count bytes of data * to the buffer. Make sure to call dasd_eer_start_record first, to * make sure that enough free space is available. * Needs to be called with bufferlock held.
*/ staticvoid dasd_eer_write_buffer(struct eerbuffer *eerb, char *data, int count)
{
/* * Whenever you want to write a blob of data to the internal buffer you * have to start by using this function first. It will write the number * of bytes that will be written to the buffer. If necessary it will remove * old records to make room for the new one. * Needs to be called with bufferlock held.
*/ staticint dasd_eer_start_record(struct eerbuffer *eerb, int count)
{ int tailcount;
/* * Release pages that are not used anymore.
*/ staticvoid dasd_eer_free_buffer_pages(char **buf, int no_pages)
{ int i;
for (i = 0; i < no_pages; i++)
free_page((unsignedlong) buf[i]);
}
/* * Allocate a new set of memory pages.
*/ staticint dasd_eer_allocate_buffer_pages(char **buf, int no_pages)
{ int i;
for (i = 0; i < no_pages; i++) {
buf[i] = (char *) get_zeroed_page(GFP_KERNEL); if (!buf[i]) {
dasd_eer_free_buffer_pages(buf, i); return -ENOMEM;
}
} return 0;
}
/* * SECTION: The extended error reporting functionality
*/
/* * When a DASD device driver wants to report an error, it calls the * function dasd_eer_write and gives the respective trigger ID as * parameter. Currently there are four kinds of triggers: * * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems * DASD_EER_PPRCSUSPEND: PPRC was suspended * DASD_EER_NOPATH: There is no path to the device left. * DASD_EER_STATECHANGE: The state of the device has changed. * * For the first three triggers all required information can be supplied by * the caller. For these triggers a record is written by the function * dasd_eer_write_standard_trigger. * * The DASD_EER_STATECHANGE trigger is special since a sense subsystem * status ccw need to be executed to gather the necessary sense data first. * The dasd_eer_snss function will queue the SNSS request and the request * callback will then call dasd_eer_write with the DASD_EER_STATCHANGE * trigger. * * To avoid memory allocations at runtime, the necessary memory is allocated * when the extended error reporting is enabled for a device (by * dasd_eer_probe). There is one sense subsystem status request for each * eer enabled DASD device. The presence of the cqr in device->eer_cqr * indicates that eer is enable for the device. The use of the snss request * is protected by the DASD_FLAG_EER_IN_USE bit. When this flag indicates * that the cqr is currently in use, dasd_eer_snss cannot start a second * request but sets the DASD_FLAG_EER_SNSS flag instead. The callback of * the SNSS request will check the bit and call dasd_eer_snss again.
*/
/* * The following function can be used for those triggers that have * all necessary data available when the function is called. * If the parameter cqr is not NULL, the chain of requests will be searched * for valid sense data, and all valid sense data sets will be added to * the triggers data.
*/ staticvoid dasd_eer_write_standard_trigger(struct dasd_device *device, struct dasd_ccw_req *cqr, int trigger)
{ struct dasd_ccw_req *temp_cqr; int data_size; struct timespec64 ts; struct dasd_eer_header header; unsignedlong flags; struct eerbuffer *eerb; char *sense;
/* go through cqr chain and count the valid sense data sets */
data_size = 0; for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) if (dasd_get_sense(&temp_cqr->irb))
data_size += 32;
/* * This function is called for all triggers. It calls the appropriate * function that writes the actual trigger records.
*/ void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr, unsignedint id)
{ if (!device->eer_cqr) return; switch (id) { case DASD_EER_FATALERROR: case DASD_EER_PPRCSUSPEND:
dasd_eer_write_standard_trigger(device, cqr, id); break; case DASD_EER_NOPATH: case DASD_EER_NOSPC: case DASD_EER_AUTOQUIESCE:
dasd_eer_write_standard_trigger(device, NULL, id); break; case DASD_EER_STATECHANGE:
dasd_eer_write_snss_trigger(device, cqr, id); break; default: /* unknown trigger, so we write it without any sense data */
dasd_eer_write_standard_trigger(device, NULL, id); break;
}
}
EXPORT_SYMBOL(dasd_eer_write);
/* * Start a sense subsystem status request. * Needs to be called with the device held.
*/ void dasd_eer_snss(struct dasd_device *device)
{ struct dasd_ccw_req *cqr;
cqr = device->eer_cqr; if (!cqr) /* Device not eer enabled. */ return; if (test_and_set_bit(DASD_FLAG_EER_IN_USE, &device->flags)) { /* Sense subsystem status request in use. */
set_bit(DASD_FLAG_EER_SNSS, &device->flags); return;
} /* cdev is already locked, can't use dasd_add_request_head */
clear_bit(DASD_FLAG_EER_SNSS, &device->flags);
cqr->status = DASD_CQR_QUEUED;
list_add(&cqr->devlist, &device->ccw_queue);
dasd_schedule_device_bh(device);
}
/* * Callback function for use with sense subsystem status request.
*/ staticvoid dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)
{ struct dasd_device *device = cqr->startdev; unsignedlong flags;
dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); if (device->eer_cqr == cqr) {
clear_bit(DASD_FLAG_EER_IN_USE, &device->flags); if (test_bit(DASD_FLAG_EER_SNSS, &device->flags)) /* Another SNSS has been requested in the meantime. */
dasd_eer_snss(device);
cqr = NULL;
}
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); if (cqr) /* * Extended error recovery has been switched off while * the SNSS request was running. It could even have * been switched off and on again in which case there * is a new ccw in device->eer_cqr. Free the "old" * snss request now.
*/
dasd_sfree_request(cqr, device);
}
/* * Enable error reporting on a given device.
*/ int dasd_eer_enable(struct dasd_device *device)
{ struct dasd_ccw_req *cqr = NULL; unsignedlong flags; struct ccw1 *ccw; int rc = 0;
/* * On the one side we need a lock to access our internal buffer, on the * other side a copy_to_user can sleep. So we need to copy the data we have * to transfer in a readbuffer, which is protected by the readbuffer_mutex.
*/ staticchar readbuffer[PAGE_SIZE]; static DEFINE_MUTEX(readbuffer_mutex);
eerb = (struct eerbuffer *) filp->private_data; if (mutex_lock_interruptible(&readbuffer_mutex)) return -ERESTARTSYS;
spin_lock_irqsave(&bufferlock, flags);
if (eerb->residual < 0) { /* the remainder of this record */ /* has been deleted */
eerb->residual = 0;
spin_unlock_irqrestore(&bufferlock, flags);
mutex_unlock(&readbuffer_mutex); return -EIO;
} elseif (eerb->residual > 0) { /* OK we still have a second half of a record to deliver */
effective_count = min(eerb->residual, (int) count);
eerb->residual -= effective_count;
} else {
tc = 0; while (!tc) {
tc = dasd_eer_read_buffer(eerb, (char *) &tailcount, sizeof(tailcount)); if (!tc) { /* no data available */
spin_unlock_irqrestore(&bufferlock, flags);
mutex_unlock(&readbuffer_mutex); if (filp->f_flags & O_NONBLOCK) return -EAGAIN;
rc = wait_event_interruptible(
dasd_eer_read_wait_queue,
eerb->head != eerb->tail); if (rc) return rc; if (mutex_lock_interruptible(&readbuffer_mutex)) return -ERESTARTSYS;
spin_lock_irqsave(&bufferlock, flags);
}
}
WARN_ON(tc != sizeof(tailcount));
effective_count = min(tailcount,(int)count);
eerb->residual = tailcount - effective_count;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.