/* * Sequence based RTAS HCALL has to issue multiple times to retrieve * complete data from the hypervisor. For some of these RTAS calls, * the OS should not interleave calls with different input until the * sequence is completed. So data is collected for these calls during * ioctl handle and export to user space with read() handle. * This file provides common functions needed for such sequence based * RTAS calls Ex: ibm,get-vpd and ibm,get-indices.
*/
/** * papr_rtas_blob_generate() - Construct a new &struct papr_rtas_blob. * @seq: work function of the caller that is called to obtain * data with the caller RTAS call. * * The @work callback is invoked until it returns NULL. @seq is * passed to @work in its first argument on each call. When * @work returns data, it should store the data length in its * second argument. * * Context: May sleep. * Return: A completely populated &struct papr_rtas_blob, or NULL on error.
*/ staticconststruct papr_rtas_blob *
papr_rtas_blob_generate(struct papr_rtas_sequence *seq)
{ struct papr_rtas_blob *blob; constchar *buf;
size_t len; int err = 0;
blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT); if (!blob) return NULL;
int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, int err)
{ /* Preserve the first error recorded. */ if (seq->error == 0)
seq->error = err;
return seq->error;
}
/* * Higher-level retrieval code below. These functions use the * papr_rtas_blob_* and sequence_* APIs defined above to create fd-based * handles for consumption by user space.
*/
/** * papr_rtas_run_sequence() - Run a single retrieval sequence. * @seq: Functions of the caller to complete the sequence * * Context: May sleep. Holds a mutex and an RTAS work area for its * duration. Typically performs multiple sleepable slab * allocations. * * Return: A populated &struct papr_rtas_blob on success. Encoded error * pointer otherwise.
*/ staticconststruct papr_rtas_blob *papr_rtas_run_sequence(struct papr_rtas_sequence *seq)
{ conststruct papr_rtas_blob *blob;
if (seq->begin)
seq->begin(seq);
blob = papr_rtas_blob_generate(seq); if (!blob)
papr_rtas_sequence_set_err(seq, -ENOMEM);
if (seq->end)
seq->end(seq);
if (seq->error) {
papr_rtas_blob_free(blob); return ERR_PTR(seq->error);
}
return blob;
}
/** * papr_rtas_retrieve() - Return the data blob that is exposed to * user space. * @seq: RTAS call specific functions to be invoked until the * sequence is completed. * * Run sequences against @param until a blob is successfully * instantiated, or a hard error is encountered, or a fatal signal is * pending. * * Context: May sleep. * Return: A fully populated data blob when successful. Encoded error * pointer otherwise.
*/ conststruct papr_rtas_blob *papr_rtas_retrieve(struct papr_rtas_sequence *seq)
{ conststruct papr_rtas_blob *blob;
/* * EAGAIN means the sequence returns error with a -4 (data * changed and need to start the sequence) status from RTAS calls * and we should attempt a new sequence. PAPR+ (v2.13 R1–7.3.20–5 * - ibm,get-vpd, R1–7.3.17–6 - ibm,get-indices) indicates that * this should be a transient condition, not something that * happens continuously. But we'll stop trying on a fatal signal.
*/ do {
blob = papr_rtas_run_sequence(seq); if (!IS_ERR(blob)) /* Success. */ break; if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */ break;
cond_resched();
} while (!fatal_signal_pending(current));
return blob;
}
/** * papr_rtas_setup_file_interface - Complete the sequence and obtain * the data and export to user space with fd-based handles. Then the * user spave gets the data with read() handle. * @seq: RTAS call specific functions to get the data. * @fops: RTAS call specific file operations such as read(). * @name: RTAS call specific char device node. * * Return: FD handle for consumption by user space
*/ long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq, conststruct file_operations *fops, char *name)
{ conststruct papr_rtas_blob *blob; struct file *file; long ret; int fd;
blob = papr_rtas_retrieve(seq); if (IS_ERR(blob)) return PTR_ERR(blob);
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); if (fd < 0) {
ret = fd; goto free_blob;
}
file = anon_inode_getfile_fmode(name, fops, (void *)blob,
O_RDONLY, FMODE_LSEEK | FMODE_PREAD); if (IS_ERR(file)) {
ret = PTR_ERR(file); goto put_fd;
}
/* * papr_rtas_sequence_should_stop() - Determine whether RTAS retrieval * sequence should continue. * * Examines the sequence error state and outputs of the last call to * the specific RTAS to determine whether the sequence in progress * should continue or stop. * * Return: True if the sequence has encountered an error or if all data * for this sequence has been retrieved. False otherwise.
*/ bool papr_rtas_sequence_should_stop(conststruct papr_rtas_sequence *seq,
s32 status, bool init_state)
{ bool done;
if (seq->error) returntrue;
switch (status) { case RTAS_SEQ_COMPLETE: if (init_state)
done = false; /* Initial state. */ else
done = true; /* All data consumed. */ break; case RTAS_SEQ_MORE_DATA:
done = false; /* More data available. */ break; default:
done = true; /* Error encountered. */ break;
}
return done;
}
/* * User space read to retrieve data for the corresponding RTAS call. * papr_rtas_blob is filled with the data using the corresponding RTAS * call sequence API.
*/
ssize_t papr_rtas_common_handle_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{ conststruct papr_rtas_blob *blob = file->private_data;
/* We should not instantiate a handle without any data attached. */ if (!papr_rtas_blob_has_data(blob)) {
pr_err_once("handle without data\n"); return -EIO;
}
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.