linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Arnd Bergmann <arnd@arndb.de>
To: Greg KH <greg@kroah.com>
Cc: linuxppc64-dev@ozlabs.org, linux-kernel@vger.kernel.org,
	Paul Mackerras <paulus@samba.org>,
	Anton Blanchard <anton@samba.org>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>
Subject: [PATCH] libfs: add simple attribute files
Date: Wed, 18 May 2005 14:40:59 +0200	[thread overview]
Message-ID: <200505181441.01495.arnd@arndb.de> (raw)
In-Reply-To: <20050514074524.GC20021@kroah.com>

Based on the discussion about spufs attributes, this is my suggestion
for a more generic attribute file support that can be used by both
debugfs and spufs.

Simple attribute files behave similarly to sequential files from
a kernel programmers perspective in that a standard set of file
operations is provided and only an open operation needs to
be written that registers file specific get() and set() functions.

These operations are defined as

void foo_set(void *data, long val); and
long foo_get(void *data);

where data is the inode->u.generic_ip pointer of the file and the
operations just need to make send of that pointer. The infrastructure
makes sure this works correctly with concurrent access and partial
read calls.

A macro named DEFINE_SIMPLE_ATTRIBUTE is provided to further simplify
using the attributes.

This patch already contains the changes for debugfs to use attributes
for its internal file operations. 

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

---
 fs/debugfs/file.c  |   74 +++++++++++++++++++----------------------
 fs/libfs.c         |   94 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h |   48 +++++++++++++++++++++++++++
 3 files changed, 177 insertions(+), 39 deletions(-)

fs/libfs.c: needs update
Index: linus-2.5/include/linux/fs.h
===================================================================
--- linus-2.5.orig/include/linux/fs.h	2005-05-18 10:58:52.000000000 +0200
+++ linus-2.5/include/linux/fs.h	2005-05-18 14:07:10.000000000 +0200
@@ -1657,6 +1657,55 @@
 	ar->size = n;
 }
 
+/*
+ * simple attribute files
+ *
+ * These attributes behave similar to those in sysfs:
+ *
+ * Writing to an attribute immediately sets a value, an open file can be
+ * written to multiple times.
+ *
+ * Reading from an attribute creates a buffer from the value that might get
+ * read with multiple read calls. When the attribute has been read
+ * completely, no further read calls are possible until the file is opened
+ * again.
+ *
+ * All spufs attributes contain a text representation of a numeric value
+ * that are accessed with the get() and set() functions.
+ *
+ * Perhaps these file operations could be put in debugfs or libfs instead,
+ * they are not really SPU specific.
+ */
+#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)		\
+static int __fops ## _open(struct inode *inode, struct file *file)	\
+{									\
+	__simple_attr_check_format(__fmt, 0ul);				\
+	return simple_attr_open(inode, file, &__get, &__set, __fmt);	\
+}									\
+static struct file_operations __fops = {				\
+	.owner	 = THIS_MODULE,						\
+	.open	 = __fops ## _open,					\
+	.release = simple_attr_close,					\
+	.read	 = simple_attr_read,					\
+	.write	 = simple_attr_write,					\
+};
+
+static inline void __attribute__((format(printf, 1, 2)))
+__simple_attr_check_format(const char *fmt, ...)
+{
+	/* don't do anything, just let the compiler check the arguments; */
+}
+
+int simple_attr_open(struct inode *inode, struct file *file,
+		long (*get)(void *), void (*set)(void *, long),
+		const char *fmt);
+int simple_attr_close(struct inode *inode, struct file *file);
+ssize_t simple_attr_read(struct file *file, char __user *buf,
+					size_t len, loff_t *ppos);
+ssize_t simple_attr_write(struct file *file, const char __user *buf,
+					size_t len, loff_t *ppos);
+
+
 #ifdef CONFIG_SECURITY
 static inline char *alloc_secdata(void)
 {
Index: linus-2.5/fs/libfs.c
===================================================================
--- linus-2.5.orig/fs/libfs.c	2005-05-18 10:58:52.000000000 +0200
+++ linus-2.5/fs/libfs.c	2005-05-18 12:06:49.000000000 +0200
@@ -519,6 +519,100 @@
 	return 0;
 }
 
