Module: xenomai-head
Branch: master
Commit: 7b98f5db55f391b55f3b104961c31cfbc36426f2
URL:    
http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=7b98f5db55f391b55f3b104961c31cfbc36426f2

Author: Philippe Gerum <r...@xenomai.org>
Date:   Mon Sep 27 10:58:21 2010 +0200

vfile: introduce O_EXCL handling

---

 include/nucleus/vfile.h |   31 ++++++++++++++++++++++++++++---
 ksrc/nucleus/vfile.c    |   35 ++++++++++++++++++++++++++++-------
 2 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/include/nucleus/vfile.h b/include/nucleus/vfile.h
index 3f42016..7aed7cc 100644
--- a/include/nucleus/vfile.h
+++ b/include/nucleus/vfile.h
@@ -40,8 +40,10 @@ struct xnvfile_lock_ops;
 
 struct xnvfile {
        struct proc_dir_entry *pde;
+       struct file *file;
        struct xnvfile_directory *parent;
        struct xnvfile_lock_ops *lockops;
+       int refcnt;
        void *private;
 };
 
@@ -109,13 +111,32 @@ struct xnvfile_input {
  */
 struct xnvfile_regular_ops {
        /**
+        * @anchor regular_rewind This handler is called only once,
+        * when the virtual file is opened, before the @ref
+        * regular_show "begin() handler" is invoked.
+        *
+        * @param it A pointer to the vfile iterator which will be
+        * used to read the file contents.
+        *
+        * @return Zero should be returned upon success. Otherwise, a
+        * negative error code aborts the operation, and is passed
+        * back to the reader.
+        *
+        * @note This handler is optional. It should not be used to
+        * allocate resources but rather to perform consistency
+        * checks, since no closure call is issued in case the open
+        * sequence eventually fails.
+        */
+       int (*rewind)(struct xnvfile_regular_iterator *it);
+       /**
         * @anchor regular_begin
         * This handler should prepare for iterating over the records
-        * upon a read request, according to the iterator data.
+        * upon a read request, starting from the specified position.
         *
         * @param it A pointer to the current vfile iterator. On
         * entry, it->pos is set to the (0-based) position of the
-        * first record to output.
+        * first record to output. This handler may be called multiple
+        * times with different position requests.
         *
         * @return A pointer to the first record to format and output,
         * to be passed to the @ref regular_show "show() handler" as
@@ -148,7 +169,7 @@ struct xnvfile_regular_ops {
         *
         * @param it A pointer to the current vfile iterator. On
         * entry, it->pos is set to the (0-based) position of the
-        * first record to output.
+        * next record to output.
         *
         * @return A pointer to the next record to format and output,
         * to be passed to the @ref regular_show "show() handler" as
@@ -573,6 +594,8 @@ static inline int xnvfile_link_p(struct xnvfile *entry)
                .pde = NULL,            \
                .parent = NULL,         \
                .private = NULL,        \
+               .file = NULL,           \
+               .refcnt = 0,            \
        }
 
 #define xnvfile_nodir  { .entry = xnvfile_noentry }
@@ -581,6 +604,8 @@ static inline int xnvfile_link_p(struct xnvfile *entry)
 
 #define xnvfile_parent(e)              ((e)->entry.parent)
 #define xnvfile_priv(e)                        ((e)->entry.private)
+#define xnvfile_nref(e)                        ((e)->entry.refcnt)
+#define xnvfile_file(e)                        ((e)->entry.file)
 #define xnvfile_iterator_priv(it)      ((void *)(&(it)->private))
 
 extern struct xnvfile_nklock_class xnvfile_nucleus_lock;
diff --git a/ksrc/nucleus/vfile.c b/ksrc/nucleus/vfile.c
index b7a0774..896b17b 100644
--- a/ksrc/nucleus/vfile.c
+++ b/ksrc/nucleus/vfile.c
@@ -174,11 +174,15 @@ static int vfile_snapshot_open(struct inode *inode, 
struct file *file)
                return 0;
        }
 
+       if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
+               return -EBUSY;
+
        it = kzalloc(sizeof(*it) + vfile->privsz, GFP_KERNEL);
        if (it == NULL)
                return -ENOMEM;
 
        it->vfile = vfile;
+       xnvfile_file(vfile) = file;
 
        ret = vfile->entry.lockops->get(&vfile->entry);
        if (ret)
@@ -290,6 +294,7 @@ finish:
        seq = file->private_data;
        it->seq = seq;
        seq->private = it;
+       xnvfile_nref(vfile)++;
 
        return 0;
 }
@@ -302,6 +307,8 @@ static int vfile_snapshot_release(struct inode *inode, 
struct file *file)
        if (seq) {
                it = seq->private;
                if (it) {
+                       --xnvfile_nref(it->vfile);
+                       XENO_BUGON(NUCLEUS, it->vfile->entry.refcnt < 0);
                        if (it->databuf)
                                it->endfn(it, it->databuf);
                        kfree(it);
@@ -500,8 +507,10 @@ static int vfile_regular_open(struct inode *inode, struct 
file *file)
        struct seq_file *seq;
        int ret;
 
-       if ((file->f_mode & FMODE_WRITE) != 0 &&
-           ops->store == NULL)
+       if ((file->f_flags & O_EXCL) != 0 && xnvfile_nref(vfile) > 0)
+               return -EBUSY;
+
+       if ((file->f_mode & FMODE_WRITE) != 0 && ops->store == NULL)
                return -EACCES;
 
        if ((file->f_mode & FMODE_READ) == 0) {
@@ -515,16 +524,25 @@ static int vfile_regular_open(struct inode *inode, struct 
file *file)
 
        it->vfile = vfile;
        it->pos = -1;
+       xnvfile_file(vfile) = file;
 
-       ret = seq_open(file, &vfile_regular_ops);
-       if (ret) {
-               kfree(it);
-               return ret;
+       if (ops->rewind) {
+               ret = ops->rewind(it);
+               if (ret) {
+               fail:
+                       kfree(it);
+                       return ret;
+               }
        }
 
+       ret = seq_open(file, &vfile_regular_ops);
+       if (ret)
+               goto fail;
+
        seq = file->private_data;
        it->seq = seq;
        seq->private = it;
+       xnvfile_nref(vfile)++;
 
        return 0;
 }
@@ -536,8 +554,11 @@ static int vfile_regular_release(struct inode *inode, 
struct file *file)
 
        if (seq) {
                it = seq->private;
-               if (it)
+               if (it) {
+                       --xnvfile_nref(it->vfile);
+                       XENO_BUGON(NUCLEUS, xnvfile_nref(it->vfile) < 0);
                        kfree(it);
+               }
 
                return seq_release(inode, file);
        }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to