Skip to contentSkip to conversation

relayfs redux for 2.6.10: lean and mean

PATCH In review Karim Yaghmour 6 participants 15 messages Jan 20, 2005 – Feb 7, 2005 VFS

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 relayfs redux for 2.6.10: lean and mean

I've reworked the relayfs patch extensively. The API and internals have been heavily purged. The patch is in fact almost HALF! its original size, loosing 90KB and going from 200KB to 110KB.

Here's a summary of changes:
- Dropped the lockless scheme (complaints from Christoph, Arjan, Ingo, Andrew, etc. regarding the debatable efficiency of cmpxchng over traditional locks.)
- Dropped the resizing capabilities (Andi, Christoph, etc.)
- Dropped all user-space read/write capabilities (Andi, Christoph, Roman, Tim, etc.) Basically this is about making relayfs do one thing and do it good: transfer high volumes of data to user-space as efficiently as possible.
- Implemented the ad-hoc mode. This mode contrasts with the managed mode (old locking scheme) in that it manages only one ring buffer, doesn't care about outside synchronization, and is basically the most basic buffer scheme one could have. (ongoing discussion with Roman on this issue.)
- Dropped the klog client (Greg).
- Modified API to use pointers instead of IDs (Roman).
- Miscallaneous cleanups (Domen).
- Miscallaneous rearrangement of code (me).

I've tested this with a hacked ltt patch and I can get it to collect data in the managed mode without a problem. Reading the data though is another story, I'll update the LTT patch once I know where the relayfs stuff is heading.
Beware: don't try to use the ltt code in Andrew's tree with this relayfs, it's a completely different beast.

So without further ado, here's the code. I've removed the Documentation/filesystems/relayfs.txt file for now (no, don't worry that's not part of the 90KB that went away ;). It's probably going to need some rewriting before we're done, so let's not get distracted by it for now.

Karim

The full patch is here:
http://www.opersys.com/ftp/pub/relayfs/patch-relayfs-redux-2.6.10-050120-real
http://www.opersys.com/ftp/pub/relayfs/patch-relayfs-redux-2.6.10-050120-real.bz2

diffstat:

 fs/Kconfig                            |   18
 fs/Makefile                           |    4
 fs/relayfs/Makefile                   |    8
 fs/relayfs/buffers.c                  |  202 +++++
 fs/relayfs/buffers.h                  |   33
 fs/relayfs/inode.c                    |  520 ++++++++++++++
 fs/relayfs/relay.c                    | 1193 ++++++++++++++++++++++++++++++++++
 fs/relayfs/relay.h                    |   62 +
 fs/relayfs/relay_adhoc.c              |  109 +++
 fs/relayfs/relay_adhoc.h              |   26
 fs/relayfs/relay_managed.c            |  270 +++++++
 fs/relayfs/relay_managed.h            |   26
 include/linux/relayfs_fs.h            |  378 ++++++++++
 14 files changed, 3659 insertions(+), 2 deletions(-)
fs/Kconfig +18 -0
@@ -972,6 +972,24 @@ config RAMFS
 	  To compile this as a module, choose M here: the module will be called
 	  ramfs.
 
+config RELAYFS_FS
+	tristate "Relayfs file system support"
+	---help---
+	  Relayfs is a high-speed data relay filesystem designed to provide
+	  an efficient mechanism for tools and facilities to relay large
+	  amounts of data from kernel space to user space.  It's not useful
+	  on its own, and should only be enabled if other facilities that
+	  need it are enabled, such as for example the Linux Trace Toolkit.
+
+	  See <file:Documentation/filesystems/relayfs.txt> for further
+	  information.
+
+	  This file system is also available as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module is called relayfs.  If you want to compile it as a
+	  module, say M here and read <file:Documentation/modules.txt>.
+	  If unsure, say N.
+
 endmenu
 
 menu "Miscellaneous filesystems"
fs/Makefile +2 -2
@@ -1,5 +1,4 @@
-#
-# Makefile for the Linux filesystems.
+## Makefile for the Linux filesystems.
 #
 # 14 Sep 2000, Christoph Hellwig <[email protected]>
 # Rewritten to use lists instead of if-statements.
@@ -53,6 +52,7 @@ obj-$(CONFIG_EXT2_FS)		+= ext2/
 obj-$(CONFIG_CRAMFS)		+= cramfs/
 obj-$(CONFIG_RAMFS)		+= ramfs/
 obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