+/* Simple attribute files */
+
+struct simple_attr {
+	long (*get)(void *);
+	void (*set)(void *, long);
+	char get_buf[24]; /* enough to store a long and "\n\0" */
+	char set_buf[24];
+	void *data;
+	const char *fmt; /* format for read operation */
+	struct semaphore sem; /* protects access to these buffers */
+};
+
+/* simple_attr_open is called by an actual attribute open file operation
+ * to set the attribute specific access operations. */
+int simple_attr_open(struct inode *inode, struct file *file,
+		long (*get)(void *), void (*set)(void *, long),
+		const char *fmt)
+{
+	struct simple_attr *attr;
+
+	attr = kmalloc(sizeof *attr, GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	/* reading/writing needs the respective get/set operation */
+	if (((file->f_mode & FMODE_READ)  && !get) ||
+	    ((file->f_mode & FMODE_WRITE) && !set))
+		return -EACCES;
+
+	attr->get = get;
+	attr->set = set;
+	attr->data = inode->u.generic_ip;
+	attr->fmt = fmt;
+	init_MUTEX(&attr->sem);
+
+	file->private_data = attr;
+
+	return nonseekable_open(inode, file);
+}
+
+int simple_attr_close(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+/* read from the buffer that is filled with the get function */
+ssize_t simple_attr_read(struct file *file, char __user *buf,
+					size_t len, loff_t *ppos)
+{
+	struct simple_attr *attr;
+	size_t size;
+	ssize_t ret;
+
+	attr = file->private_data;
+
+	down(&attr->sem);
+	if (*ppos) /* continued read */
+		size = strlen(attr->get_buf);
+	else	  /* first read */
+		size = scnprintf(attr->get_buf, sizeof (attr->get_buf),
+				 attr->fmt, attr->get(attr->data));
+
+	ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size);
+	up(&attr->sem);
+	return ret;
+}
+
+/* interpret the buffer as a number to call the set function with */
+ssize_t simple_attr_write(struct file *file, const char __user *buf,
+					size_t len, loff_t *ppos)
+{
+	struct simple_attr *attr;
+	long val;
+	size_t size;
+	ssize_t ret;
+
+	attr = file->private_data;
+
+	down(&attr->sem);
+	ret = -EFAULT;
+	size = min(sizeof (attr->set_buf) - 1, len);
+	if (copy_from_user(attr->set_buf, buf, size))
+		goto out;
+
+	ret = len; /* claim we got the whole input */
+	attr->set_buf[size] = '\0';
+	val = simple_strtol(attr->set_buf, NULL, 0);
+	attr->set(attr->data, val);
+out:
+	up(&attr->sem);
+	return ret;
+}
+
 EXPORT_SYMBOL(dcache_dir_close);
 EXPORT_SYMBOL(dcache_dir_lseek);
 EXPORT_SYMBOL(dcache_dir_open);
Index: linus-2.5/fs/debugfs/file.c
===================================================================
--- linus-2.5.orig/fs/debugfs/file.c	2005-05-18 10:58:52.000000000 +0200
+++ linus-2.5/fs/debugfs/file.c	2005-05-18 12:22:16.000000000 +0200
@@ -45,45 +45,6 @@
 	.open =		default_open,
 };
 
-#define simple_type(type, format, temptype, strtolfn)				\
-static ssize_t read_file_##type(struct file *file, char __user *user_buf,	\
-				size_t count, loff_t *ppos)			\
-{										\
-	char buf[32];								\
-	type *val = file->private_data;						\
-										\
-	snprintf(buf, sizeof(buf), format "\n", *val);				\
-	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));\
-}										\
-static ssize_t write_file_##type(struct file *file, const char __user *user_buf,\
-				 size_t count, loff_t *ppos)			\
-{										\
-	char *endp;								\
-	char buf[32];								\
-	int buf_size;								\
-	type *val = file->private_data;						\
-	temptype tmp;								\
-										\
-	memset(buf, 0x00, sizeof(buf));						\
-	buf_size = min(count, (sizeof(buf)-1));					\
-	if (copy_from_user(buf, user_buf, buf_size))				\
-		return -EFAULT;							\
-										\
-	tmp = strtolfn(buf, &endp, 0);						\
-	if ((endp == buf) || ((type)tmp != tmp))				\
-		return -EINVAL;							\
-	*val = tmp;								\
-	return count;								\
-}										\
-static struct file_operations fops_##type = {					\
-	.read =		read_file_##type,					\
-	.write =	write_file_##type,					\
-	.open =		default_open,						\
-};
-simple_type(u8, "%c", unsigned long, simple_strtoul);
-simple_type(u16, "%hi", unsigned long, simple_strtoul);
-simple_type(u32, "%i", unsigned long, simple_strtoul);
-
 /**
  * debugfs_create_u8 - create a file in the debugfs filesystem that is used to read and write a unsigned 8 bit value.
  *
@@ -109,6 +70,18 @@
  * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
+static void debugfs_u8_set(void *data, long val)
+{
+	*(u8 *)data = val;
+}
+
+static long debugfs_u8_get(void *data)
+{
+	return *(u8 *)data;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%lu\n");
+
 struct dentry *debugfs_create_u8(const char *name, mode_t mode,
 				 struct dentry *parent, u8 *value)
 {
@@ -141,6 +114,17 @@
  * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
+static void debugfs_u16_set(void *data, long val)
+{
+	*(u16 *)data = val;
+}
+
+static long debugfs_u16_get(void *data)
+{
+	return *(u16 *)data;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%lu\n");
+
 struct dentry *debugfs_create_u16(const char *name, mode_t mode,
 				  struct dentry *parent, u16 *value)
 {
@@ -173,6 +157,18 @@
  * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
  * code.
  */
