All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@domain.hid>
To: Rodrigo Rosenfeld Rosas <lbocseg@domain.hid>
Cc: xenomai@xenomai.org
Subject: Re: [Xenomai-core] [PATCH] provide rtdm_mmap_to_user / rtdm_munmap
Date: Tue, 14 Feb 2006 01:39:48 +0100	[thread overview]
Message-ID: <43F126D4.4040407@domain.hid> (raw)
In-Reply-To: <43EFFB80.1080104@domain.hid>


[-- Attachment #1.1: Type: text/plain, Size: 1926 bytes --]

Rodrigo Rosenfeld Rosas wrote:
> Jan Kiszka escreveu:
>> Ok, but even if you decide to let rt-mmap be non-deterministic, you
>> still need some means to prevent the scenario you described above.
>> Actually, all you need is some callback when the mapped memory block was
>> actually released (munmap/application exit). Such a callback can be
>> registered inside the rtdm_mmap handler as a vma_fileop.
> I have never worked with vma_fileop... I would need to learn it first.

Here is the patch to offer you access to those ops. Revert the previous
version, then apply this one. It still needs some final documentation
notes and a test on kernel 2.4. But is should already work on 2.6.

I also attached a demo for the handler usage based on my previous test
framework. Just grab the pattern and put some useful code in the close
handler...

>>  It will run in
>> non-RT, and could be used to mark the related hardware buffer as finally
>> free for re-allocation.
> Now, I did realize that there is one more problem on my current design.
> If the user application exits or is terminated, I'm not sure if the
> close handler is called if the user forgot/was not able to. If it is
> not, the buffer would be marked as used until I reloaded the driver...
> Is the close handler invocated on application termination?

Yep, this is a general issue you cannot avoid: all skin objects besides
task are only released when the user-space application cleans it up as
it's ought to. There is no tracking of used resources, no auto-cleanup.
If your application fails to close a device or socket, you will get a
stalled handle which can be found in /proc/xenomai/rtdm/open_files.
Writing the file descriptor number to this particular proc-file (e.g.
"echo 3 > /proc/xeno...") will trigger an enforced close and will
release the file descriptor again. Useful when debugging such broken
applications.

Jan

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: rtdm_mmap-v3.patch --]
[-- Type: text/x-patch; name="rtdm_mmap-v3.patch", Size: 6356 bytes --]

Index: include/rtdm/rtdm_driver.h
===================================================================
--- include/rtdm/rtdm_driver.h	(Revision 564)
+++ include/rtdm/rtdm_driver.h	(Arbeitskopie)
@@ -995,6 +995,12 @@
     xnfree(ptr);
 }
 