+obj-$(CONFIG_RELAYFS_FS)	+= relayfs/
 obj-$(CONFIG_CODA_FS)		+= coda/
 obj-$(CONFIG_MINIX_FS)		+= minix/
 obj-$(CONFIG_FAT_FS)		+= fat/
fs/relayfs/buffers.c +202 -0

202 lines not on this page · raw message

fs/relayfs/buffers.h +33 -0
@@ -0,0 +1,33 @@
+#ifndef _BUFFERS_H
+#define _BUFFERS_H
+
+/* This inspired by rtai/shmem */
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE
+
+/*
+ * Used for deferring resized channel free
+ */
+struct free_rchan_buf
+{
+	char *unmap_buf;
+	struct
+	{
+		struct page **array;
+		int count;
+	} page_array[3];
+
+	int cur;
+	struct work_struct work;	/* de-allocation work struct */
+};
+
+extern void *
+alloc_rchan_buf(unsigned long size,
+		struct page ***page_array,
+		int *page_count);
+
+extern int
+free_rchan_buf(void *buf,
+	       struct page **page_array,
+	       int page_count);
+
+#endif/* _BUFFERS_H */
fs/relayfs/inode.c +520 -0

520 lines not on this page · raw message

fs/relayfs/Makefile +8 -0
@@ -0,0 +1,8 @@
+#
+# relayfs Makefile
+#
+
+obj-$(CONFIG_RELAYFS_FS) += relayfs.o
+
+relayfs-y := relay.o buffers.o relay_managed.o relay_adhoc.o inode.o
+
fs/relayfs/relay_adhoc.c +109 -0

109 lines not on this page · raw message

fs/relayfs/relay_adhoc.h +26 -0
@@ -0,0 +1,26 @@
+#ifndef _RELAY_ADHOC_H
+#define _RELAY_ADHOC_H
+
+extern char *
+adhoc_reserve(struct rchan *rchan,
+		u32 slot_len,
+		int *err,
+		int *interrupting);
+
+extern void
+adhoc_commit(struct rchan *rchan,
+	       char *from,
+	       u32 len,
+	       int deliver,
+	       int interrupting);
+
+extern void
+adhoc_finalize(struct rchan *rchan);
+
+extern u32
+adhoc_get_offset(struct rchan *rchan, u32 *max_offset);
+
+extern void
+adhoc_reset(struct rchan *rchan, int init);
+
+#endif	/* _RELAY_ADHOC_H */
fs/relayfs/relay.c +1193 -0

1,193 lines not on this page · raw message

fs/relayfs/relay.h +62 -0

62 lines not on this page · raw message

fs/relayfs/relay_managed.c +270 -0

270 lines not on this page · raw message

fs/relayfs/relay_managed.h +26 -0
@@ -0,0 +1,26 @@
+#ifndef _RELAY_MANAGED_H
+#define _RELAY_MANAGED_H
+
+extern char *
+managed_reserve(struct rchan *rchan,
+		u32 slot_len,
+		int *err,
+		int *interrupting);
+
+extern void
+managed_commit(struct rchan *rchan,
+	       char *from,
+	       u32 len,
+	       int deliver,
+	       int interrupting);
+
+extern void
+managed_finalize(struct rchan *rchan);
+
+extern u32
+managed_get_offset(struct rchan *rchan, u32 *max_offset);
+
+extern void
+managed_reset(struct rchan *rchan, int init);
+
+#endif	/* _RELAY_MANAGED_H */
include/linux/relayfs_fs.h +378 -0

378 lines not on this page · raw message

#1 lore raw
Quoted 4 lines · Karim Yaghmour

I've reworked the relayfs patch extensively. The API and internals have been heavily purged. The patch is in fact almost HALF! its original size, loosing 90KB and going from 200KB to 110KB.

Hm, how about this idea for cutting about 500 more lines from the code:

Why not drop the "fs" part of relayfs and just make the code a set of struct file_operations. That way you could have "relayfs-like" files in any ram based file system that is being used. Then, a user could use these fops and assorted interface to create debugfs or even procfs files using this type of interface.

As relayfs really is almost the same (conceptually wise) as debugfs as far as concept of what kinds of files will be in there (nothing anyone would ever rely on for normal operations, but for debugging only) this keeps users and developers from having to spread their debugging and instrumenting files from accross two different file systems.

Just an idea...

thanks,

greg k-h

#2 lore raw
Quoted 8 lines · Greg KH

Hm, how about this idea for cutting about 500 more lines from the code:

Why not drop the "fs" part of relayfs and just make the code a set of struct file_operations. That way you could have "relayfs-like" files in any ram based file system that is being used. Then, a user could use these fops and assorted interface to create debugfs or even procfs files using this type of interface.

Quoted 5 lines

As relayfs really is almost the same (conceptually wise) as debugfs as far as concept of what kinds of files will be in there (nothing anyone would ever rely on for normal operations, but for debugging only) this keeps users and developers from having to spread their debugging and instrumenting files from accross two different file systems.

However this assumes that the users of relayfs are not going to want it during normal system operation. This is an assumption that fails with at least LTT as it is targeted at sysadmins, application developers and power users who need to be able to trace their systems at any time.

I don't mind piggy-backing off another fs, if it makes sense, but unlike debugfs, relayfs is meant for general use, and all files in there are of the same type: relay channels for dumping huge amounts of data to user-space. It seems to me the target audience and basic idea (relay channels only in the fs) are different, but let me know if there's a compeling argument for doing this in another way without making it too confusing for users of those special "files" (IOW, when this starts being used in distros, it'll be more straightforward for users to understand if all files in a mounted fs behave a certain way than if they have certain "odd" files in certain directories, even if it's /proc.)

Karim

Signature · 3 lines
Author, Speaker, Developer, Consultant
Pushing Embedded and Real-Time Linux Systems Beyond the Limits
http://www.opersys.com || [email protected] || 1-866-677-4546
#3 lore raw
Quoted 22 lines · Karim Yaghmour
Quoted 8 lines · Greg KH

Hm, how about this idea for cutting about 500 more lines from the code:

Why not drop the "fs" part of relayfs and just make the code a set of struct file_operations. That way you could have "relayfs-like" files in any ram based file system that is being used. Then, a user could use these fops and assorted interface to create debugfs or even procfs files using this type of interface.

Quoted 5 lines

As relayfs really is almost the same (conceptually wise) as debugfs as far as concept of what kinds of files will be in there (nothing anyone would ever rely on for normal operations, but for debugging only) this keeps users and developers from having to spread their debugging and instrumenting files from accross two different file systems.

However this assumes that the users of relayfs are not going to want it during normal system operation. This is an assumption that fails with at least LTT as it is targeted at sysadmins, application developers and power users who need to be able to trace their systems at any time.

Quoted 11 lines

I don't mind piggy-backing off another fs, if it makes sense, but unlike debugfs, relayfs is meant for general use, and all files in there are of the same type: relay channels for dumping huge amounts of data to user-space. It seems to me the target audience and basic idea (relay channels only in the fs) are different, but let me know if there's a compeling argument for doing this in another way without making it too confusing for users of those special "files" (IOW, when this starts being used in distros, it'll be more straightforward for users to understand if all files in a mounted fs behave a certain way than if they have certain "odd" files in certain directories, even if it's /proc.)

Perhaps the logical solution is to implement debugfs in terms of relayfs?

Peter

Signature · 4 lines
Peter Williams                                   [email protected]

"Learning, n. The kind of ignorance distinguishing the studious."
 -- Ambrose Bierce
#4 lore raw
Quoted 2 lines · Peter Williams

Perhaps the logical solution is to implement debugfs in terms of relayfs?

What do you mean by this statement?

greg k-h

#5 lore raw
Quoted 6 lines · Greg KH
Quoted 1 line · Peter Williams

Perhaps the logical solution is to implement debugfs in terms of relayfs?

What do you mean by this statement?

I mean that if, as you say, debugfs is very similar to relayfs only more restricted (i.e. a debugging option) then it should be implementable as an instance or specialization of the more general relayfs and that this should be a better solution than two independent implementations of similar functionality.

Peter

Signature · 4 lines
Peter Williams                                   [email protected]

"Learning, n. The kind of ignorance distinguishing the studious."
 -- Ambrose Bierce
#6 lore raw
Quoted 6 lines · Peter Williams
Quoted 5 lines · Greg KH
Quoted 1 line · Peter Williams

Perhaps the logical solution is to implement debugfs in terms of relayfs?

Quoted 7 lines
Quoted 1 line

What do you mean by this statement?

I mean that if, as you say, debugfs is very similar to relayfs only more restricted (i.e. a debugging option) then it should be implementable as an instance or specialization of the more general relayfs and that this should be a better solution than two independent implementations of similar functionality.

Ah.

No.

The implementations are not of the same functionality, or so Karim says.

thanks,

greg k-h

