/****************************************************************************** * gntalloc.c * * Device for creating grant references (in user-space) that may be shared * with other domains. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* * This driver exists to allow userspace programs in Linux to allocate kernel * memory that will later be shared with another domain. Without this device, * Linux userspace programs cannot create grant references. * * How this stuff works: * X -> granting a page to Y * Y -> mapping the grant from X * * 1. X uses the gntalloc device to allocate a page of kernel memory, P. * 2. X creates an entry in the grant table that says domid(Y) can access P. * This is done without a hypercall unless the grant table needs expansion. * 3. X gives the grant reference identifier, GREF, to Y. * 4. Y maps the page, either directly into kernel memory for use in a backend * driver, or via a the gntdev device to map into the address space of an * application running in Y. This is the first point at which Xen does any * tracking of the page. * 5. A program in X mmap()s a segment of the gntalloc device that corresponds * to the shared page, and can now communicate with Y over the shared page. * * * NOTE TO USERSPACE LIBRARIES: * The grant allocation and mmap()ing are, naturally, two separate operations. * You set up the sharing by calling the create ioctl() and then the mmap(). * Teardown requires munmap() and either close() or ioctl(). * * WARNING: Since Xen does not allow a guest to forcibly end the use of a grant * reference, this device can be used to consume kernel memory by leaving grant * references mapped by another domain when an application exits. Therefore, * there is a global limit on the number of pages that can be allocated. When * all references to the page are unmapped, it will be freed during the next * grant operation.
*/
staticint limit = 1024;
module_param(limit, int, 0644);
MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by " "the gntalloc device");
struct notify_info {
uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */
uint16_t flags:2; /* Bits 12-13: Unmap notification flags */ int event; /* Port (event channel) to notify */
};
/* Metadata on a grant reference. */ struct gntalloc_gref { struct list_head next_gref; /* list entry gref_list */ struct list_head next_file; /* list entry file->list, if open */ struct page *page; /* The shared page */
uint64_t file_index; /* File offset for mmap() */ unsignedint users; /* Use count - when zero, waiting on Xen */
grant_ref_t gref_id; /* The grant reference number */ struct notify_info notify; /* Unmap notification */
};
mutex_lock(&gref_mutex); /* Clean up pages that were at zero (local) users but were still mapped * by remote domains. Since those pages count towards the limit that we * are about to enforce, removing them here is a good idea.
*/
do_cleanup(); if (gref_size + op.count > limit) {
mutex_unlock(&gref_mutex);
rc = -ENOSPC; goto out_free;
}
gref_size += op.count;
op.index = priv->index;
priv->index += op.count * PAGE_SIZE;
mutex_unlock(&gref_mutex);
/* Once we finish add_grefs, it is unsafe to touch the new reference, * since it is possible for a concurrent ioctl to remove it (by guessing * its index). If the userspace application doesn't provide valid memory * to write the IDs to, then it will need to close the file in order to * release - which it will do by segfaulting when it tries to access the * IDs to close them.
*/ if (copy_to_user(arg, &op, sizeof(op))) {
rc = -EFAULT; goto out_free;
} if (copy_to_user(arg->gref_ids_flex, gref_ids, sizeof(gref_ids[0]) * op.count)) {
rc = -EFAULT; goto out_free;
}
out_free:
kfree(gref_ids);
out: return rc;
}
staticlong gntalloc_ioctl_dealloc(struct gntalloc_file_private_data *priv, void __user *arg)
{ int i, rc = 0; struct ioctl_gntalloc_dealloc_gref op; struct gntalloc_gref *gref, *n;
mutex_lock(&gref_mutex);
gref = find_grefs(priv, op.index, op.count); if (gref) { /* Remove from the file list only, and decrease reference count. * The later call to do_cleanup() will remove from gref_list and * free the memory if the pages aren't mapped anywhere.
*/ for (i = 0; i < op.count; i++) {
n = list_entry(gref->next_file.next, struct gntalloc_gref, next_file);
list_del(&gref->next_file);
gref->users--;
gref = n;
}
} else {
rc = -EINVAL;
}
/* We need to grab a reference to the event channel we are going to use * to send the notify before releasing the reference we may already have * (if someone has called this ioctl twice). This is required so that * it is possible to change the clear_byte part of the notification * without disturbing the event channel part, which may now be the last * reference to that event channel.
*/ if (op.action & UNMAP_NOTIFY_SEND_EVENT) { if (evtchn_get(op.event_channel_port)) {
rc = -EINVAL; goto unlock_out;
}
}
if (gref->notify.flags & UNMAP_NOTIFY_SEND_EVENT)
evtchn_put(gref->notify.event);
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.