#include <linux/ctype.h>
#include <linux/namei.h>
#include <linux/miscdevice.h>
+#include <linux/version.h>
+#include <linux/magic.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "export.h"
#include "compression.h"
-#define BTRFS_SUPER_MAGIC 0x9123683E
static struct super_operations btrfs_super_ops;
-static void btrfs_put_super (struct super_block * sb)
+static void btrfs_put_super(struct super_block *sb)
{
struct btrfs_root *root = btrfs_sb(sb);
- struct btrfs_fs_info *fs = root->fs_info;
int ret;
ret = close_ctree(root);
- if (ret) {
- printk("close ctree returns %d\n", ret);
- }
- btrfs_sysfs_del_super(fs);
sb->s_fs_info = NULL;
}
* All other options will be parsed on much later in the mount process and
* only when we need to allocate a new super block.
*/
-static int btrfs_parse_early_options(const char *options, int flags,
+static int btrfs_parse_early_options(const char *options, fmode_t flags,
void *holder, char **subvol_name,
struct btrfs_fs_devices **fs_devices)
{
out:
/*
* If no subvolume name is specified we use the default one. Allocate
- * a copy of the string "default" here so that code later in the
+ * a copy of the string "." here so that code later in the
* mount path doesn't care if it's the default volume or another one.
*/
if (!*subvol_name) {
- *subvol_name = kstrdup("default", GFP_KERNEL);
+ *subvol_name = kstrdup(".", GFP_KERNEL);
if (!*subvol_name)
return -ENOMEM;
}
return error;
}
-static int btrfs_fill_super(struct super_block * sb,
+static int btrfs_fill_super(struct super_block *sb,
struct btrfs_fs_devices *fs_devices,
- void * data, int silent)
+ void *data, int silent)
{
- struct inode * inode;
- struct dentry * root_dentry;
+ struct inode *inode;
+ struct dentry *root_dentry;
struct btrfs_super_block *disk_super;
struct btrfs_root *tree_root;
struct btrfs_inode *bi;
}
sb->s_fs_info = tree_root;
disk_super = &tree_root->fs_info->super_copy;
- inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super),
- tree_root);
+ inode = btrfs_iget_locked(sb, BTRFS_FIRST_FREE_OBJECTID,
+ tree_root->fs_info->fs_root);
bi = BTRFS_I(inode);
bi->location.objectid = inode->i_ino;
bi->location.offset = 0;
- bi->root = tree_root;
+ bi->root = tree_root->fs_info->fs_root;
btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY);
err = -ENOMEM;
goto fail_close;
}
-
+#if 0
/* this does the super kobj at the same time */
err = btrfs_sysfs_add_super(tree_root->fs_info);
if (err)
goto fail_close;
+#endif
sb->s_root = root_dentry;
struct super_block *s;
struct dentry *root;
struct btrfs_fs_devices *fs_devices = NULL;
+ fmode_t mode = FMODE_READ;
int error = 0;
- error = btrfs_parse_early_options(data, flags, fs_type,
+ if (!(flags & MS_RDONLY))
+ mode |= FMODE_WRITE;
+
+ error = btrfs_parse_early_options(data, mode, fs_type,
&subvol_name, &fs_devices);
if (error)
- goto error;
+ return error;
- error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices);
+ error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices);
if (error)
goto error_free_subvol_name;
- error = btrfs_open_devices(fs_devices, flags, fs_type);
+ error = btrfs_open_devices(fs_devices, mode, fs_type);
if (error)
goto error_free_subvol_name;
+ if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
+ error = -EACCES;
+ goto error_close_devices;
+ }
+
bdev = fs_devices->latest_bdev;
s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
if (IS_ERR(s))
goto error_close_devices;
}
+ btrfs_close_devices(fs_devices);
} else {
char b[BDEVNAME_SIZE];
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- goto error;
+ goto error_free_subvol_name;
}
btrfs_sb(s)->fs_info->bdev_holder = fs_type;
root = dget(s->s_root);
else {
mutex_lock(&s->s_root->d_inode->i_mutex);
- root = lookup_one_len(subvol_name, s->s_root, strlen(subvol_name));
+ root = lookup_one_len(subvol_name, s->s_root,
+ strlen(subvol_name));
mutex_unlock(&s->s_root->d_inode->i_mutex);
+
if (IS_ERR(root)) {
up_write(&s->s_umount);
deactivate_super(s);
error = PTR_ERR(root);
- goto error;
+ goto error_free_subvol_name;
}
if (!root->d_inode) {
dput(root);
up_write(&s->s_umount);
deactivate_super(s);
error = -ENXIO;
- goto error;
+ goto error_free_subvol_name;
}
}
btrfs_close_devices(fs_devices);
error_free_subvol_name:
kfree(subvol_name);
-error:
return error;
}
ret = btrfs_commit_super(root);
WARN_ON(ret);
} else {
+ if (root->fs_info->fs_devices->rw_devices == 0)
+ return -EACCES;
+
if (btrfs_super_log_root(&root->fs_info->super_copy) != 0)
return -EINVAL;
buf->f_bavail = buf->f_bfree;
buf->f_bsize = dentry->d_sb->s_blocksize;
buf->f_type = BTRFS_SUPER_MAGIC;
+
/* We treat it as constant endianness (it doesn't matter _which_)
- because we want the fsid to come out the same whether mounted
+ because we want the fsid to come out the same whether mounted
on a big-endian or little-endian host */
buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]);
buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]);
{
struct btrfs_ioctl_vol_args *vol;
struct btrfs_fs_devices *fs_devices;
- int ret = 0;
+ int ret = -ENOTTY;
int len;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
vol = kmalloc(sizeof(*vol), GFP_KERNEL);
if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
ret = -EFAULT;
goto out;
}
len = strnlen(vol->name, BTRFS_PATH_NAME_MAX);
+
switch (cmd) {
case BTRFS_IOC_SCAN_DEV:
- ret = btrfs_scan_one_device(vol->name, MS_RDONLY,
+ ret = btrfs_scan_one_device(vol->name, FMODE_READ,
&btrfs_fs_type, &fs_devices);
break;
}
return ret;
}
-static void btrfs_write_super_lockfs(struct super_block *sb)
+static int btrfs_freeze(struct super_block *sb)
{
struct btrfs_root *root = btrfs_sb(sb);
mutex_lock(&root->fs_info->transaction_kthread_mutex);
mutex_lock(&root->fs_info->cleaner_mutex);
+ return 0;
}
-static void btrfs_unlockfs(struct super_block *sb)
+static int btrfs_unfreeze(struct super_block *sb)
{
struct btrfs_root *root = btrfs_sb(sb);
mutex_unlock(&root->fs_info->cleaner_mutex);
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
+ return 0;
}
static struct super_operations btrfs_super_ops = {
.destroy_inode = btrfs_destroy_inode,
.statfs = btrfs_statfs,
.remount_fs = btrfs_remount,
- .write_super_lockfs = btrfs_write_super_lockfs,
- .unlockfs = btrfs_unlockfs,
+ .freeze_fs = btrfs_freeze,
+ .unfreeze_fs = btrfs_unfreeze,
};
static const struct file_operations btrfs_ctl_fops = {
return misc_register(&btrfs_misc);
}
-void btrfs_interface_exit(void)
+static void btrfs_interface_exit(void)
{
if (misc_deregister(&btrfs_misc) < 0)
- printk("misc_deregister failed for control device");
+ printk(KERN_INFO "misc_deregister failed for control device");
}
static int __init init_btrfs_fs(void)