libfs: allow error return from simple attributes
authorChristoph Hellwig <hch@lst.de>
Fri, 8 Feb 2008 12:20:26 +0000 (04:20 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 8 Feb 2008 17:22:34 +0000 (09:22 -0800)
Sometimes simple attributes might need to return an error, e.g. for
acquiring a mutex interruptibly.  In fact we have that situation in
spufs already which is the original user of the simple attributes.  This
patch merged the temporarily forked attributes in spufs back into the
main ones and allows to return errors.

[akpm@linux-foundation.org: build fix]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: <stefano.brivio@polimi.it>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg KH <greg@kroah.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/avr32/kernel/ocd.c
arch/powerpc/platforms/cell/spufs/file.c
fs/debugfs/file.c
fs/libfs.c
include/linux/fs.h
lib/fault-inject.c
virt/kvm/kvm_main.c

index c4f023294d750659e992b93afc1d22ca456065f6..1b0245d4e0ca6937292770d72cdeb410a20b8d7e 100644 (file)
@@ -90,25 +90,29 @@ static struct dentry *ocd_debugfs_DC;
 static struct dentry *ocd_debugfs_DS;
 static struct dentry *ocd_debugfs_count;
 
-static u64 ocd_DC_get(void *data)
+static int ocd_DC_get(void *data, u64 *val)
 {
-       return ocd_read(DC);
+       *val = ocd_read(DC);
+       return 0;
 }
-static void ocd_DC_set(void *data, u64 val)
+static int ocd_DC_set(void *data, u64 val)
 {
        ocd_write(DC, val);
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_DC, ocd_DC_get, ocd_DC_set, "0x%08llx\n");
 
-static u64 ocd_DS_get(void *data)
+static int ocd_DS_get(void *data, u64 *val)
 {
-       return ocd_read(DS);
+       *val = ocd_read(DS);
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_DS, ocd_DS_get, NULL, "0x%08llx\n");
 
-static u64 ocd_count_get(void *data)
+static int ocd_count_get(void *data, u64 *val)
 {
-       return ocd_count;
+       *val = ocd_count;
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_count, ocd_count_get, NULL, "%lld\n");
 
index 1018acd1746b76f7ac99ef91b62092d4d45529d6..9326714717ca1db5febb93eb692a075a3e5039fc 100644 (file)
@@ -460,7 +460,7 @@ static int spufs_cntl_open(struct inode *inode, struct file *file)
        if (!i->i_openers++)
                ctx->cntl = inode->i_mapping;
        mutex_unlock(&ctx->mapping_lock);
-       return spufs_attr_open(inode, file, spufs_cntl_get,
+       return simple_attr_open(inode, file, spufs_cntl_get,
                                        spufs_cntl_set, "0x%08lx");
 }
 
@@ -470,7 +470,7 @@ spufs_cntl_release(struct inode *inode, struct file *file)
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
 
-       spufs_attr_release(inode, file);
+       simple_attr_close(inode, file);
 
        mutex_lock(&ctx->mapping_lock);
        if (!--i->i_openers)
@@ -482,8 +482,8 @@ spufs_cntl_release(struct inode *inode, struct file *file)
 static const struct file_operations spufs_cntl_fops = {
        .open = spufs_cntl_open,
        .release = spufs_cntl_release,
-       .read = spufs_attr_read,
-       .write = spufs_attr_write,
+       .read = simple_attr_read,
+       .write = simple_attr_write,
        .mmap = spufs_cntl_mmap,
 };
 
index fa6b7f7ff914269a8a8bbc4fe0bc90d01701f567..fddffe4851f550cd78315189d6466bc0a24ad126 100644 (file)
@@ -56,13 +56,15 @@ const struct inode_operations debugfs_link_operations = {
        .follow_link    = debugfs_follow_link,
 };
 
-static void debugfs_u8_set(void *data, u64 val)
+static int debugfs_u8_set(void *data, u64 val)
 {
        *(u8 *)data = val;
+       return 0;
 }
-static u64 debugfs_u8_get(void *data)
+static int debugfs_u8_get(void *data, u64 *val)
 {
-       return *(u8 *)data;
+       *val = *(u8 *)data;
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
 
@@ -97,13 +99,15 @@ struct dentry *debugfs_create_u8(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u8);
 
-static void debugfs_u16_set(void *data, u64 val)
+static int debugfs_u16_set(void *data, u64 val)
 {
        *(u16 *)data = val;
+       return 0;
 }
-static u64 debugfs_u16_get(void *data)
+static int debugfs_u16_get(void *data, u64 *val)
 {
-       return *(u16 *)data;
+       *val = *(u16 *)data;
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
 
@@ -138,13 +142,15 @@ struct dentry *debugfs_create_u16(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u16);
 
-static void debugfs_u32_set(void *data, u64 val)
+static int debugfs_u32_set(void *data, u64 val)
 {
        *(u32 *)data = val;
+       return 0;
 }
-static u64 debugfs_u32_get(void *data)
+static int debugfs_u32_get(void *data, u64 *val)
 {
-       return *(u32 *)data;
+       *val = *(u32 *)data;
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
 
@@ -179,14 +185,16 @@ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
 
-static void debugfs_u64_set(void *data, u64 val)
+static int debugfs_u64_set(void *data, u64 val)
 {
        *(u64 *)data = val;
+       return 0;
 }
 
-static u64 debugfs_u64_get(void *data)
+static int debugfs_u64_get(void *data, u64 *val)
 {
-       return *(u64 *)data;
+       *val = *(u64 *)data;
+       return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
 
index 5523bde963879d6060c9a9d19396e8a8615b40a2..2319415ddb5e966fd99f3851460adfcad55de440 100644 (file)
@@ -583,8 +583,8 @@ int simple_transaction_release(struct inode *inode, struct file *file)
 /* Simple attribute files */
 
 struct simple_attr {
-       u64 (*get)(void *);
-       void (*set)(void *, u64);
+       int (*get)(void *, u64 *);
+       int (*set)(void *, u64);
        char get_buf[24];       /* enough to store a u64 and "\n\0" */
        char set_buf[24];
        void *data;
@@ -595,7 +595,7 @@ struct simple_attr {
 /* 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,
-                    u64 (*get)(void *), void (*set)(void *, u64),
+                    int (*get)(void *, u64 *), int (*set)(void *, u64),
                     const char *fmt)
 {
        struct simple_attr *attr;
@@ -635,14 +635,20 @@ ssize_t simple_attr_read(struct file *file, char __user *buf,
                return -EACCES;
 
        mutex_lock(&attr->mutex);
-       if (*ppos) /* continued read */
+       if (*ppos) {            /* continued read */
                size = strlen(attr->get_buf);
-       else      /* first read */
+       } else {                /* first read */
+               u64 val;
+               ret = attr->get(attr->data, &val);
+               if (ret)
+                       goto out;
+
                size = scnprintf(attr->get_buf, sizeof(attr->get_buf),
-                                attr->fmt,
-                                (unsigned long long)attr->get(attr->data));
+                                attr->fmt, (unsigned long long)val);
+       }
 
        ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size);
+out:
        mutex_unlock(&attr->mutex);
        return ret;
 }
@@ -657,7 +663,6 @@ ssize_t simple_attr_write(struct file *file, const char __user *buf,
        ssize_t ret;
 
        attr = file->private_data;
-
        if (!attr->set)
                return -EACCES;
 
index 36b7abefacbe4b743ba128afcdcfee7b5c05a885..ebe996ac2589aee6740d441c7d4a6b644c6fb93d 100644 (file)
@@ -2068,7 +2068,7 @@ __simple_attr_check_format(const char *fmt, ...)
 }
 
 int simple_attr_open(struct inode *inode, struct file *file,
-                    u64 (*get)(void *), void (*set)(void *, u64),
+                    int (*get)(void *, u64 *), int (*set)(void *, u64),
                     const char *fmt);
 int simple_attr_close(struct inode *inode, struct file *file);
 ssize_t simple_attr_read(struct file *file, char __user *buf,
index 23985a278bbb08d919ab9bc92dd7869d3aba8f0a..a50a311554cc30e5e1b5d992988397a33f560ac6 100644 (file)
@@ -134,23 +134,26 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
 
 #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
 
-static void debugfs_ul_set(void *data, u64 val)
+static int debugfs_ul_set(void *data, u64 val)
 {
        *(unsigned long *)data = val;
+       return 0;
 }
 
 #ifdef CONFIG_FAULT_INJECTION_STACKTRACE_FILTER
-static void debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val)
+static int debugfs_ul_set_MAX_STACK_TRACE_DEPTH(void *data, u64 val)
 {
        *(unsigned long *)data =
                val < MAX_STACK_TRACE_DEPTH ?
                val : MAX_STACK_TRACE_DEPTH;
+       return 0;
 }
 #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
 
-static u64 debugfs_ul_get(void *data)
+static int debugfs_ul_get(void *data, u64 *val)
 {
-       return *(unsigned long *)data;
+       *val = *(unsigned long *)data;
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_ul, debugfs_ul_get, debugfs_ul_set, "%llu\n");
@@ -174,14 +177,16 @@ static struct dentry *debugfs_create_ul_MAX_STACK_TRACE_DEPTH(
 }
 #endif /* CONFIG_FAULT_INJECTION_STACKTRACE_FILTER */
 
-static void debugfs_atomic_t_set(void *data, u64 val)
+static int debugfs_atomic_t_set(void *data, u64 val)
 {
        atomic_set((atomic_t *)data, val);
+       return 0;
 }
 
-static u64 debugfs_atomic_t_get(void *data)
+static int debugfs_atomic_t_get(void *data, u64 *val)
 {
-       return atomic_read((atomic_t *)data);
+       *val = atomic_read((atomic_t *)data);
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get,
index 3c4fe26096fcd3917db20d8a9ecfa6188496f420..32fbf800696901866b760cef48b880a151c58399 100644 (file)
@@ -1186,38 +1186,38 @@ static struct notifier_block kvm_cpu_notifier = {
        .priority = 20, /* must be > scheduler priority */
 };
 
-static u64 vm_stat_get(void *_offset)
+static int vm_stat_get(void *_offset, u64 *val)
 {
        unsigned offset = (long)_offset;
-       u64 total = 0;
        struct kvm *kvm;
 
+       *val = 0;
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
-               total += *(u32 *)((void *)kvm + offset);
+               *val += *(u32 *)((void *)kvm + offset);
        spin_unlock(&kvm_lock);
-       return total;
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vm_stat_fops, vm_stat_get, NULL, "%llu\n");
 
-static u64 vcpu_stat_get(void *_offset)
+static int vcpu_stat_get(void *_offset, u64 *val)
 {
        unsigned offset = (long)_offset;
-       u64 total = 0;
        struct kvm *kvm;
        struct kvm_vcpu *vcpu;
        int i;
 
+       *val = 0;
        spin_lock(&kvm_lock);
        list_for_each_entry(kvm, &vm_list, vm_list)
                for (i = 0; i < KVM_MAX_VCPUS; ++i) {
                        vcpu = kvm->vcpus[i];
                        if (vcpu)
-                               total += *(u32 *)((void *)vcpu + offset);
+                               *val += *(u32 *)((void *)vcpu + offset);
                }
        spin_unlock(&kvm_lock);
-       return total;
+       return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(vcpu_stat_fops, vcpu_stat_get, NULL, "%llu\n");