#include <linux/ctype.h>
#include <linux/namei.h>
#include <linux/miscdevice.h>
+#include <linux/version.h>
+#include "compat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "volumes.h"
#include "version.h"
#include "export.h"
+#include "compression.h"
#define BTRFS_SUPER_MAGIC 0x9123683E
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);
+#if 0
+ btrfs_sysfs_del_super(root->fs_info);
+#endif
sb->s_fs_info = NULL;
}
enum {
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
- Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_err,
+ Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_err,
};
static match_table_t tokens = {
{Opt_max_inline, "max_inline=%s"},
{Opt_alloc_start, "alloc_start=%s"},
{Opt_thread_pool, "thread_pool=%d"},
+ {Opt_compress, "compress"},
{Opt_ssd, "ssd"},
{Opt_noacl, "noacl"},
{Opt_err, NULL},
btrfs_set_opt(info->mount_opt, NODATACOW);
btrfs_set_opt(info->mount_opt, NODATASUM);
break;
+ case Opt_compress:
+ printk(KERN_INFO "btrfs: use compression\n");
+ btrfs_set_opt(info->mount_opt, COMPRESS);
+ break;
case Opt_ssd:
printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
btrfs_set_opt(info->mount_opt, SSD);
* 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;
}
}
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;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
save_mount_options(sb, data);
-#endif
-
return 0;
fail_close:
int ret;
root = btrfs_sb(sb);
+ if (sb->s_flags & MS_RDONLY)
+ return 0;
+
sb->s_dirt = 0;
if (!wait) {
filemap_flush(root->fs_info->btree_inode->i_mapping);
return 0;
}
+
+ btrfs_start_delalloc_inodes(root);
+ btrfs_wait_ordered_extents(root, 0);
+
btrfs_clean_old_snapshots(root);
trans = btrfs_start_transaction(root, 1);
ret = btrfs_commit_transaction(trans, root);
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;
- 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))
up_write(&s->s_umount);
deactivate_super(s);
error = -EBUSY;
- goto error_bdev;
+ goto error_close_devices;
}
+ btrfs_close_devices(fs_devices);
} else {
char b[BDEVNAME_SIZE];
error_s:
error = PTR_ERR(s);
-error_bdev:
+error_close_devices:
btrfs_close_devices(fs_devices);
error_free_subvol_name:
kfree(subvol_name);
return error;
}
+static int btrfs_remount(struct super_block *sb, int *flags, char *data)
+{
+ struct btrfs_root *root = btrfs_sb(sb);
+ int ret;
+
+ if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+ return 0;
+
+ if (*flags & MS_RDONLY) {
+ sb->s_flags |= MS_RDONLY;
+
+ 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;
+
+ ret = btrfs_cleanup_reloc_trees(root);
+ WARN_ON(ret);
+
+ ret = btrfs_cleanup_fs_roots(root->fs_info);
+ WARN_ON(ret);
+
+ sb->s_flags &= ~MS_RDONLY;
+ }
+
+ return 0;
+}
+
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct btrfs_root *root = btrfs_sb(dentry->d_sb);
.fs_flags = FS_REQUIRES_DEV,
};
+/*
+ * used by btrfsctl to scan devices when no FS is mounted
+ */
static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
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;
}
.put_super = btrfs_put_super,
.write_super = btrfs_write_super,
.sync_fs = btrfs_sync_fs,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
- .read_inode = btrfs_read_locked_inode,
-#else
.show_options = generic_show_options,
-#endif
.write_inode = btrfs_write_inode,
.dirty_inode = btrfs_dirty_inode,
.alloc_inode = btrfs_alloc_inode,
.destroy_inode = btrfs_destroy_inode,
.statfs = btrfs_statfs,
+ .remount_fs = btrfs_remount,
.write_super_lockfs = btrfs_write_super_lockfs,
.unlockfs = btrfs_unlockfs,
};
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");
err = btrfs_interface_init();
if (err)
goto free_extent_map;
+
err = register_filesystem(&btrfs_fs_type);
if (err)
goto unregister_ioctl;
unregister_filesystem(&btrfs_fs_type);
btrfs_exit_sysfs();
btrfs_cleanup_fs_uuids();
+ btrfs_zlib_exit();
}
module_init(init_btrfs_fs)