#7 lore raw
In reply to Karim Yaghmour
Quoted 10 lines · Karim Yaghmour
Quoted 8 lines · Greg KH

Hm, how about this idea for cutting about 500 more lines from the code:

Why not drop the "fs" part of relayfs and just make the code a set of struct file_operations. That way you could have "relayfs-like" files in any ram based file system that is being used. Then, a user could use these fops and assorted interface to create debugfs or even procfs files using this type of interface.

Quoted 8 lines
Quoted 5 lines

As relayfs really is almost the same (conceptually wise) as debugfs as far as concept of what kinds of files will be in there (nothing anyone would ever rely on for normal operations, but for debugging only) this keeps users and developers from having to spread their debugging and instrumenting files from accross two different file systems.

However this assumes that the users of relayfs are not going to want it during normal system operation.

That is true.

Quoted 3 lines

This is an assumption that fails with at least LTT as it is targeted at sysadmins, application developers and power users who need to be able to trace their systems at any time.

Are they willing to trade off the performance of LTT to get this? I thought this was being touted as a "when you need to test" type of thing, not a "run it all the time" type of feature.

Quoted 4 lines

I don't mind piggy-backing off another fs, if it makes sense, but unlike debugfs, relayfs is meant for general use, and all files in there are of the same type: relay channels for dumping huge amounts of data to user-space.

And a driver will never want to have both a relay channel, and a simple debug output at the same time? You are now requiring them to look for that data in two different points in the fs.

Quoted 8 lines

It seems to me the target audience and basic idea (relay channels only in the fs) are different, but let me know if there's a compeling argument for doing this in another way without making it too confusing for users of those special "files" (IOW, when this starts being used in distros, it'll be more straightforward for users to understand if all files in a mounted fs behave a certain way than if they have certain "odd" files in certain directories, even if it's /proc.)

So, since you are proposing that relayfs be mounted all the time, where do you want to mount it at? I had to provide a "standard" location for debugfs for people to be happy with it, and the same issue comes up here.

Also, why not export your relayfs ops so that someone useing debugfs can create a relay channel in it, or in any other type of fs they might create?

thanks,

greg k-h

#8 lore raw
Quoted 3 lines · Greg KH

Are they willing to trade off the performance of LTT to get this? I thought this was being touted as a "when you need to test" type of thing, not a "run it all the time" type of feature.

The problem is that you never know beforehand when you're going to get that weird glitch on your server, or how much time you're going to need to reproduce it. People who manage thousands of servers will want to be able to fire this off at will without having to reboot/recompile their kernel. What has to be done is make the cost of the tracing infrastructure as minimal as possible when it is indeed built into the kernel (of course if it's disabled it should cost the same thing as if it wasn't there to boot: nothing.) This, though, is a separate topic which is being addressed in other threads. Have a look at Werner's resent postings if you're interested on the "[RFC] instrumentation" thread.

Quoted 3 lines

And a driver will never want to have both a relay channel, and a simple debug output at the same time? You are now requiring them to look for that data in two different points in the fs.

[snip]

Quoted 8 lines

So, since you are proposing that relayfs be mounted all the time, where do you want to mount it at? I had to provide a "standard" location for debugfs for people to be happy with it, and the same issue comes up here.

Also, why not export your relayfs ops so that someone useing debugfs can create a relay channel in it, or in any other type of fs they might create?

Ok, there are a couple of things in there:

- First I don't object to having the relayfs ops being exported so that they could be used in conjunction with other filesystems, in addition to having relayfs live as an independent fs. So as in the case above, we should be able to accomodate the device driver writer who wants to have all his files in the same fs. However, for the first case relayfs was built for, I think there is merit for having it live as a separate fs. Is this a good compromise for you?

- As for where relayfs should be mounted, then this is a very good question. We've taken to the habit of having a /relayfs. If this is too problematic, I don't see any problem with /mnt/relayfs also. In either case, I have to admit frankly that I'm not familiar with the exact formal rules for introducing something like this. Of course I'm aware of the FHS and LSB, but let me know what you think is the best way to proceed here.

Thanks,

Karim

Signature · 3 lines
Author, Speaker, Developer, Consultant
Pushing Embedded and Real-Time Linux Systems Beyond the Limits
http://www.opersys.com || [email protected] || 1-866-677-4546
#9 lore raw
In reply to Karim Yaghmour

fs/relayfs/inode.c line 55