+int rtdm_mmap_to_user(rtdm_user_info_t *user_info, void *src_addr, size_t len,
+                      int prot, void **pptr,
+                      struct vm_operations_struct *vm_ops,
+                      void *vm_private_data);
+int rtdm_munmap(rtdm_user_info_t *user_info, void *ptr, size_t len);
+
 static inline int rtdm_read_user_ok(rtdm_user_info_t *user_info,
                                     const void __user *ptr, size_t size)
 {
Index: ksrc/skins/rtdm/drvlib.c
===================================================================
--- ksrc/skins/rtdm/drvlib.c	(Revision 564)
+++ ksrc/skins/rtdm/drvlib.c	(Arbeitskopie)
@@ -31,6 +31,7 @@
 
 
 #include <linux/delay.h>
+#include <linux/mman.h>
 
 #include <rtdm/rtdm_driver.h>
 
@@ -1286,7 +1287,7 @@
  * Rescheduling: never.
  */
 int rtdm_irq_disable(rtdm_irq_t *irq_handle);
-/** @} */
+/** @} Interrupt Management Services */
 
 
 /*!
@@ -1358,16 +1359,158 @@
  * environments.
  */
 void rtdm_nrtsig_pend(rtdm_nrtsig_t *nrt_sig);
-/** @} */
+/** @} Non-Real-Time Signalling Services */
 
+#endif /* DOXYGEN_CPP */
 
+
 /*!
  * @ingroup driverapi
  * @defgroup util Utility Services
  * @{
  */
 
+struct rtdm_mmap_data {
+    void *src_addr;
+    struct vm_operations_struct *vm_ops;
+    void *vm_private_data;
+};
+
+static int rtdm_mmap_buffer(struct file *filp, struct vm_area_struct *vma)
+{
+    struct rtdm_mmap_data *mmap_data = filp->private_data;
+
+    vma->vm_ops = mmap_data->vm_ops;
+    vma->vm_private_data = mmap_data->vm_private_data;
+
+    return xnarch_remap_page_range(vma, vma->vm_start,
+                                   virt_to_phys(mmap_data->src_addr),
+                                   vma->vm_end - vma->vm_start, PAGE_SHARED);
+}
+
+static struct file_operations rtdm_mmap_fops = {
+    .mmap = rtdm_mmap_buffer,
+};
+
 /**
+ * Map a kernel memory range into the address space of the user.
+ *
+ * @param[in] user_info User information pointer as passed to the invoked
+ * device operation handler
+ * @param[in] src_addr Kernel address to be mapped
+ * @param[in] len Length of the memory range
+ * @param[in] prot Protection flags for the user's memory range, typically
+ * either PROT_READ or PROT_READ|PROT_WRITE
+ * @param[in,out] pptr Address of a pointer containing the desired user
+ * address or NULL on entry and the finally assigned address on return
+ * @param[in] vm_ops vm_operations to be executed on the vma_area of the
+ * user memory range or NULL
+ * @param[in] vm_private_data Private data to be stored in the vma_area,
+ * primarily useful for vm_operation handlers
+ *
+ * @return 0 on success, otherwise:
+ *
+ * - -EXXX is returned if .
+ *
+ * @note RTDM supports two models for unmapping the user memory range again.
+ * One is explicite unmapping via rtdm_munmap(), either performed when the
+ * user requests it via an IOCTL etc. or when the related device is closed.
+ * The other is automatic unmapping, triggered by the user invoking standard
+ * munmap() or by the termination of the related process. To track release of
+ * the mapping and therefore relinquishment of the referenced physical memory,
+ * the caller of rtdm_mmap_to_user() can pass a vm_operations_struct on
+ * invocation, defining a close handler for the vm_area. See Linux
+ * documentaion (e.g. Linux Device Drivers book) on virtual memory management
+ * for details.
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - User-space task (non-RT)
+ *
+ * Rescheduling: possible.
+ */
+int rtdm_mmap_to_user(rtdm_user_info_t *user_info, void *src_addr, size_t len,
+                      int prot, void **pptr,
+                      struct vm_operations_struct *vm_ops,
+                      void *vm_private_data)
+{
+    struct rtdm_mmap_data   mmap_data = {src_addr, vm_ops, vm_private_data};
+    struct file             *filp;
+    struct file_operations  *old_fops;
+    void                    *old_priv_data;
+    void                    *user_ptr;
+
+    filp = filp_open("/dev/zero", O_RDWR, 0);
+    if (IS_ERR(filp))
+        return PTR_ERR(filp);
+
+    old_fops = filp->f_op;
+    filp->f_op = &rtdm_mmap_fops;
+
+    old_priv_data = filp->private_data;
+    filp->private_data = &mmap_data;
+
+    down_write(&user_info->mm->mmap_sem);
+    user_ptr = (void *)do_mmap(filp, (unsigned long)*pptr, len, prot,
+                               MAP_SHARED, 0);
+    up_write(&user_info->mm->mmap_sem);
+
+    filp->f_op = old_fops;
+    filp->private_data = old_priv_data;
+
+    filp_close(filp, user_info->files);
+
+    if (IS_ERR(user_ptr))
+        return PTR_ERR(user_ptr);
+
+    *pptr = user_ptr;
+    return 0;
+}
+
+EXPORT_SYMBOL(rtdm_mmap_to_user);
+
+
+/**
+ * Unmap a user memory range.
+ *
+ * @param[in] user_info User information pointer as passed to
+ * rtdm_mmap_to_user() when requesting to map the memory range
+ * @param[in] ptr User address or the memory range
+ * @param[in] len Length of the memory range
+ *
+ * @return 0 on success, otherwise:
+ *
+ * - -EXXX is returned if .
+ *
+ * Environments:
+ *
+ * This service can be called from:
+ *
+ * - Kernel module initialization/cleanup code
+ * - User-space task (non-RT)
+ *
+ * Rescheduling: possible.
+ */
+int rtdm_munmap(rtdm_user_info_t *user_info, void *ptr, size_t len)
+{
+    int err;
+
+    down_write(&user_info->mm->mmap_sem);
+    err = do_munmap(user_info->mm, (unsigned long)ptr, len);
+    up_write(&user_info->mm->mmap_sem);
+
+    return err;
+}
+
+EXPORT_SYMBOL(rtdm_munmap);
+
+
+#ifdef DOXYGEN_CPP /* Only used for doxygen doc generation */
+
+/**
  * Real-time safe message printing on kernel console
  *
  * @param[in] format Format string (conforming standard @c printf())
@@ -1583,6 +1726,6 @@
  */
 int rtdm_in_rt_context(void);
 
-/** @} */
+#endif /* DOXYGEN_CPP */
 
-#endif /* DOXYGEN_CPP */
+/** @} Utility Services */

[-- Attachment #1.3: rtmmap_drv.c --]
[-- Type: text/plain, Size: 3271 bytes --]

#include <linux/mman.h>

#include <rtdm/rtdm_driver.h>


#define BUFFER_SIZE     100000


struct demodrv_context {
    void *buf;
};


static void demo_vm_close(struct vm_area_struct *vma)
{
    printk("releasing %p, data = %p\n", vma, vma->vm_private_data);
}


static struct vm_operations_struct mmap_ops = {
    .close = demo_vm_close,
};


int demo_open_rt(struct rtdm_dev_context    *context,
                 rtdm_user_info_t           *user_info,
                 int                        oflags)
{
    struct demodrv_context  *my_context;
    unsigned long vaddr;


    my_context = (struct demodrv_context *)context->dev_private;

    my_context->buf = kmalloc(BUFFER_SIZE, 0);
    /* mark pages reserved so that remap_pfn_range works */
    for (vaddr = (unsigned long)my_context->buf;
         vaddr < (unsigned long)my_context->buf + BUFFER_SIZE;
         vaddr += PAGE_SIZE)
        SetPageReserved(virt_to_page(vaddr));
    *(int *)my_context->buf = 1234;

    return 0;
}


int demo_close_rt(struct rtdm_dev_context   *context,
                  rtdm_user_info_t          *user_info)
{
    struct demodrv_context  *my_context;


    my_context = (struct demodrv_context *)context->dev_private;

    printk("%d\n", *((int *)my_context->buf + 1000));

    kfree(my_context->buf);

    return 0;
}


int demo_ioctl_rt(struct rtdm_dev_context   *context,
                  rtdm_user_info_t          *user_info,
                  int                       request,
                  void                      *arg)
{
    struct demodrv_context  *my_context;
    int err;


    my_context = (struct demodrv_context *)context->dev_private;

    printk("buf = %p:%x\n", my_context->buf, *(int *)my_context->buf);

    err = rtdm_mmap_to_user(user_info, my_context->buf, BUFFER_SIZE,
                            PROT_READ|PROT_WRITE, (void **)arg, &mmap_ops,
                            0x12345678);
    printk("rtdm_mmap = %p %d\n", *(void **)arg, err);

    return 0;
}


static struct rtdm_device demo_device = {
    struct_version:     RTDM_DEVICE_STRUCT_VER,

    device_flags:       RTDM_NAMED_DEVICE,
    context_size:       sizeof(struct demodrv_context),
    device_name:        "demodev0",

    open_rt:            NULL,
    open_nrt:           demo_open_rt,

    ops: {
        close_rt:       NULL,
        close_nrt:      demo_close_rt,

        ioctl_rt:       NULL,
        ioctl_nrt:      demo_ioctl_rt,

        read_rt:        NULL,
        read_nrt:       NULL,

        write_rt:       NULL,
        write_nrt:      NULL,

        recvmsg_rt:     NULL,
        recvmsg_nrt:    NULL,

        sendmsg_rt:     NULL,
        sendmsg_nrt:    NULL,
    },

    device_class:       RTDM_CLASS_EXPERIMENTAL,
    device_sub_class:   222,
    driver_name:        "demodrv",
    peripheral_name:    "demodev",
    provider_name:      "-",
    proc_name:          demo_device.device_name,
};

int init_module(void)
{
    int ret;


    ret = rtdm_dev_register(&demo_device);
    printk("rtdm_dev_register = %d\n", ret);

    return ret;
}


void cleanup_module(void)
{
    rtdm_dev_unregister(&demo_device, 1000);
}

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]

  reply	other threads:[~2006-02-14  0:39 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-02-10  0:09 [Xenomai-core] [PATCH] provide rtdm_mmap_to_user / rtdm_munmap Jan Kiszka
2006-02-10  0:37 ` Jan Kiszka
2006-02-10 20:58   ` Rodrigo Rosenfeld Rosas
2006-02-10 21:28     ` Rodrigo Rosenfeld Rosas
2006-02-11  0:35       ` Jan Kiszka
2006-02-11 13:11         ` Rodrigo Rosenfeld Rosas
2006-02-11 13:29           ` Jan Kiszka
2006-02-11 19:44             ` Rodrigo Rosenfeld Rosas
2006-02-12 22:45               ` Jan Kiszka
2006-02-13  3:22                 ` Rodrigo Rosenfeld Rosas
2006-02-14  0:39                   ` Jan Kiszka [this message]
2006-02-14  2:04                     ` Rodrigo Rosenfeld Rosas
2006-02-14  7:55                       ` Jan Kiszka
  -- strict thread matches above, loose matches on Subject: below --
2006-02-14 13:14 Rodrigo Rosenfeld Rosas
2006-02-14 19:13 ` Philippe Gerum
2006-02-15  0:30 ` Jan Kiszka
2006-02-15 14:53   ` Rodrigo Rosenfeld Rosas
2006-02-16 17:14     ` Rodrigo Rosenfeld Rosas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=43F126D4.4040407@domain.hid \
    --to=jan.kiszka@domain.hid \
    --cc=lbocseg@domain.hid \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.