relayFS question: calling relay_write() from interrupt context does not write to file - why ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I am trying to use relayFS from an interrupt context. I read the
documentation and downloaded and ran successfully the examples from
http://relayfs.sourceforge.net.

I am running on Fedora 6 machine with 2.6.18-1.2798.fc6 kernel (no patches).
I have two years of experience in linux kernel programming.

I am mounting successfully debugfs on /debug.

According to relay.txt from the Linux documentation,
relay_write() should be used if you might be logging from interrupt context.

My module needs to write from interrupt context (in fact, it is a soft
interrupt) so I tried using relay_write.

My user space application try to read the relayFS files using read, not mmap,
following the read-mod kernel module from the examples (which I tried
successfully).

What happens that when I try reading the relayFS files (by cat, which
eventually uses read) which I generated
from interrupt context in my module, I get nothing;
while when trying files which are generated
from a kernel thread with relay_write, I do succeed with reading these
files using cat.
I am attaching the code for the test module I wrote and I hope you can
take a look at it; I simplified it and removed away everything which is
not connected directly to my question.
What happens is, in fact: when calling start_test_thread_new() we DO succeed to
read the file with cat /debug/testTree/cpu0, whereas when
using the second alternative, meaning calling directly test_thread_new()
from the main_hook() (which runs in software interrupt context) we
do not read anything (cat /debug/testTree/cpu0 shows nothing; there is,however,
no segfault when running "cat /debug/testTree/cpu0" in that case).

here below is test.c, a short module which I wrote demonstarting this
problem.


Any ideas?

Regards,
Rami Rosen



// test.c

#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/compiler.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/byteorder/generic.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/spinlock.h>
#include <net/ip.h>
#include <linux/vmalloc.h>
#include <linux/debugfs.h>
#include <linux/relay.h>
#include <linux/kthread.h>


#define MAX_EVENT_SIZE 256


struct dentry *dir;
struct rchan *channel;
static struct completion done;
static int hooksRegistered = 0;
static struct task_struct *kthread_thread;

static int test_thread_new(void *unused)
{
	int i,count;
	char buf[MAX_EVENT_SIZE + 1];

	for (i = 0; i < 10; i++) {
			count = snprintf(buf, MAX_EVENT_SIZE,
				"[%08i]test event\n", i);
	
			relay_write(channel, buf, count);
	}
	return 0;
}


static void start_test_thread_new(void)
{
	int cpu = 0;
	struct task_struct *p;
	printk("in start_test_thread_new\n");
	init_completion(&done);
	
	p = kthread_create(test_thread_new, NULL, "%s/%d", "test", cpu);
	if (IS_ERR(p))
		return;
	if (p) {
		kthread_bind(p, cpu);
		wake_up_process(p);
		kthread_thread = p;
	}

}



static int test_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
                                     void *prev_subbuf, size_t prev_padding)
{
	if (relay_buf_full(buf))
		{
		printk("buffer full\n");	
		return 0;
		}

	return 1;
		
}

static int test_remove_buf_file_callback(struct dentry *dentry)
{
	 debugfs_remove(dentry);
	 return 0;
}


static struct dentry *test_create_buf_file_callback(const char *filename,
                                                   struct dentry *parent,
                                                   int mode,
                                                   struct rchan_buf *buf,
                                                   int *is_global)
{
	 return debugfs_create_file(filename, mode, parent, buf,
                                   &relay_file_operations);
}

static struct nf_hook_ops netfilter_ops_in;
	
static int inithook(void);

//////////////////////////////////////////////////////////////////////////////	


unsigned int main_hook(unsigned int hooknum,
											 struct sk_buff** skb,
											 const struct net_device* in,
											 const struct net_device* out,
											 int (*okfn)(struct sk_buff*))
 {
	static int counter=0;
	void *unused=NULL;
	counter++;	
	printk("in main_hook counter=%d\n",counter);
	test_thread_new(unused);
	return NF_ACCEPT;
	}
	
//////////////////////////////////////////////////////////////////////////////

static int inithook()
{
	int i;
	printk("starting inithook\n");

	netfilter_ops_in.hook     = main_hook;
	netfilter_ops_in.pf       = PF_INET;	
	netfilter_ops_in.hooknum  = NF_IP_PRE_ROUTING;
	netfilter_ops_in.priority = NF_IP_PRI_FIRST;
	nf_register_hook(&netfilter_ops_in);

	hooksRegistered = 1;
	printk(KERN_INFO "ioctl_init finished OK \n");
	
	return 0;
	}


//////////////////////////////////////////////////////////////////////////////
	
	
	
static int __init test_init(void)
	{
	int ret;
	int j;
	int res;
	
	printk("starting test_init \n");
		{
		static struct rchan_callbacks blk_relay_callbacks = {
        .subbuf_start           = test_subbuf_start_callback,
        .create_buf_file        = test_create_buf_file_callback,
        .remove_buf_file        = test_remove_buf_file_callback,
		};
		
		dir = debugfs_create_dir("testTree",0);
		if (!dir)
			{
			printk("debugfs_create_dir failed!\n");
			}
		else
			printk("debugfs_create_dir succeeded!\n");

		channel=relay_open("cpu",
						 					  dir,
												262144,
												4,
												&blk_relay_callbacks);
		if (!(channel))
			{
			printk("relay_open() failed!\n");
			return -1;
			}

		}
	res = inithook();
	// start_test_thread_new();
	if (res==-1)
			return -1;
	return 0;
	}

//////////////////////////////////////////////////////////////////////////////

static void __exit test_exit(void)
	{
	if (hooksRegistered)
		nf_unregister_hook(&netfilter_ops_in);
	if (channel)
		relay_close(channel);	
	if (dir)
			debugfs_remove(dir);
	printk("test_exit finished \n");
	}
	
//////////////////////////////////////////////////////////////////////////////

module_init(test_init)
module_exit(test_exit)

MODULE_AUTHOR("test");
MODULE_DESCRIPTION("test");
MODULE_LICENSE("GPL");
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux