aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds2007-04-27 12:58:54 -0700
committerLinus Torvalds2007-04-27 12:58:54 -0700
commitd868772fff6c4b881d66af8640251714e1aefa98 (patch)
treec95a68d358d5c875d25763ffe9a44fe9f2081f34 /fs
parenta205752d1ad2d37d6597aaae5a56fc396a770868 (diff)
parent404d5b185b4eb56d6fa2f7bd27833f8df1c38ce4 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (46 commits) dev_dbg: check dev_dbg() arguments drivers/base/attribute_container.c: use mutex instead of binary semaphore mod_sysfs_setup() doesn't return errno when kobject_add_dir() failure occurs s2ram: add arch irq disable/enable hooks define platform wakeup hook, use in pci_enable_wake() security: prevent permission checking of file removal via sysfs_remove_group() device_schedule_callback() needs a module reference s390: cio: Delay uevents for subchannels sysfs: bin.c printk fix Driver core: use mutex instead of semaphore in DMA pool handler driver core: bus_add_driver should return an error if no bus debugfs: Add debugfs_create_u64() the overdue removal of the mount/umount uevents kobject: Comment and warning fixes to kobject.c Driver core: warn when userspace writes to the uevent file in a non-supported way Driver core: make uevent-environment available in uevent-file kobject core: remove rwsem from struct subsystem qeth: Remove usage of subsys.rwsem PHY: remove rwsem use from phy core IEEE1394: remove rwsem use from ieee1394 core ...
Diffstat (limited to 'fs')
-rw-r--r--fs/debugfs/file.c42
-rw-r--r--fs/namei.c72
-rw-r--r--fs/super.c12
-rw-r--r--fs/sysfs/bin.c2
-rw-r--r--fs/sysfs/file.c14
-rw-r--r--fs/sysfs/group.c6
6 files changed, 110 insertions, 38 deletions
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 682f928b7f4d..2e124e0075c5 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -179,6 +179,48 @@ 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)
+{
+ *(u64 *)data = val;
+}
+
+static u64 debugfs_u64_get(void *data)
+{
+ return *(u64 *)data;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+
+/**
+ * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file. This should be a
+ * directory dentry if set. If this parameter is %NULL, then the
+ * file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ * from.
+ *
+ * This function creates a file in debugfs with the given name that
+ * contains the value of the variable @value. If the @mode variable is so
+ * set, it can be read from, and written to.
+ *
+ * This function will return a pointer to a dentry if it succeeds. This
+ * pointer must be passed to the debugfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.) If an error occurs, %NULL will be returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned. It is not wise to check for this value, but rather, check for
+ * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *debugfs_create_u64(const char *name, mode_t mode,
+ struct dentry *parent, u64 *value)
+{
+ return debugfs_create_file(name, mode, parent, value, &fops_u64);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_u64);
+
static ssize_t read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
diff --git a/fs/namei.c b/fs/namei.c
index ee60cc4d3453..880052cadbcd 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1243,22 +1243,13 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
return err;
}
-/*
- * Restricted form of lookup. Doesn't follow links, single-component only,
- * needs parent already locked. Doesn't follow mounts.
- * SMP-safe.
- */
-static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
+static inline struct dentry *__lookup_hash_kern(struct qstr *name, struct dentry *base, struct nameidata *nd)
{
- struct dentry * dentry;
+ struct dentry *dentry;
struct inode *inode;
int err;
inode = base->d_inode;
- err = permission(inode, MAY_EXEC, nd);
- dentry = ERR_PTR(err);
- if (err)
- goto out;
/*
* See if the low-level filesystem might want
@@ -1287,35 +1278,76 @@ out:
return dentry;
}
+/*
+ * Restricted form of lookup. Doesn't follow links, single-component only,
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+static inline struct dentry * __lookup_hash(struct qstr *name, struct dentry *base, struct nameidata *nd)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+ int err;
+
+ inode = base->d_inode;
+
+ err = permission(inode, MAY_EXEC, nd);
+ dentry = ERR_PTR(err);
+ if (err)
+ goto out;
+
+ dentry = __lookup_hash_kern(name, base, nd);
+out:
+ return dentry;
+}
+
static struct dentry *lookup_hash(struct nameidata *nd)
{
return __lookup_hash(&nd->last, nd->dentry, nd);
}
/* SMP-safe */
-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+static inline int __lookup_one_len(const char *name, struct qstr *this, struct dentry *base, int len)
{
unsigned long hash;
- struct qstr this;
unsigned int c;
- this.name = name;
- this.len = len;
+ this->name = name;
+ this->len = len;
if (!len)
- goto access;
+ return -EACCES;
hash = init_name_hash();
while (len--) {
c = *(const unsigned char *)name++;
if (c == '/' || c == '\0')
- goto access;
+ return -EACCES;
hash = partial_name_hash(c, hash);
}
- this.hash = end_name_hash(hash);
+ this->hash = end_name_hash(hash);
+ return 0;
+}
+struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+{
+ int err;
+ struct qstr this;
+
+ err = __lookup_one_len(name, &this, base, len);
+ if (err)
+ return ERR_PTR(err);
return __lookup_hash(&this, base, NULL);
-access:
- return ERR_PTR(-EACCES);
+}
+
+struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int len)
+{
+ int err;
+ struct qstr this;
+
+ err = __lookup_one_len(name, &this, base, len);
+ if (err)
+ return ERR_PTR(err);
+ return __lookup_hash_kern(&this, base, NULL);
}
/*
diff --git a/fs/super.c b/fs/super.c
index 60b1e50cbf53..8341e4e1d738 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -725,16 +725,6 @@ static int test_bdev_super(struct super_block *s, void *data)
return (void *)s->s_bdev == data;
}
-static void bdev_uevent(struct block_device *bdev, enum kobject_action action)
-{
- if (bdev->bd_disk) {
- if (bdev->bd_part)
- kobject_uevent(&bdev->bd_part->kobj, action);
- else
- kobject_uevent(&bdev->bd_disk->kobj, action);
- }
-}
-
int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
int (*fill_super)(struct super_block *, void *, int),
@@ -782,7 +772,6 @@ int get_sb_bdev(struct file_system_type *fs_type,
}
s->s_flags |= MS_ACTIVE;
- bdev_uevent(bdev, KOBJ_MOUNT);
}
return simple_set_mnt(mnt, s);
@@ -801,7 +790,6 @@ void kill_block_super(struct super_block *sb)
{
struct block_device *bdev = sb->s_bdev;
- bdev_uevent(bdev, KOBJ_UMOUNT);
generic_shutdown_super(sb);
sync_blockdev(bdev);
close_bdev_excl(bdev);
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index d3b9f5f07db1..8ea2a51ce883 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
if (copy_to_user(userbuf, buffer, count))
return -EFAULT;
- pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
+ pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
*off = offs + count;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index fc4633378dc0..db0413a411d6 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -633,6 +633,7 @@ struct sysfs_schedule_callback_struct {
struct kobject *kobj;
void (*func)(void *);
void *data;
+ struct module *owner;
struct work_struct work;
};
@@ -643,6 +644,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
(ss->func)(ss->data);
kobject_put(ss->kobj);
+ module_put(ss->owner);
kfree(ss);
}
@@ -651,6 +653,7 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
* @kobj: object we're acting for.
* @func: callback function to invoke later.
* @data: argument to pass to @func.
+ * @owner: module owning the callback code
*
* sysfs attribute methods must not unregister themselves or their parent
* kobject (which would amount to the same thing). Attempts to do so will
@@ -663,20 +666,25 @@ static void sysfs_schedule_callback_work(struct work_struct *work)
* until @func returns.
*
* Returns 0 if the request was submitted, -ENOMEM if storage could not
- * be allocated.
+ * be allocated, -ENODEV if a reference to @owner isn't available.
*/
int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
- void *data)
+ void *data, struct module *owner)
{
struct sysfs_schedule_callback_struct *ss;
+ if (!try_module_get(owner))
+ return -ENODEV;
ss = kmalloc(sizeof(*ss), GFP_KERNEL);
- if (!ss)
+ if (!ss) {
+ module_put(owner);
return -ENOMEM;
+ }
kobject_get(kobj);
ss->kobj = kobj;
ss->func = func;
ss->data = data;
+ ss->owner = owner;
INIT_WORK(&ss->work, sysfs_schedule_callback_work);
schedule_work(&ss->work);
return 0;
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index b20951c93761..52eed2a7a5ef 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj,
{
struct dentry * dir;
- if (grp->name)
- dir = lookup_one_len(grp->name, kobj->dentry,
+ if (grp->name) {
+ dir = lookup_one_len_kern(grp->name, kobj->dentry,
strlen(grp->name));
+ BUG_ON(IS_ERR(dir));
+ }
else
dir = dget(kobj->dentry);