#include "print-tree.h"
#include "volumes.h"
#include "locking.h"
+#include "inode-map.h"
/* Mask out flags that are inappropriate for the given type of inode. */
static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
u64 index = 0;
- ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
- 0, &objectid);
+ ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid);
if (ret) {
dput(parent);
return ret;
BUG_ON(ret);
ret = btrfs_insert_dir_item(trans, root,
- name, namelen, dir->i_ino, &key,
+ name, namelen, dir, &key,
BTRFS_FT_DIR, index);
if (ret)
goto fail;
ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
objectid, root->root_key.objectid,
- dir->i_ino, index, name, namelen);
+ btrfs_ino(dir), index, name, namelen);
BUG_ON(ret);
int ret = 0;
u64 flags = 0;
- if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+ if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
return -EINVAL;
down_read(&root->fs_info->subvol_sem);
if (root->fs_info->sb->s_flags & MS_RDONLY)
return -EROFS;
- if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
+ if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
return -EINVAL;
if (copy_from_user(&flags, arg, sizeof(flags)))
}
ret = copy_to_sk(root, path, &key, sk, args->buf,
&sk_offset, &num_found);
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
if (ret || num_found >= sk->nr_items)
break;
if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
break;
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
key.objectid = key.offset;
key.offset = (u64)-1;
dirid = key.objectid;
goto out_dput;
}
- if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) {
+ if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) {
err = -EINVAL;
goto out_dput;
}
return ret;
}
+static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
+{
+ struct btrfs_ioctl_fs_info_args fi_args;
+ struct btrfs_device *device;
+ struct btrfs_device *next;
+ struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ fi_args.num_devices = fs_devices->num_devices;
+ fi_args.max_id = 0;
+ memcpy(&fi_args.fsid, root->fs_info->fsid, sizeof(fi_args.fsid));
+
+ mutex_lock(&fs_devices->device_list_mutex);
+ list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
+ if (device->devid > fi_args.max_id)
+ fi_args.max_id = device->devid;
+ }
+ mutex_unlock(&fs_devices->device_list_mutex);
+
+ if (copy_to_user(arg, &fi_args, sizeof(fi_args)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
+{
+ struct btrfs_ioctl_dev_info_args *di_args;
+ struct btrfs_device *dev;
+ struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+ int ret = 0;
+ char *s_uuid = NULL;
+ char empty_uuid[BTRFS_UUID_SIZE] = {0};
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ di_args = memdup_user(arg, sizeof(*di_args));
+ if (IS_ERR(di_args))
+ return PTR_ERR(di_args);
+
+ if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
+ s_uuid = di_args->uuid;
+
+ mutex_lock(&fs_devices->device_list_mutex);
+ dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL);
+ mutex_unlock(&fs_devices->device_list_mutex);
+
+ if (!dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ di_args->devid = dev->devid;
+ di_args->bytes_used = dev->bytes_used;
+ di_args->total_bytes = dev->total_bytes;
+ memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid));
+ strncpy(di_args->path, dev->name, sizeof(di_args->path));
+
+out:
+ if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args)))
+ ret = -EFAULT;
+
+ kfree(di_args);
+ return ret;
+}
+
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
u64 off, u64 olen, u64 destoff)
{
}
/* clone data */
- key.objectid = src->i_ino;
+ key.objectid = btrfs_ino(src);
key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = 0;
btrfs_item_key_to_cpu(leaf, &key, slot);
if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY ||
- key.objectid != src->i_ino)
+ key.objectid != btrfs_ino(src))
break;
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) {
datal = btrfs_file_extent_ram_bytes(leaf,
extent);
}
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
if (key.offset + datal <= off ||
key.offset >= off+len)
goto next;
memcpy(&new_key, &key, sizeof(new_key));
- new_key.objectid = inode->i_ino;
+ new_key.objectid = btrfs_ino(inode);
if (off <= key.offset)
new_key.offset = key.offset + destoff - off;
else
ret = btrfs_inc_extent_ref(trans, root,
disko, diskl, 0,
root->root_key.objectid,
- inode->i_ino,
+ btrfs_ino(inode),
new_key.offset - datao);
BUG_ON(ret);
}
}
btrfs_mark_buffer_dirty(leaf);
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
btrfs_end_transaction(trans, root);
}
next:
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
key.offset++;
}
ret = 0;
out:
- btrfs_release_path(root, path);
+ btrfs_release_path(path);
unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS);
out_unlock:
mutex_unlock(&src->i_mutex);
return btrfs_wait_for_commit(root, transid);
}
+static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg)
+{
+ int ret;
+ struct btrfs_ioctl_scrub_args *sa;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ sa = memdup_user(arg, sizeof(*sa));
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end,
+ &sa->progress, sa->flags & BTRFS_SCRUB_READONLY);
+
+ if (copy_to_user(arg, sa, sizeof(*sa)))
+ ret = -EFAULT;
+
+ kfree(sa);
+ return ret;
+}
+
+static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return btrfs_scrub_cancel(root);
+}
+
+static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
+ void __user *arg)
+{
+ struct btrfs_ioctl_scrub_args *sa;
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ sa = memdup_user(arg, sizeof(*sa));
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ ret = btrfs_scrub_progress(root, sa->devid, &sa->progress);
+
+ if (copy_to_user(arg, sa, sizeof(*sa)))
+ ret = -EFAULT;
+
+ kfree(sa);
+ return ret;
+}
+
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
{
return btrfs_ioctl_add_dev(root, argp);
case BTRFS_IOC_RM_DEV:
return btrfs_ioctl_rm_dev(root, argp);
+ case BTRFS_IOC_FS_INFO:
+ return btrfs_ioctl_fs_info(root, argp);
+ case BTRFS_IOC_DEV_INFO:
+ return btrfs_ioctl_dev_info(root, argp);
case BTRFS_IOC_BALANCE:
return btrfs_balance(root->fs_info->dev_root);
case BTRFS_IOC_CLONE:
return btrfs_ioctl_start_sync(file, argp);
case BTRFS_IOC_WAIT_SYNC:
return btrfs_ioctl_wait_sync(file, argp);
+ case BTRFS_IOC_SCRUB:
+ return btrfs_ioctl_scrub(root, argp);
+ case BTRFS_IOC_SCRUB_CANCEL:
+ return btrfs_ioctl_scrub_cancel(root, argp);
+ case BTRFS_IOC_SCRUB_PROGRESS:
+ return btrfs_ioctl_scrub_progress(root, argp);
}
return -ENOTTY;