]> err.no Git - linux-2.6/blobdiff - fs/relayfs/relay.c
Merge branch 'drm-forlinus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6] / fs / relayfs / relay.c
index 16446a15c96d956d84d83859a0660f4a8736bc29..abf3ceaace4916822cbd91ba233c2709d43cae91 100644 (file)
@@ -80,11 +80,34 @@ static void buf_unmapped_default_callback(struct rchan_buf *buf,
 {
 }
 
+/*
+ * create_buf_file_create() default callback.  Creates file to represent buf.
+ */
+static struct dentry *create_buf_file_default_callback(const char *filename,
+                                                      struct dentry *parent,
+                                                      int mode,
+                                                      struct rchan_buf *buf,
+                                                      int *is_global)
+{
+       return relayfs_create_file(filename, parent, mode,
+                                  &relay_file_operations, buf);
+}
+
+/*
+ * remove_buf_file() default callback.  Removes file representing relay buffer.
+ */
+static int remove_buf_file_default_callback(struct dentry *dentry)
+{
+       return relayfs_remove(dentry);
+}
+
 /* relay channel default callbacks */
 static struct rchan_callbacks default_channel_callbacks = {
        .subbuf_start = subbuf_start_default_callback,
        .buf_mapped = buf_mapped_default_callback,
        .buf_unmapped = buf_unmapped_default_callback,
+       .create_buf_file = create_buf_file_default_callback,
+       .remove_buf_file = remove_buf_file_default_callback,
 };
 
 /**
@@ -148,14 +171,16 @@ static inline void __relay_reset(struct rchan_buf *buf, unsigned int init)
 void relay_reset(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                __relay_reset(chan->buf[i], 0);
+               prev = chan->buf[i];
        }
 }
 
@@ -166,17 +191,27 @@ void relay_reset(struct rchan *chan)
  */
 static struct rchan_buf *relay_open_buf(struct rchan *chan,
                                        const char *filename,
-                                       struct dentry *parent)
+                                       struct dentry *parent,
+                                       int *is_global)
 {
        struct rchan_buf *buf;
        struct dentry *dentry;
 
+       if (*is_global)
+               return chan->buf[0];
+
+       buf = relay_create_buf(chan);
+       if (!buf)
+               return NULL;
+
        /* Create file in fs */
-       dentry = relayfs_create_file(filename, parent, S_IRUSR, chan);
-       if (!dentry)
+       dentry = chan->cb->create_buf_file(filename, parent, S_IRUSR,
+                                          buf, is_global);
+       if (!dentry) {
+               relay_destroy_buf(buf);
                return NULL;
+       }
 
-       buf = RELAYFS_I(dentry->d_inode)->buf;
        buf->dentry = dentry;
        __relay_reset(buf, 1);
 
@@ -214,6 +249,10 @@ static inline void setup_callbacks(struct rchan *chan,
                cb->buf_mapped = buf_mapped_default_callback;
        if (!cb->buf_unmapped)
                cb->buf_unmapped = buf_unmapped_default_callback;
+       if (!cb->create_buf_file)
+               cb->create_buf_file = create_buf_file_default_callback;
+       if (!cb->remove_buf_file)
+               cb->remove_buf_file = remove_buf_file_default_callback;
        chan->cb = cb;
 }
 
@@ -241,6 +280,7 @@ struct rchan *relay_open(const char *base_filename,
        unsigned int i;
        struct rchan *chan;
        char *tmpname;
+       int is_global = 0;
 
        if (!base_filename)
                return NULL;
@@ -265,7 +305,8 @@ struct rchan *relay_open(const char *base_filename,
 
        for_each_online_cpu(i) {
                sprintf(tmpname, "%s%d", base_filename, i);
-               chan->buf[i] = relay_open_buf(chan, tmpname, parent);
+               chan->buf[i] = relay_open_buf(chan, tmpname, parent,
+                                             &is_global);
                chan->buf[i]->cpu = i;
                if (!chan->buf[i])
                        goto free_bufs;
@@ -279,6 +320,8 @@ free_bufs:
                if (!chan->buf[i])
                        break;
                relay_close_buf(chan->buf[i]);
+               if (is_global)
+                       break;
        }
        kfree(tmpname);
 
@@ -333,8 +376,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
        return length;
 
 toobig:
-       printk(KERN_WARNING "relayfs: event too large (%Zd)\n", length);
-       WARN_ON(1);
+       buf->chan->last_toobig = length;
        return 0;
 }
 
@@ -389,16 +431,23 @@ void relay_destroy_channel(struct kref *kref)
 void relay_close(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                relay_close_buf(chan->buf[i]);
+               prev = chan->buf[i];
        }
 
+       if (chan->last_toobig)
+               printk(KERN_WARNING "relayfs: one or more items not logged "
+                      "[item size (%Zd) > sub-buffer size (%Zd)]\n",
+                      chan->last_toobig, chan->subbuf_size);
+
        kref_put(&chan->kref, relay_destroy_channel);
 }
 
@@ -411,14 +460,16 @@ void relay_close(struct rchan *chan)
 void relay_flush(struct rchan *chan)
 {
        unsigned int i;
+       struct rchan_buf *prev = NULL;
 
        if (!chan)
                return;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (!chan->buf[i])
-                       continue;
+               if (!chan->buf[i] || chan->buf[i] == prev)
+                       break;
                relay_switch_subbuf(chan->buf[i], 0);
+               prev = chan->buf[i];
        }
 }