Quoted 11 lines · Karim Yaghmour
fs/relayfs/inode.c +11 -0
+static struct inode *
+relayfs_get_inode(struct super_block *sb, int mode, dev_t dev)
+{
+	struct inode * inode;
+
+	inode = new_inode(sb);
+
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;

Are you sure you want these two fields set to the value of current-> ?

fs/relayfs/inode.c line 94

Quoted 11 lines
fs/relayfs/inode.c +11 -0
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+/* SMP-safe */
+static int
+relayfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+	struct inode * inode;
+	int error = -ENOSPC;
+
+	inode = relayfs_get_inode(dir->i_sb, mode, dev);

Need to check for dentry->d_inode here before using it.

Quoted 4 lines
fs/relayfs/inode.c +4 -0
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);	/* Extra count - pin the dentry in core */
+		error = 0;

fs/relayfs/inode.c line 109

Quoted 10 lines
fs/relayfs/inode.c +10 -0
+	}
+	return error;
+}
+
+static int
+relayfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	int retval;
+
+	retval = relayfs_mknod(dir, dentry, mode | S_IFDIR, 0);

(mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR
instead of just | with S_IFDIR, right?

fs/relayfs/inode.c line 119

Quoted 10 lines
fs/relayfs/inode.c +10 -0
+
+	if (!retval)
+		dir->i_nlink++;
+	return retval;
+}
+
+static int
+relayfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+{
+	return relayfs_mknod(dir, dentry, mode | S_IFREG, 0);

(mode & S_IALLUGO) | S_IFREG
here too, to be safe, right?

Quoted 11 lines
fs/relayfs/inode.c +11 -0
+}
+
+static int
+relayfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	struct inode *inode;
+	int error = -ENOSPC;
+
+	inode = relayfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+
+	if (inode) {

fs/relayfs/inode.c line 140

Quoted 10 lines
fs/relayfs/inode.c +10 -0
+		int l = strlen(symname)+1;
+		error = page_symlink(inode, symname, l);
+		if (!error) {
+			d_instantiate(dentry, inode);
+			dget(dentry);
+		} else
+			iput(inode);
+	}
+	return error;
+}

Why do you want to allow symlinks in relayfs?