+static void debugfs_u32_set(void *data, long val)
+{
+	*(u32 *)data = val;
+}
+
+static long debugfs_u32_get(void *data)
+{
+	return *(u32 *)data;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%lu\n");
+
 struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 				 struct dentry *parent, u32 *value)
 {

  parent reply	other threads:[~2005-05-18 12:58 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-05-13 19:31 [PATCH 0/8] ppc64: Introduce Cell/BPA platform, v2 Arnd Bergmann
2005-05-13 19:21 ` [PATCH 1/8] ppc64: split out generic rtas code from pSeries_pci.c Arnd Bergmann
2005-05-13 19:23 ` [PATCH 2/8] ppc64: add a minimal nvram driver Arnd Bergmann
2005-05-13 19:24 ` [PATCH 3/8] ppc64: add a watchdog driver for rtas Arnd Bergmann
2005-05-17 20:40   ` Nathan Lynch
2005-05-18  7:14     ` Arnd Bergmann
2005-05-18 14:45       ` Nathan Lynch
2005-05-18 14:39         ` Arnd Bergmann
2005-05-13 19:25 ` [PATCH 4/8] ppc64: add BPA platform type Arnd Bergmann
2005-05-17  7:01   ` Paul Mackerras
2005-05-17 11:05     ` Arnd Bergmann
2005-05-13 19:26 ` [PATCH 5/8] ppc64: Add driver for BPA interrupt controllers Arnd Bergmann
2005-05-13 19:27 ` [PATCH 6/8] ppc64: Add driver for BPA iommu Arnd Bergmann
2005-05-13 19:29 ` [PATCH 7/8] ppc64: SPU file system Arnd Bergmann
2005-05-13 23:31   ` Benjamin Herrenschmidt
2005-05-15  9:07     ` Pavel Machek
2005-05-15 12:02       ` Benjamin Herrenschmidt
2005-05-15 12:33         ` Arnd Bergmann
2005-05-14  7:45   ` Greg KH
2005-05-14 13:05     ` Arnd Bergmann
2005-05-15  6:29       ` Benjamin Herrenschmidt
2005-05-15 10:08         ` Arnd Bergmann
2005-05-15 11:50           ` Arnd Bergmann
2005-05-16 20:58       ` Greg KH
2005-05-16 22:01         ` Arnd Bergmann
2005-05-16 22:27           ` Greg KH
2005-05-16 22:22             ` Arnd Bergmann
2005-05-16 22:49               ` Greg KH
2005-05-15 11:24     ` Andi Kleen
2005-05-16 20:14     ` Roland Dreier
2005-05-16 20:53       ` Greg KH
2005-05-18 12:40     ` Arnd Bergmann [this message]
2005-05-18 20:24       ` [PATCH] libfs: add simple attribute files Greg KH
2005-05-19  8:29         ` Arnd Bergmann
2005-05-19  9:18           ` 2.4 Kernel threads linux
2005-06-10  4:33           ` [PATCH] libfs: add simple attribute files Greg KH
2005-05-13 19:32 ` [PATCH 8/8] ppc64: add spufs user library Arnd Bergmann
2005-06-20 22:59 [PATCH] usbcore: Don't call device_release_driver recursively Greg KH
2005-06-20 22:59 ` [PATCH] libfs: add simple attribute files Greg KH

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=200505181441.01495.arnd@arndb.de \
    --to=arnd@arndb.de \
    --cc=anton@samba.org \
    --cc=benh@kernel.crashing.org \
    --cc=greg@kroah.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc64-dev@ozlabs.org \
    --cc=paulus@samba.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).