Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
36fac9e9
K
Kernel
项目概览
openeuler
/
Kernel
12 个月 前同步成功
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
36fac9e9
编写于
5月 16, 2016
作者:
D
David Sterba
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'foreign/anand/dev-del-by-id-ext' into for-chris-4.7-20160516
上级
5ef64a3e
88acff64
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
324 addition
and
242 deletion
+324
-242
fs/btrfs/dev-replace.c
fs/btrfs/dev-replace.c
+44
-55
fs/btrfs/dev-replace.h
fs/btrfs/dev-replace.h
+3
-1
fs/btrfs/ioctl.c
fs/btrfs/ioctl.c
+58
-2
fs/btrfs/volumes.c
fs/btrfs/volumes.c
+198
-181
fs/btrfs/volumes.h
fs/btrfs/volumes.h
+7
-2
include/uapi/linux/btrfs.h
include/uapi/linux/btrfs.h
+14
-1
未找到文件。
fs/btrfs/dev-replace.c
浏览文件 @
36fac9e9
...
...
@@ -44,9 +44,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_device
*
srcdev
,
struct
btrfs_device
*
tgtdev
);
static
int
btrfs_dev_replace_find_srcdev
(
struct
btrfs_root
*
root
,
u64
srcdevid
,
char
*
srcdev_name
,
struct
btrfs_device
**
device
);
static
u64
__btrfs_dev_replace_cancel
(
struct
btrfs_fs_info
*
fs_info
);
static
int
btrfs_dev_replace_kthread
(
void
*
data
);
static
int
btrfs_dev_replace_continue_on_mount
(
struct
btrfs_fs_info
*
fs_info
);
...
...
@@ -305,8 +302,8 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
dev_replace
->
cursor_left_last_write_of_item
;
}
int
btrfs_dev_replace_start
(
struct
btrfs_root
*
root
,
struct
btrfs_ioctl_dev_replace_args
*
args
)
int
btrfs_dev_replace_start
(
struct
btrfs_root
*
root
,
char
*
tgtdev_name
,
u64
srcdevid
,
char
*
srcdev_name
,
int
read_src
)
{
struct
btrfs_trans_handle
*
trans
;
struct
btrfs_fs_info
*
fs_info
=
root
->
fs_info
;
...
...
@@ -315,29 +312,16 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
struct
btrfs_device
*
tgt_device
=
NULL
;
struct
btrfs_device
*
src_device
=
NULL
;
switch
(
args
->
start
.
cont_reading_from_srcdev_mode
)
{
case
BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS
:
case
BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID
:
break
;
default:
return
-
EINVAL
;
}
if
((
args
->
start
.
srcdevid
==
0
&&
args
->
start
.
srcdev_name
[
0
]
==
'\0'
)
||
args
->
start
.
tgtdev_name
[
0
]
==
'\0'
)
return
-
EINVAL
;
/* the disk copy procedure reuses the scrub code */
mutex_lock
(
&
fs_info
->
volume_mutex
);
ret
=
btrfs_dev_replace_find_srcdev
(
root
,
args
->
start
.
srcdevid
,
args
->
start
.
srcdev_name
,
&
src_device
);
ret
=
btrfs_find_device_by_devspec
(
root
,
srcdevid
,
srcdev_name
,
&
src_device
);
if
(
ret
)
{
mutex_unlock
(
&
fs_info
->
volume_mutex
);
return
ret
;
}
ret
=
btrfs_init_dev_replace_tgtdev
(
root
,
args
->
start
.
tgtdev_name
,
ret
=
btrfs_init_dev_replace_tgtdev
(
root
,
tgtdev_name
,
src_device
,
&
tgt_device
);
mutex_unlock
(
&
fs_info
->
volume_mutex
);
if
(
ret
)
...
...
@@ -364,18 +348,17 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
break
;
case
BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED
:
case
BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED
:
args
->
resul
t
=
BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED
;
re
t
=
BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED
;
goto
leave
;
}
dev_replace
->
cont_reading_from_srcdev_mode
=
args
->
start
.
cont_reading_from_srcdev_mode
;
dev_replace
->
cont_reading_from_srcdev_mode
=
read_src
;
WARN_ON
(
!
src_device
);
dev_replace
->
srcdev
=
src_device
;
WARN_ON
(
!
tgt_device
);
dev_replace
->
tgtdev
=
tgt_device
;
btrfs_info_in_rcu
(
root
->
fs_info
,
btrfs_info_in_rcu
(
fs_info
,
"dev_replace from %s (devid %llu) to %s started"
,
src_device
->
missing
?
"<missing disk>"
:
rcu_str_deref
(
src_device
->
name
),
...
...
@@ -396,14 +379,13 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
dev_replace
->
item_needs_writeback
=
1
;
atomic64_set
(
&
dev_replace
->
num_write_errors
,
0
);
atomic64_set
(
&
dev_replace
->
num_uncorrectable_read_errors
,
0
);
args
->
result
=
BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR
;
btrfs_dev_replace_unlock
(
dev_replace
,
1
);
ret
=
btrfs_sysfs_add_device_link
(
tgt_device
->
fs_devices
,
tgt_device
);
if
(
ret
)
btrfs_err
(
root
->
fs_info
,
"kobj add dev failed %d
\n
"
,
ret
);
btrfs_err
(
fs_info
,
"kobj add dev failed %d
\n
"
,
ret
);
btrfs_wait_ordered_roots
(
root
->
fs_info
,
-
1
);
btrfs_wait_ordered_roots
(
fs_info
,
-
1
);
/* force writing the updated state information to disk */
trans
=
btrfs_start_transaction
(
root
,
0
);
...
...
@@ -421,11 +403,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
btrfs_device_get_total_bytes
(
src_device
),
&
dev_replace
->
scrub_progress
,
0
,
1
);
ret
=
btrfs_dev_replace_finishing
(
root
->
fs_info
,
ret
);
/* don't warn if EINPROGRESS, someone else might be running scrub */
ret
=
btrfs_dev_replace_finishing
(
fs_info
,
ret
);
if
(
ret
==
-
EINPROGRESS
)
{
args
->
result
=
BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS
;
ret
=
0
;
ret
=
BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS
;
}
else
{
WARN_ON
(
ret
);
}
...
...
@@ -440,6 +420,35 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
return
ret
;
}
int
btrfs_dev_replace_by_ioctl
(
struct
btrfs_root
*
root
,
struct
btrfs_ioctl_dev_replace_args
*
args
)
{
int
ret
;
switch
(
args
->
start
.
cont_reading_from_srcdev_mode
)
{
case
BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS
:
case
BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID
:
break
;
default:
return
-
EINVAL
;
}
if
((
args
->
start
.
srcdevid
==
0
&&
args
->
start
.
srcdev_name
[
0
]
==
'\0'
)
||
args
->
start
.
tgtdev_name
[
0
]
==
'\0'
)
return
-
EINVAL
;
ret
=
btrfs_dev_replace_start
(
root
,
args
->
start
.
tgtdev_name
,
args
->
start
.
srcdevid
,
args
->
start
.
srcdev_name
,
args
->
start
.
cont_reading_from_srcdev_mode
);
args
->
result
=
ret
;
/* don't warn if EINPROGRESS, someone else might be running scrub */
if
(
ret
==
BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS
)
ret
=
0
;
return
ret
;
}
/*
* blocked until all flighting bios are finished.
*/
...
...
@@ -560,10 +569,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
ASSERT
(
list_empty
(
&
src_device
->
resized_list
));
tgt_device
->
commit_total_bytes
=
src_device
->
commit_total_bytes
;
tgt_device
->
commit_bytes_used
=
src_device
->
bytes_used
;
if
(
fs_info
->
sb
->
s_bdev
==
src_device
->
bdev
)
fs_info
->
sb
->
s_bdev
=
tgt_device
->
bdev
;
if
(
fs_info
->
fs_devices
->
latest_bdev
==
src_device
->
bdev
)
fs_info
->
fs_devices
->
latest_bdev
=
tgt_device
->
bdev
;
btrfs_assign_next_active_device
(
fs_info
,
src_device
,
tgt_device
);
list_add
(
&
tgt_device
->
dev_alloc_list
,
&
fs_info
->
fs_devices
->
alloc_list
);
fs_info
->
fs_devices
->
rw_devices
++
;
...
...
@@ -626,25 +634,6 @@ static void btrfs_dev_replace_update_device_in_mapping_tree(
write_unlock
(
&
em_tree
->
lock
);
}
static
int
btrfs_dev_replace_find_srcdev
(
struct
btrfs_root
*
root
,
u64
srcdevid
,
char
*
srcdev_name
,
struct
btrfs_device
**
device
)
{
int
ret
;
if
(
srcdevid
)
{
ret
=
0
;
*
device
=
btrfs_find_device
(
root
->
fs_info
,
srcdevid
,
NULL
,
NULL
);
if
(
!*
device
)
ret
=
-
ENOENT
;
}
else
{
ret
=
btrfs_find_device_missing_or_by_path
(
root
,
srcdev_name
,
device
);
}
return
ret
;
}
void
btrfs_dev_replace_status
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_ioctl_dev_replace_args
*
args
)
{
...
...
fs/btrfs/dev-replace.h
浏览文件 @
36fac9e9
...
...
@@ -25,8 +25,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
int
btrfs_run_dev_replace
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_fs_info
*
fs_info
);
void
btrfs_after_dev_replace_commit
(
struct
btrfs_fs_info
*
fs_info
);
int
btrfs_dev_replace_
start
(
struct
btrfs_root
*
root
,
int
btrfs_dev_replace_
by_ioctl
(
struct
btrfs_root
*
root
,
struct
btrfs_ioctl_dev_replace_args
*
args
);
int
btrfs_dev_replace_start
(
struct
btrfs_root
*
root
,
char
*
tgtdev_name
,
u64
srcdevid
,
char
*
srcdev_name
,
int
read_src
);
void
btrfs_dev_replace_status
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_ioctl_dev_replace_args
*
args
);
int
btrfs_dev_replace_cancel
(
struct
btrfs_fs_info
*
fs_info
,
...
...
fs/btrfs/ioctl.c
浏览文件 @
36fac9e9
...
...
@@ -2676,6 +2676,60 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
return
ret
;
}
static
long
btrfs_ioctl_rm_dev_v2
(
struct
file
*
file
,
void
__user
*
arg
)
{
struct
btrfs_root
*
root
=
BTRFS_I
(
file_inode
(
file
))
->
root
;
struct
btrfs_ioctl_vol_args_v2
*
vol_args
;
int
ret
;
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
ret
=
mnt_want_write_file
(
file
);
if
(
ret
)
return
ret
;
vol_args
=
memdup_user
(
arg
,
sizeof
(
*
vol_args
));
if
(
IS_ERR
(
vol_args
))
{
ret
=
PTR_ERR
(
vol_args
);
goto
err_drop
;
}
/* Check for compatibility reject unknown flags */
if
(
vol_args
->
flags
&
~
BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED
)
return
-
EOPNOTSUPP
;
if
(
atomic_xchg
(
&
root
->
fs_info
->
mutually_exclusive_operation_running
,
1
))
{
ret
=
BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS
;
goto
out
;
}
mutex_lock
(
&
root
->
fs_info
->
volume_mutex
);
if
(
vol_args
->
flags
&
BTRFS_DEVICE_SPEC_BY_ID
)
{
ret
=
btrfs_rm_device
(
root
,
NULL
,
vol_args
->
devid
);
}
else
{
vol_args
->
name
[
BTRFS_SUBVOL_NAME_MAX
]
=
'\0'
;
ret
=
btrfs_rm_device
(
root
,
vol_args
->
name
,
0
);
}
mutex_unlock
(
&
root
->
fs_info
->
volume_mutex
);
atomic_set
(
&
root
->
fs_info
->
mutually_exclusive_operation_running
,
0
);
if
(
!
ret
)
{
if
(
vol_args
->
flags
&
BTRFS_DEVICE_SPEC_BY_ID
)
btrfs_info
(
root
->
fs_info
,
"device deleted: id %llu"
,
vol_args
->
devid
);
else
btrfs_info
(
root
->
fs_info
,
"device deleted: %s"
,
vol_args
->
name
);
}
out:
kfree
(
vol_args
);
err_drop:
mnt_drop_write_file
(
file
);
return
ret
;
}
static
long
btrfs_ioctl_rm_dev
(
struct
file
*
file
,
void
__user
*
arg
)
{
struct
btrfs_root
*
root
=
BTRFS_I
(
file_inode
(
file
))
->
root
;
...
...
@@ -2703,7 +2757,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
vol_args
->
name
[
BTRFS_PATH_NAME_MAX
]
=
'\0'
;
mutex_lock
(
&
root
->
fs_info
->
volume_mutex
);
ret
=
btrfs_rm_device
(
root
,
vol_args
->
name
);
ret
=
btrfs_rm_device
(
root
,
vol_args
->
name
,
0
);
mutex_unlock
(
&
root
->
fs_info
->
volume_mutex
);
if
(
!
ret
)
...
...
@@ -4387,7 +4441,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
1
))
{
ret
=
BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS
;
}
else
{
ret
=
btrfs_dev_replace_
start
(
root
,
p
);
ret
=
btrfs_dev_replace_
by_ioctl
(
root
,
p
);
atomic_set
(
&
root
->
fs_info
->
mutually_exclusive_operation_running
,
0
);
...
...
@@ -5480,6 +5534,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return
btrfs_ioctl_add_dev
(
root
,
argp
);
case
BTRFS_IOC_RM_DEV
:
return
btrfs_ioctl_rm_dev
(
file
,
argp
);
case
BTRFS_IOC_RM_DEV_V2
:
return
btrfs_ioctl_rm_dev_v2
(
file
,
argp
);
case
BTRFS_IOC_FS_INFO
:
return
btrfs_ioctl_fs_info
(
root
,
argp
);
case
BTRFS_IOC_DEV_INFO
:
...
...
fs/btrfs/volumes.c
浏览文件 @
36fac9e9
...
...
@@ -118,6 +118,21 @@ const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = {
[
BTRFS_RAID_RAID6
]
=
BTRFS_BLOCK_GROUP_RAID6
,
};
/*
* Table to convert BTRFS_RAID_* to the error code if minimum number of devices
* condition is not met. Zero means there's no corresponding
* BTRFS_ERROR_DEV_*_NOT_MET value.
*/
const
int
btrfs_raid_mindev_error
[
BTRFS_NR_RAID_TYPES
]
=
{
[
BTRFS_RAID_RAID10
]
=
BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET
,
[
BTRFS_RAID_RAID1
]
=
BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET
,
[
BTRFS_RAID_DUP
]
=
0
,
[
BTRFS_RAID_RAID0
]
=
0
,
[
BTRFS_RAID_SINGLE
]
=
0
,
[
BTRFS_RAID_RAID5
]
=
BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET
,
[
BTRFS_RAID_RAID6
]
=
BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET
,
};
static
int
init_first_rw_device
(
struct
btrfs_trans_handle
*
trans
,
struct
btrfs_root
*
root
,
struct
btrfs_device
*
device
);
...
...
@@ -699,7 +714,8 @@ static noinline int device_list_add(const char *path,
* if there is new btrfs on an already registered device,
* then remove the stale device entry.
*/
btrfs_free_stale_device
(
device
);
if
(
ret
>
0
)
btrfs_free_stale_device
(
device
);
*
fs_devices_ret
=
fs_devices
;
...
...
@@ -988,6 +1004,56 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
return
ret
;
}
void
btrfs_release_disk_super
(
struct
page
*
page
)
{
kunmap
(
page
);
put_page
(
page
);
}
int
btrfs_read_disk_super
(
struct
block_device
*
bdev
,
u64
bytenr
,
struct
page
**
page
,
struct
btrfs_super_block
**
disk_super
)
{
void
*
p
;
pgoff_t
index
;
/* make sure our super fits in the device */
if
(
bytenr
+
PAGE_SIZE
>=
i_size_read
(
bdev
->
bd_inode
))
return
1
;
/* make sure our super fits in the page */
if
(
sizeof
(
**
disk_super
)
>
PAGE_SIZE
)
return
1
;
/* make sure our super doesn't straddle pages on disk */
index
=
bytenr
>>
PAGE_SHIFT
;
if
((
bytenr
+
sizeof
(
**
disk_super
)
-
1
)
>>
PAGE_SHIFT
!=
index
)
return
1
;
/* pull in the page with our super */
*
page
=
read_cache_page_gfp
(
bdev
->
bd_inode
->
i_mapping
,
index
,
GFP_KERNEL
);
if
(
IS_ERR_OR_NULL
(
*
page
))
return
1
;
p
=
kmap
(
*
page
);
/* align our pointer to the offset of the super block */
*
disk_super
=
p
+
(
bytenr
&
~
PAGE_MASK
);
if
(
btrfs_super_bytenr
(
*
disk_super
)
!=
bytenr
||
btrfs_super_magic
(
*
disk_super
)
!=
BTRFS_MAGIC
)
{
btrfs_release_disk_super
(
*
page
);
return
1
;
}
if
((
*
disk_super
)
->
label
[
0
]
&&
(
*
disk_super
)
->
label
[
BTRFS_LABEL_SIZE
-
1
])
(
*
disk_super
)
->
label
[
BTRFS_LABEL_SIZE
-
1
]
=
'\0'
;
return
0
;
}
/*
* Look for a btrfs signature on a device. This may be called out of the mount path
* and we are not allowed to call set_blocksize during the scan. The superblock
...
...
@@ -999,13 +1065,11 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
struct
btrfs_super_block
*
disk_super
;
struct
block_device
*
bdev
;
struct
page
*
page
;
void
*
p
;
int
ret
=
-
EINVAL
;
u64
devid
;
u64
transid
;
u64
total_devices
;
u64
bytenr
;
pgoff_t
index
;
/*
* we would like to check all the supers, but that would make
...
...
@@ -1018,41 +1082,14 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
mutex_lock
(
&
uuid_mutex
);
bdev
=
blkdev_get_by_path
(
path
,
flags
,
holder
);
if
(
IS_ERR
(
bdev
))
{
ret
=
PTR_ERR
(
bdev
);
goto
error
;
}
/* make sure our super fits in the device */
if
(
bytenr
+
PAGE_SIZE
>=
i_size_read
(
bdev
->
bd_inode
))
goto
error_bdev_put
;
/* make sure our super fits in the page */
if
(
sizeof
(
*
disk_super
)
>
PAGE_SIZE
)
if
(
btrfs_read_disk_super
(
bdev
,
bytenr
,
&
page
,
&
disk_super
))
goto
error_bdev_put
;
/* make sure our super doesn't straddle pages on disk */
index
=
bytenr
>>
PAGE_SHIFT
;
if
((
bytenr
+
sizeof
(
*
disk_super
)
-
1
)
>>
PAGE_SHIFT
!=
index
)
goto
error_bdev_put
;
/* pull in the page with our super */
page
=
read_cache_page_gfp
(
bdev
->
bd_inode
->
i_mapping
,
index
,
GFP_NOFS
);
if
(
IS_ERR_OR_NULL
(
page
))
goto
error_bdev_put
;
p
=
kmap
(
page
);
/* align our pointer to the offset of the super block */
disk_super
=
p
+
(
bytenr
&
~
PAGE_MASK
);
if
(
btrfs_super_bytenr
(
disk_super
)
!=
bytenr
||
btrfs_super_magic
(
disk_super
)
!=
BTRFS_MAGIC
)
goto
error_unmap
;
devid
=
btrfs_stack_device_id
(
&
disk_super
->
dev_item
);
transid
=
btrfs_super_generation
(
disk_super
);
total_devices
=
btrfs_super_num_devices
(
disk_super
);
...
...
@@ -1060,8 +1097,6 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
ret
=
device_list_add
(
path
,
disk_super
,
devid
,
fs_devices_ret
);
if
(
ret
>
0
)
{
if
(
disk_super
->
label
[
0
])
{
if
(
disk_super
->
label
[
BTRFS_LABEL_SIZE
-
1
])
disk_super
->
label
[
BTRFS_LABEL_SIZE
-
1
]
=
'\0'
;
printk
(
KERN_INFO
"BTRFS: device label %s "
,
disk_super
->
label
);
}
else
{
printk
(
KERN_INFO
"BTRFS: device fsid %pU "
,
disk_super
->
fsid
);
...
...
@@ -1073,9 +1108,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
if
(
!
ret
&&
fs_devices_ret
)
(
*
fs_devices_ret
)
->
total_devices
=
total_devices
;
error_unmap:
kunmap
(
page
);
put_page
(
page
);
btrfs_release_disk_super
(
page
);
error_bdev_put:
blkdev_put
(
bdev
,
flags
);
...
...
@@ -1688,32 +1721,92 @@ static int btrfs_rm_dev_item(struct btrfs_root *root,
return
ret
;
}
int
btrfs_rm_device
(
struct
btrfs_root
*
root
,
char
*
device_path
)
/*
* Verify that @num_devices satisfies the RAID profile constraints in the whole
* filesystem. It's up to the caller to adjust that number regarding eg. device
* replace.
*/
static
int
btrfs_check_raid_min_devices
(
struct
btrfs_fs_info
*
fs_info
,
u64
num_devices
)
{
u64
all_avail
;
unsigned
seq
;
int
i
;
do
{
seq
=
read_seqbegin
(
&
fs_info
->
profiles_lock
);
all_avail
=
fs_info
->
avail_data_alloc_bits
|
fs_info
->
avail_system_alloc_bits
|
fs_info
->
avail_metadata_alloc_bits
;
}
while
(
read_seqretry
(
&
fs_info
->
profiles_lock
,
seq
));
for
(
i
=
0
;
i
<
BTRFS_NR_RAID_TYPES
;
i
++
)
{
if
(
!
(
all_avail
&
btrfs_raid_group
[
i
]))
continue
;
if
(
num_devices
<
btrfs_raid_array
[
i
].
devs_min
)
{
int
ret
=
btrfs_raid_mindev_error
[
i
];
if
(
ret
)
return
ret
;
}
}
return
0
;
}
struct
btrfs_device
*
btrfs_find_next_active_device
(
struct
btrfs_fs_devices
*
fs_devs
,
struct
btrfs_device
*
device
)
{
struct
btrfs_device
*
device
;
struct
btrfs_device
*
next_device
;
struct
block_device
*
bdev
;
struct
buffer_head
*
bh
=
NULL
;
struct
btrfs_super_block
*
disk_super
;
list_for_each_entry
(
next_device
,
&
fs_devs
->
devices
,
dev_list
)
{
if
(
next_device
!=
device
&&
!
next_device
->
missing
&&
next_device
->
bdev
)
return
next_device
;
}
return
NULL
;
}
/*
* Helper function to check if the given device is part of s_bdev / latest_bdev
* and replace it with the provided or the next active device, in the context
* where this function called, there should be always be another device (or
* this_dev) which is active.
*/
void
btrfs_assign_next_active_device
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_device
*
device
,
struct
btrfs_device
*
this_dev
)
{
struct
btrfs_device
*
next_device
;
if
(
this_dev
)
next_device
=
this_dev
;
else
next_device
=
btrfs_find_next_active_device
(
fs_info
->
fs_devices
,
device
);
ASSERT
(
next_device
);
if
(
fs_info
->
sb
->
s_bdev
&&
(
fs_info
->
sb
->
s_bdev
==
device
->
bdev
))
fs_info
->
sb
->
s_bdev
=
next_device
->
bdev
;
if
(
fs_info
->
fs_devices
->
latest_bdev
==
device
->
bdev
)
fs_info
->
fs_devices
->
latest_bdev
=
next_device
->
bdev
;
}
int
btrfs_rm_device
(
struct
btrfs_root
*
root
,
char
*
device_path
,
u64
devid
)
{
struct
btrfs_device
*
device
;
struct
btrfs_fs_devices
*
cur_devices
;
u64
all_avail
;
u64
devid
;
u64
num_devices
;
u8
*
dev_uuid
;
unsigned
seq
;
int
ret
=
0
;
bool
clear_super
=
false
;
char
*
dev_name
=
NULL
;
mutex_lock
(
&
uuid_mutex
);
do
{
seq
=
read_seqbegin
(
&
root
->
fs_info
->
profiles_lock
);
all_avail
=
root
->
fs_info
->
avail_data_alloc_bits
|
root
->
fs_info
->
avail_system_alloc_bits
|
root
->
fs_info
->
avail_metadata_alloc_bits
;
}
while
(
read_seqretry
(
&
root
->
fs_info
->
profiles_lock
,
seq
));
num_devices
=
root
->
fs_info
->
fs_devices
->
num_devices
;
btrfs_dev_replace_lock
(
&
root
->
fs_info
->
dev_replace
,
0
);
if
(
btrfs_dev_replace_is_ongoing
(
&
root
->
fs_info
->
dev_replace
))
{
...
...
@@ -1722,78 +1815,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
}
btrfs_dev_replace_unlock
(
&
root
->
fs_info
->
dev_replace
,
0
);
if
((
all_avail
&
BTRFS_BLOCK_GROUP_RAID10
)
&&
num_devices
<=
4
)
{
ret
=
BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET
;
goto
out
;
}
if
((
all_avail
&
BTRFS_BLOCK_GROUP_RAID1
)
&&
num_devices
<=
2
)
{
ret
=
BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET
;
ret
=
btrfs_check_raid_min_devices
(
root
->
fs_info
,
num_devices
-
1
);
if
(
ret
)
goto
out
;
}
if
((
all_avail
&
BTRFS_BLOCK_GROUP_RAID5
)
&&
root
->
fs_info
->
fs_devices
->
rw_devices
<=
2
)
{
ret
=
BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET
;
goto
out
;
}
if
((
all_avail
&
BTRFS_BLOCK_GROUP_RAID6
)
&&
root
->
fs_info
->
fs_devices
->
rw_devices
<=
3
)
{
ret
=
BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET
;
ret
=
btrfs_find_device_by_devspec
(
root
,
devid
,
device_path
,
&
device
);
if
(
ret
)
goto
out
;
}
if
(
strcmp
(
device_path
,
"missing"
)
==
0
)
{
struct
list_head
*
devices
;
struct
btrfs_device
*
tmp
;
device
=
NULL
;
devices
=
&
root
->
fs_info
->
fs_devices
->
devices
;
/*
* It is safe to read the devices since the volume_mutex
* is held.
*/
list_for_each_entry
(
tmp
,
devices
,
dev_list
)
{
if
(
tmp
->
in_fs_metadata
&&
!
tmp
->
is_tgtdev_for_dev_replace
&&
!
tmp
->
bdev
)
{
device
=
tmp
;
break
;
}
}
bdev
=
NULL
;
bh
=
NULL
;
disk_super
=
NULL
;
if
(
!
device
)
{
ret
=
BTRFS_ERROR_DEV_MISSING_NOT_FOUND
;
goto
out
;
}
}
else
{
ret
=
btrfs_get_bdev_and_sb
(
device_path
,
FMODE_WRITE
|
FMODE_EXCL
,
root
->
fs_info
->
bdev_holder
,
0
,
&
bdev
,
&
bh
);
if
(
ret
)
goto
out
;
disk_super
=
(
struct
btrfs_super_block
*
)
bh
->
b_data
;
devid
=
btrfs_stack_device_id
(
&
disk_super
->
dev_item
);
dev_uuid
=
disk_super
->
dev_item
.
uuid
;
device
=
btrfs_find_device
(
root
->
fs_info
,
devid
,
dev_uuid
,
disk_super
->
fsid
);
if
(
!
device
)
{
ret
=
-
ENOENT
;
goto
error_brelse
;
}
}
if
(
device
->
is_tgtdev_for_dev_replace
)
{
ret
=
BTRFS_ERROR_DEV_TGT_REPLACE
;
goto
error_brelse
;
goto
out
;
}
if
(
device
->
writeable
&&
root
->
fs_info
->
fs_devices
->
rw_devices
==
1
)
{
ret
=
BTRFS_ERROR_DEV_ONLY_WRITABLE
;
goto
error_brelse
;
goto
out
;
}
if
(
device
->
writeable
)
{
...
...
@@ -1801,6 +1839,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
list_del_init
(
&
device
->
dev_alloc_list
);
device
->
fs_devices
->
rw_devices
--
;
unlock_chunks
(
root
);
dev_name
=
kstrdup
(
device
->
name
->
str
,
GFP_KERNEL
);
if
(
!
dev_name
)
{
ret
=
-
ENOMEM
;
goto
error_undo
;
}
clear_super
=
true
;
}
...
...
@@ -1842,12 +1885,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
if
(
device
->
missing
)
device
->
fs_devices
->
missing_devices
--
;
next_device
=
list_entry
(
root
->
fs_info
->
fs_devices
->
devices
.
next
,
struct
btrfs_device
,
dev_list
);
if
(
device
->
bdev
==
root
->
fs_info
->
sb
->
s_bdev
)
root
->
fs_info
->
sb
->
s_bdev
=
next_device
->
bdev
;
if
(
device
->
bdev
==
root
->
fs_info
->
fs_devices
->
latest_bdev
)
root
->
fs_info
->
fs_devices
->
latest_bdev
=
next_device
->
bdev
;
btrfs_assign_next_active_device
(
root
->
fs_info
,
device
,
NULL
);
if
(
device
->
bdev
)
{
device
->
fs_devices
->
open_devices
--
;
...
...
@@ -1883,63 +1921,23 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
* at this point, the device is zero sized. We want to
* remove it from the devices list and zero out the old super
*/
if
(
clear_super
&&
disk_super
)
{
u64
bytenr
;
int
i
;
/* make sure this device isn't detected as part of
* the FS anymore
*/
memset
(
&
disk_super
->
magic
,
0
,
sizeof
(
disk_super
->
magic
));
set_buffer_dirty
(
bh
);
sync_dirty_buffer
(
bh
);
/* clear the mirror copies of super block on the disk
* being removed, 0th copy is been taken care above and
* the below would take of the rest
*/
for
(
i
=
1
;
i
<
BTRFS_SUPER_MIRROR_MAX
;
i
++
)
{
bytenr
=
btrfs_sb_offset
(
i
);
if
(
bytenr
+
BTRFS_SUPER_INFO_SIZE
>=
i_size_read
(
bdev
->
bd_inode
))
break
;
brelse
(
bh
);
bh
=
__bread
(
bdev
,
bytenr
/
4096
,
BTRFS_SUPER_INFO_SIZE
);
if
(
!
bh
)
continue
;
disk_super
=
(
struct
btrfs_super_block
*
)
bh
->
b_data
;
if
(
btrfs_super_bytenr
(
disk_super
)
!=
bytenr
||
btrfs_super_magic
(
disk_super
)
!=
BTRFS_MAGIC
)
{
continue
;
}
memset
(
&
disk_super
->
magic
,
0
,
sizeof
(
disk_super
->
magic
));
set_buffer_dirty
(
bh
);
sync_dirty_buffer
(
bh
);
if
(
clear_super
)
{
struct
block_device
*
bdev
;
bdev
=
blkdev_get_by_path
(
dev_name
,
FMODE_READ
|
FMODE_EXCL
,
root
->
fs_info
->
bdev_holder
);
if
(
!
IS_ERR
(
bdev
))
{
btrfs_scratch_superblocks
(
bdev
,
dev_name
);
blkdev_put
(
bdev
,
FMODE_READ
|
FMODE_EXCL
);
}
}
ret
=
0
;
if
(
bdev
)
{
/* Notify udev that device has changed */
btrfs_kobject_uevent
(
bdev
,
KOBJ_CHANGE
);
/* Update ctime/mtime for device path for libblkid */
update_dev_time
(
device_path
);
}
error_brelse:
brelse
(
bh
);
if
(
bdev
)
blkdev_put
(
bdev
,
FMODE_READ
|
FMODE_EXCL
);
out:
kfree
(
dev_name
);
mutex_unlock
(
&
uuid_mutex
);
return
ret
;
error_undo:
if
(
device
->
writeable
)
{
lock_chunks
(
root
);
...
...
@@ -1948,7 +1946,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
device
->
fs_devices
->
rw_devices
++
;
unlock_chunks
(
root
);
}
goto
error_brelse
;
goto
out
;
}
void
btrfs_rm_dev_replace_remove_srcdev
(
struct
btrfs_fs_info
*
fs_info
,
...
...
@@ -2017,8 +2015,6 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,
void
btrfs_destroy_dev_replace_tgtdev
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_device
*
tgtdev
)
{
struct
btrfs_device
*
next_device
;
mutex_lock
(
&
uuid_mutex
);
WARN_ON
(
!
tgtdev
);
mutex_lock
(
&
fs_info
->
fs_devices
->
device_list_mutex
);
...
...
@@ -2030,12 +2026,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
fs_info
->
fs_devices
->
num_devices
--
;
next_device
=
list_entry
(
fs_info
->
fs_devices
->
devices
.
next
,
struct
btrfs_device
,
dev_list
);
if
(
tgtdev
->
bdev
==
fs_info
->
sb
->
s_bdev
)
fs_info
->
sb
->
s_bdev
=
next_device
->
bdev
;
if
(
tgtdev
->
bdev
==
fs_info
->
fs_devices
->
latest_bdev
)
fs_info
->
fs_devices
->
latest_bdev
=
next_device
->
bdev
;
btrfs_assign_next_active_device
(
fs_info
,
tgtdev
,
NULL
);
list_del_rcu
(
&
tgtdev
->
dev_list
);
mutex_unlock
(
&
fs_info
->
fs_devices
->
device_list_mutex
);
...
...
@@ -2109,6 +2101,31 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
}
}
/*
* Lookup a device given by device id, or the path if the id is 0.
*/
int
btrfs_find_device_by_devspec
(
struct
btrfs_root
*
root
,
u64
devid
,
char
*
devpath
,
struct
btrfs_device
**
device
)
{
int
ret
;
if
(
devid
)
{
ret
=
0
;
*
device
=
btrfs_find_device
(
root
->
fs_info
,
devid
,
NULL
,
NULL
);
if
(
!*
device
)
ret
=
-
ENOENT
;
}
else
{
if
(
!
devpath
||
!
devpath
[
0
])
return
-
EINVAL
;
ret
=
btrfs_find_device_missing_or_by_path
(
root
,
devpath
,
device
);
}
return
ret
;
}
/*
* does all the dirty work required for changing file system's UUID.
*/
...
...
fs/btrfs/volumes.h
浏览文件 @
36fac9e9
...
...
@@ -340,7 +340,7 @@ struct btrfs_raid_attr {
};
extern
const
struct
btrfs_raid_attr
btrfs_raid_array
[
BTRFS_NR_RAID_TYPES
];
extern
const
int
btrfs_raid_mindev_error
[
BTRFS_NR_RAID_TYPES
];
extern
const
u64
btrfs_raid_group
[
BTRFS_NR_RAID_TYPES
];
struct
map_lookup
{
...
...
@@ -445,13 +445,18 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
struct
btrfs_fs_devices
**
fs_devices_ret
);
int
btrfs_close_devices
(
struct
btrfs_fs_devices
*
fs_devices
);
void
btrfs_close_extra_devices
(
struct
btrfs_fs_devices
*
fs_devices
,
int
step
);
void
btrfs_assign_next_active_device
(
struct
btrfs_fs_info
*
fs_info
,
struct
btrfs_device
*
device
,
struct
btrfs_device
*
this_dev
);
int
btrfs_find_device_missing_or_by_path
(
struct
btrfs_root
*
root
,
char
*
device_path
,
struct
btrfs_device
**
device
);
int
btrfs_find_device_by_devspec
(
struct
btrfs_root
*
root
,
u64
devid
,
char
*
devpath
,
struct
btrfs_device
**
device
);
struct
btrfs_device
*
btrfs_alloc_device
(
struct
btrfs_fs_info
*
fs_info
,
const
u64
*
devid
,
const
u8
*
uuid
);
int
btrfs_rm_device
(
struct
btrfs_root
*
root
,
char
*
device_path
);
int
btrfs_rm_device
(
struct
btrfs_root
*
root
,
char
*
device_path
,
u64
devid
);
void
btrfs_cleanup_fs_uuids
(
void
);
int
btrfs_num_copies
(
struct
btrfs_fs_info
*
fs_info
,
u64
logical
,
u64
len
);
int
btrfs_grow_device
(
struct
btrfs_trans_handle
*
trans
,
...
...
include/uapi/linux/btrfs.h
浏览文件 @
36fac9e9
...
...
@@ -36,6 +36,14 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
#define BTRFS_SUBVOL_RDONLY (1ULL << 1)
#define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2)
#define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3)
#define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \
(BTRFS_SUBVOL_CREATE_ASYNC | \
BTRFS_SUBVOL_RDONLY | \
BTRFS_SUBVOL_QGROUP_INHERIT | \
BTRFS_DEVICE_SPEC_BY_ID)
#define BTRFS_FSID_SIZE 16
#define BTRFS_UUID_SIZE 16
#define BTRFS_UUID_UNPARSED_SIZE 37
...
...
@@ -76,7 +84,10 @@ struct btrfs_ioctl_vol_args_v2 {
};
__u64
unused
[
4
];
};
char
name
[
BTRFS_SUBVOL_NAME_MAX
+
1
];
union
{
char
name
[
BTRFS_SUBVOL_NAME_MAX
+
1
];
u64
devid
;
};
};
/*
...
...
@@ -659,5 +670,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
struct btrfs_ioctl_feature_flags[2])
#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
struct btrfs_ioctl_feature_flags[3])
#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \
struct btrfs_ioctl_vol_args_v2)
#endif
/* _UAPI_LINUX_BTRFS_H */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录