Quoted 46 lines
fs/relayfs/inode.c +46 -0
+
+/**
+ *	relayfs_create_entry - create a relayfs directory or file
+ *	@name: the name of the file to create
+ *	@parent: parent directory
+ *	@dentry: result dentry
+ *	@entry_type: type of file to create (S_IFREG, S_IFDIR)
+ *	@mode: mode
+ *	@data: data to associate with the file
+ *
+ *	Creates a file or directory with the specifed permissions.
+ */
+static int
+relayfs_create_entry(const char * name, struct dentry * parent, struct dentry **dentry, int entry_type, int mode, void * data)
+{
+	struct qstr qname;
+	struct dentry * d;
+
+	int error = 0;
+
+	error = simple_pin_fs("relayfs", &relayfs_mount, &relayfs_mount_count);
+	if (error) {
+		printk(KERN_ERR "Couldn't mount relayfs: errcode %d\n", error);
+		return error;
+	}
+
+	qname.name = name;
+	qname.len = strlen(name);
+	qname.hash = full_name_hash(name, qname.len);
+
+	if (parent == NULL)
+		if (relayfs_mount && relayfs_mount->mnt_sb)
+			parent = relayfs_mount->mnt_sb->s_root;
+
+	if (parent == NULL) {
+		simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+ 		return -EINVAL;
+	}
+
+	parent = dget(parent);
+	down(&parent->d_inode->i_sem);
+	d = lookup_hash(&qname, parent);
+	if (IS_ERR(d)) {
+		error = PTR_ERR(d);
+		goto release_mount;
+	}

fs/relayfs/inode.c line 196

Quoted 10 lines
fs/relayfs/inode.c +10 -0
+
+	if (d->d_inode) {
+		error = -EEXIST;
+		goto release_mount;
+	}
+
+	if (entry_type == S_IFREG)
+		error = relayfs_create(parent->d_inode, d, entry_type | mode, NULL);
+	else
+		error = relayfs_mkdir(parent->d_inode, d, entry_type | mode);

Why not just go off of the mode here? That would let you get rid of a paramater, as you need mode to be set properly anyway for directories.

fs/relayfs/inode.c line 203

Quoted 7 lines
fs/relayfs/inode.c +7 -0
+	if (error)
+		goto release_mount;
+
+	if ((entry_type == S_IFREG) && data) {
+		d->d_inode->u.generic_ip = data;
+		goto exit; /* don't release mount for regular files */
+	}

Same here.

thanks,

greg k-h

#10 lore raw
In reply to Karim Yaghmour

fs/Kconfig config RAMFS · line 985

Quoted 11 lines · Karim Yaghmour
fs/Kconfig +11 -0
+config RELAYFS_FS
+	tristate "Relayfs file system support"
+	---help---
+	  Relayfs is a high-speed data relay filesystem designed to provide
+	  an efficient mechanism for tools and facilities to relay large
+	  amounts of data from kernel space to user space.  It's not useful
+	  on its own, and should only be enabled if other facilities that
+	  need it are enabled, such as for example the Linux Trace Toolkit.
+
+	  See <file:Documentation/filesystems/relayfs.txt> for further
+	  information.

Please remove the above if you don't include the file in this patch.

fs/Makefile line 1

Quoted 7 lines

menu "Miscellaneous filesystems"

fs/Makefile +1 -2
@@ -1,5 +1,4 @@
-#
-# Makefile for the Linux filesystems.
+## Makefile for the Linux filesystems.

Please remove the patch noise above.

Quoted 20 lines
fs/Makefile +20 -0
+/**
+ *	alloc_page_array - alloc array to hold pages, but not pages
+ *	@size: the total size of the memory represented by the page array
+ *	@page_count: the number of pages the array can hold
+ *	@err: 0 on success, negative otherwise
+ *
+ *	Returns a pointer to the page array if successful, NULL otherwise.
+ */
+static struct page **
+alloc_page_array(int size, int *page_count, int *err)
+{
+	int n_pages;
+	struct page **page_array;
+	int page_array_size;
+
+	*err = 0;
+
+	size = PAGE_ALIGN(size);
+	n_pages = size >> PAGE_SHIFT;
+	page_array_size = n_pages * sizeof(struct page *);

fs/Makefile

Quoted 10 lines
fs/Makefile +10 -0
+	page_array = kmalloc(page_array_size, GFP_KERNEL);
+	if (page_array == NULL) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+	*page_count = n_pages;
+	memset(page_array, 0, page_array_size);
+
+	return page_array;
+}

err parameter seems overkill as you can simply return NULL when failing. Furthermore this allocator looks a lot like kcalloc(). As there's only one caller for this function, please switch to kcalloc and inline this method to the caller.

fs/Makefile

Quoted 10 lines
fs/Makefile +10 -0
+
+/**
+ *	free_page_array - free array to hold pages, but not pages
+ *	@page_array: pointer to the page array
+ */
+static inline void
+free_page_array(struct page **page_array)
+{
+	kfree(page_array);
+}

Please remove this useless wrapper and inline kfree() in the code.

fs/Makefile

Quoted 11 lines
fs/Makefile +11 -0
+/**
+ *	relaybuf_free - free a resized channel buffer
+ *	@private: pointer to the channel struct
+ *
+ *	Internal - manages the de-allocation and unmapping of old channel
+ *	buffers.
+ */
+static void
+relaybuf_free(void *private)
+{
+	struct free_rchan_buf *free_buf = (struct free_rchan_buf *)private;

Please remove the redundant cast.

fs/Makefile

Quoted 10 lines
fs/Makefile +10 -0
+/**
+ *     remove_rchan_file - remove the channel file
+ *     @private: pointer to the channel struct
+ *
+ *     Internal - manages the removal of old channel file
+ */
+static void
+remove_rchan_file(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;

Please remove the redundant cast.

fs/Makefile

Quoted 11 lines
fs/Makefile +11 -0
+/**
+ *	rchan_put - decrement channel refcount, releasing it if 0
+ *	@rchan: the channel
+ *
+ *	If the refcount reaches 0, the channel will be destroyed.
+ */
+void
+rchan_put(struct rchan *rchan)
+{
+	if (atomic_dec_and_test(&rchan->refcount))
+		relay_release(rchan);

relay_release returns an error code. Either check for it or remove the pointless error value propagation from the code.

fs/Makefile

Quoted 13 lines
fs/Makefile +13 -0
+/**
+ *	wakeup_readers - wake up VFS readers waiting on a channel
+ *	@private: the channel
+ *
+ *	This is the work function used to defer reader waking.  The
+ *	reason waking is deferred is that calling directly from commit
+ *	causes problems if you're writing from say the scheduler.
+ */
+static void
+wakeup_readers(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;
+

Remove the redundant cast.

fs/Makefile

Quoted 12 lines
fs/Makefile +12 -0
+/*
+ * close() vm_op implementation for relayfs file mapping.
+ */
+static void
+relay_file_mmap_close(struct vm_area_struct *vma)
+{
+	struct file *filp = vma->vm_file;
+	struct rchan_reader *reader;
+	struct rchan *rchan;
+
+	reader = filp->private_data;
+	rchan = reader->rchan;

Why not move these initializations to the declaration like vma->vm_file.

fs/Makefile

Quoted 10 lines
fs/Makefile +10 -0
+		if (err == 0)
+			atomic_inc(&rchan->mapped);
+	}
+exit:
+	return err;
+}
+
+/*
+ * High-level relayfs kernel API.  See Documentation/filesystems/relafys.txt.
+ */

s/relafys/relayfs/

fs/Makefile

Quoted 7 lines
fs/Makefile +7 -0
+static inline int
+rchan_create_buf(struct rchan *rchan, int size_alloc)
+{
+	struct page **page_array;
+	int page_count;
+
+	if ((rchan->buf = (char *)alloc_rchan_buf(size_alloc, &page_array, &page_count)) == NULL) {

Please remove the redundant cast.

Quoted 13 lines
fs/Makefile +13 -0
+/**
+ *	rchan_create - allocate and initialize a channel, including buffer
+ *	@chanpath: path specifying the relayfs channel file to create
+ *	@bufsize: the size of the sub-buffers within the channel buffer
+ *	@nbufs: the number of sub-buffers within the channel buffer
+ *	@rchan_flags: flags specifying buffer attributes
+ *	@err: err code
+ *
+ *	Returns channel if successful, NULL otherwise, err receives errcode.
+ *
+ *	Allocates a struct rchan representing a relay channel, according
+ *	to the attributes passed in via rchan_flags.  Does some basic sanity
+ *	checking but doesn't try to do anything smart.  In particular, the

fs/Makefile

Quoted 10 lines
fs/Makefile +10 -0
+ *	number of buffers must be a power of 2, and if the lockless scheme
+ *	is being used, the sub-buffer size must also be a power of 2.  The
+ *	locking scheme can use buffers of any size.
+ */
+static struct rchan *
+rchan_create(const char *chanpath,
+	     int bufsize,
+	     int nbufs,
+	     u32 rchan_flags,
+	     int *err)

err parameter seems overkill as you can achieve the same thing by returning NULL to the caller.

fs/Makefile

Quoted 11 lines
fs/Makefile +11 -0
+exit:
+	if (*err) {
+		kfree(rchan);
+		rchan = NULL;
+	}
+
+	return rchan;
+}
+
+
+static char tmpname[NAME_MAX];

Hmm? At least move this bugger into rchan_create_dir. How are you serializing accesses to this anyway?

fs/Makefile

Quoted 11 lines
fs/Makefile +11 -0
+/**
+ *	restore_callbacks - restore default channel callbacks
+ *	@rchan: the channel
+ *
+ *	Restore callbacks to the default versions.
+ */
+static inline void
+restore_callbacks(struct rchan *rchan)
+{
+	if (rchan->callbacks != &default_channel_callbacks)
+		rchan->callbacks = &default_channel_callbacks;

The if clause achieves nothing. Please remove it and inline the code to its callers.

Pekka

#11 lore raw

PATCH 1/1 relayfs crash

In reply to Karim Yaghmour

Hi Tom,

I've been stress testing a module that uses relayfs on a custom built 2.6 kernel with relayfs patches in it. This test simply loaded and unloaded the module while a script loaded the system with forks of 'ls' in the background. It was conducted on a dual 3.00GHz Xeon box (I couldn't reproduce the bug on slower machines I had) and produced oopses of the following type:

wembley login: Oops: 0000 [#1]
SMP

CPU:    2
EIP:    0060:[<f9824790>]    Tainted: GF U
EFLAGS: 00010292   (2.6.5-7.97ZP2-smp)

EIP is at relayfs_remove_file+0x10/0xc0 [relayfs]
eax: 00000000 ebx: 00000292 ecx: f0cf3918 edx: c193810c
esi: 00000000 edi: f0cf391c ebp: f0cf3000 esp: f7fabf4c
ds: 007b es: 007b ss: 0068
Process events/2 (pid: 12, threadinfo=f7faa000 task=cdea2730)

Stack: 00000292 c1938100 f0cf391c c0138cc7 00000000 c180c960 c180c960 c1938120
       f9822cb0 f7faa000 c193810c ffffffff ffffffff 00000001 00000000 c0122b10
       00010000 00000000 00fffff0 00000000 00000000 00000000 cdea2730 c0122b10
Call Trace:
 [<c0138cc7>] worker_thread+0x187/0x230
 [<f9822cb0>] remove_rchan_file+0x0/0xb [relayfs]
 [<c0122b10>] default_wake_function+0x0/0x10
 [<c0122b10>] default_wake_function+0x0/0x10
 [<c0138b40>] worker_thread+0x0/0x230
 [<c013c894>] kthread+0xd4/0x118
 [<c013c7c0>] kthread+0x0/0x118
 [<c0107005>] kernel_thread_helper+0x5/0x10

Code: 8b 58 64 b8 ea ff ff ff 85 db 74 5b 8b 46 0c 0f b7 40 20 25

This oops looks like one mentioned in
http://www.listserv.shafik.org/pipermail/ltt/2004-July/000627.html

It seems to be the same problem where the rchan work queue is scheduled to run, but rchan has already been destroyed when the tries it. This still happens in the latest patch against 2.6.10 at
http://www.opersys.com/ftp/pub/relayfs/patch-relayfs-2.6.10-050113

To solve the problem I applied a patch similar to the one you posted back in July and it fixed the problem. Could we consider putting this patch into relayfs? Its similar to the one posted in July 2004, except it also moves clear_readers() before INIT_WORK in relay_release (is that acceptable?).

Thanks,

Signature · 1 line
		Kingsley
fs/relayfs/relay.c renamed from fs/relayfs/relay.c.old +2 -3
@@ -184,6 +184,7 @@
 	struct rchan *rchan = (struct rchan *)private;
 
 	relayfs_remove_file(rchan->dentry);
+	kfree(rchan);
 }
  
 
@@ -212,12 +213,10 @@
 		goto exit;
 
 	rchan_free_id(rchan->id);
+	clear_readers(rchan);
 
 	INIT_WORK(&rchan->work, remove_rchan_file, rchan);
 	schedule_delayed_work(&rchan->work, 1);
-
-	clear_readers(rchan);
-	kfree(rchan);
 exit:
 	return err;
 }
#12 lore raw

Re: [PATCH] relayfs crash

Quoted 5 lines · Kingsley Cheung

To solve the problem I applied a patch similar to the one you posted back in July and it fixed the problem. Could we consider putting this patch into relayfs? Its similar to the one posted in July 2004, except it also moves clear_readers() before INIT_WORK in relay_release (is that acceptable?).

Tom, correct me if I'm wrong but these fixes were integrated in the first relayfs redux I sent to LKML a few weeks back, right?

Karim

Signature · 3 lines
Author, Speaker, Developer, Consultant
Pushing Embedded and Real-Time Linux Systems Beyond the Limits
http://www.opersys.com || [email protected] || 1-866-677-4546
#13 lore raw

Re: [PATCH] relayfs crash

In reply to Kingsley Cheung
Quoted 7 lines · Kingsley Cheung

To solve the problem I applied a patch similar to the one you posted back in July and it fixed the problem. Could we consider putting this patch into relayfs? Its similar to the one posted in July 2004, except it also moves clear_readers() before INIT_WORK in relay_release (is that acceptable?).

Yes, for some reason the July patch never got applied to that (now outdated) 2.6.10 version of relayfs - either that patch or yours should fix the problem - thanks for sending it. In any case, the version of relayfs you're using is now ancient history - the latest redux versions of relayfs recently posted to lkml have completely changed or removed all that code, so you might want to try testing with the latest patch (which I'm still reworking parts of even now).

Thanks,

Tom

#14 lore raw

Re: [PATCH] relayfs crash

Quoted 17 lines · Tom Zanussi
Quoted 7 lines · Kingsley Cheung

To solve the problem I applied a patch similar to the one you posted back in July and it fixed the problem. Could we consider putting this patch into relayfs? Its similar to the one posted in July 2004, except it also moves clear_readers() before INIT_WORK in relay_release (is that acceptable?).

Yes, for some reason the July patch never got applied to that (now outdated) 2.6.10 version of relayfs - either that patch or yours should fix the problem - thanks for sending it. In any case, the version of relayfs you're using is now ancient history - the latest redux versions of relayfs recently posted to lkml have completely changed or removed all that code, so you might want to try testing with the latest patch (which I'm still reworking parts of even now).

Quoted 4 lines

Thanks,

Tom

Okay. I'll give the new patch a go when I can.

Thanks,

Signature · 1 line
		Kingsley