diff options
| author | Dr. Tilmann Bubeck <t.bubeck@reinform.de> | 2013-04-08 12:54:05 -0400 |
|---|---|---|
| committer | Theodore Ts'o <tytso@mit.edu> | 2013-04-08 12:54:05 -0400 |
| commit | 393d1d1d76933886d5e1ce603214c9987589c6d5 (patch) | |
| tree | 2f2368a9d787ccb8e69f61a3e5023ef9c4abfd8b /fs/ext4 | |
| parent | f78ee70db40040e6f38a5134527d4760254d6683 (diff) | |
ext4: implementation of a new ioctl called EXT4_IOC_SWAP_BOOT
Add a new ioctl, EXT4_IOC_SWAP_BOOT which swaps i_blocks and
associated attributes (like i_blocks, i_size, i_flags, ...) from the
specified inode with inode EXT4_BOOT_LOADER_INO (#5). This is
typically used to store a boot loader in a secure part of the
filesystem, where it can't be changed by a normal user by accident.
The data blocks of the previous boot loader will be associated with
the given inode.
This usercode program is a simple example of the usage:
int main(int argc, char *argv[])
{
int fd;
int err;
if ( argc != 2 ) {
printf("usage: ext4-swap-boot-inode FILE-TO-SWAP\n");
exit(1);
}
fd = open(argv[1], O_WRONLY);
if ( fd < 0 ) {
perror("open");
exit(1);
}
err = ioctl(fd, EXT4_IOC_SWAP_BOOT);
if ( err < 0 ) {
perror("ioctl");
exit(1);
}
close(fd);
exit(0);
}
[ Modified by Theodore Ts'o to fix a number of bugs in the original code.]
Signed-off-by: Dr. Tilmann Bubeck <t.bubeck@reinform.de>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
| -rw-r--r-- | fs/ext4/ext4.h | 8 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 11 | ||||
| -rw-r--r-- | fs/ext4/ioctl.c | 197 | ||||
| -rw-r--r-- | fs/ext4/move_extent.c | 48 |
4 files changed, 238 insertions, 26 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index a0637e5057ae..d91871570982 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -616,6 +616,7 @@ enum { | |||
| 616 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) | 616 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) |
| 617 | #define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent) | 617 | #define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent) |
| 618 | #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) | 618 | #define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) |
| 619 | #define EXT4_IOC_SWAP_BOOT _IO('f', 17) | ||
| 619 | 620 | ||
| 620 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | 621 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) |
| 621 | /* | 622 | /* |
| @@ -1341,6 +1342,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) | |||
| 1341 | return ino == EXT4_ROOT_INO || | 1342 | return ino == EXT4_ROOT_INO || |
| 1342 | ino == EXT4_USR_QUOTA_INO || | 1343 | ino == EXT4_USR_QUOTA_INO || |
| 1343 | ino == EXT4_GRP_QUOTA_INO || | 1344 | ino == EXT4_GRP_QUOTA_INO || |
| 1345 | ino == EXT4_BOOT_LOADER_INO || | ||
| 1344 | ino == EXT4_JOURNAL_INO || | 1346 | ino == EXT4_JOURNAL_INO || |
| 1345 | ino == EXT4_RESIZE_INO || | 1347 | ino == EXT4_RESIZE_INO || |
| 1346 | (ino >= EXT4_FIRST_INO(sb) && | 1348 | (ino >= EXT4_FIRST_INO(sb) && |
| @@ -2624,6 +2626,12 @@ extern int ext4_ind_migrate(struct inode *inode); | |||
| 2624 | 2626 | ||
| 2625 | 2627 | ||
| 2626 | /* move_extent.c */ | 2628 | /* move_extent.c */ |
| 2629 | extern void ext4_double_down_write_data_sem(struct inode *first, | ||
| 2630 | struct inode *second); | ||
| 2631 | extern void ext4_double_up_write_data_sem(struct inode *orig_inode, | ||
| 2632 | struct inode *donor_inode); | ||
| 2633 | void ext4_inode_double_lock(struct inode *inode1, struct inode *inode2); | ||
| 2634 | void ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2); | ||
| 2627 | extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, | 2635 | extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, |
| 2628 | __u64 start_orig, __u64 start_donor, | 2636 | __u64 start_orig, __u64 start_donor, |
| 2629 | __u64 len, __u64 *moved_len); | 2637 | __u64 len, __u64 *moved_len); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 769c656ea3b1..a29bfc2142ef 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -4191,8 +4191,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 4191 | * NeilBrown 1999oct15 | 4191 | * NeilBrown 1999oct15 |
| 4192 | */ | 4192 | */ |
| 4193 | if (inode->i_nlink == 0) { | 4193 | if (inode->i_nlink == 0) { |
| 4194 | if (inode->i_mode == 0 || | 4194 | if ((inode->i_mode == 0 || |
| 4195 | !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) { | 4195 | !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) && |
| 4196 | ino != EXT4_BOOT_LOADER_INO) { | ||
| 4196 | /* this inode is deleted */ | 4197 | /* this inode is deleted */ |
| 4197 | ret = -ESTALE; | 4198 | ret = -ESTALE; |
| 4198 | goto bad_inode; | 4199 | goto bad_inode; |
| @@ -4200,7 +4201,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 4200 | /* The only unlinked inodes we let through here have | 4201 | /* The only unlinked inodes we let through here have |
| 4201 | * valid i_mode and are being read by the orphan | 4202 | * valid i_mode and are being read by the orphan |
| 4202 | * recovery code: that's fine, we're about to complete | 4203 | * recovery code: that's fine, we're about to complete |
| 4203 | * the process of deleting those. */ | 4204 | * the process of deleting those. |
| 4205 | * OR it is the EXT4_BOOT_LOADER_INO which is | ||
| 4206 | * not initialized on a new filesystem. */ | ||
| 4204 | } | 4207 | } |
| 4205 | ei->i_flags = le32_to_cpu(raw_inode->i_flags); | 4208 | ei->i_flags = le32_to_cpu(raw_inode->i_flags); |
| 4206 | inode->i_blocks = ext4_inode_blocks(raw_inode, ei); | 4209 | inode->i_blocks = ext4_inode_blocks(raw_inode, ei); |
| @@ -4320,6 +4323,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
| 4320 | else | 4323 | else |
| 4321 | init_special_inode(inode, inode->i_mode, | 4324 | init_special_inode(inode, inode->i_mode, |
| 4322 | new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); | 4325 | new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); |
| 4326 | } else if (ino == EXT4_BOOT_LOADER_INO) { | ||
| 4327 | make_bad_inode(inode); | ||
| 4323 | } else { | 4328 | } else { |
| 4324 | ret = -EIO; | 4329 | ret = -EIO; |
| 4325 | EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode); | 4330 | EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode); |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a07b7bc0856a..cbc3acea6bcf 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
| @@ -17,9 +17,201 @@ | |||
| 17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
| 18 | #include "ext4_jbd2.h" | 18 | #include "ext4_jbd2.h" |
| 19 | #include "ext4.h" | 19 | #include "ext4.h" |
| 20 | #include "ext4_extents.h" | ||
| 20 | 21 | ||
| 21 | #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1) | 22 | #define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1) |
| 22 | 23 | ||
| 24 | /** | ||
| 25 | * Swap memory between @a and @b for @len bytes. | ||
| 26 | * | ||
| 27 | * @a: pointer to first memory area | ||
| 28 | * @b: pointer to second memory area | ||
| 29 | * @len: number of bytes to swap | ||
| 30 | * | ||
| 31 | */ | ||
| 32 | static void memswap(void *a, void *b, size_t len) | ||
| 33 | { | ||
| 34 | unsigned char *ap, *bp; | ||
| 35 | unsigned char tmp; | ||
| 36 | |||
| 37 | ap = (unsigned char *)a; | ||
| 38 | bp = (unsigned char *)b; | ||
| 39 | while (len-- > 0) { | ||
| 40 | tmp = *ap; | ||
| 41 | *ap = *bp; | ||
| 42 | *bp = tmp; | ||
| 43 | ap++; | ||
| 44 | bp++; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Swap i_data and associated attributes between @inode1 and @inode2. | ||
| 50 | * This function is used for the primary swap between inode1 and inode2 | ||
| 51 | * and also to revert this primary swap in case of errors. | ||
| 52 | * | ||
| 53 | * Therefore you have to make sure, that calling this method twice | ||
| 54 | * will revert all changes. | ||
| 55 | * | ||
| 56 | * @inode1: pointer to first inode | ||
| 57 | * @inode2: pointer to second inode | ||
| 58 | */ | ||
| 59 | static void swap_inode_data(struct inode *inode1, struct inode *inode2) | ||
| 60 | { | ||
| 61 | loff_t isize; | ||
| 62 | struct ext4_inode_info *ei1; | ||
| 63 | struct ext4_inode_info *ei2; | ||
| 64 | |||
| 65 | ei1 = EXT4_I(inode1); | ||
| 66 | ei2 = EXT4_I(inode2); | ||
| 67 | |||
| 68 | memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags)); | ||
| 69 | memswap(&inode1->i_version, &inode2->i_version, | ||
| 70 | sizeof(inode1->i_version)); | ||
| 71 | memswap(&inode1->i_blocks, &inode2->i_blocks, | ||
| 72 | sizeof(inode1->i_blocks)); | ||
| 73 | memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes)); | ||
| 74 | memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime)); | ||
| 75 | memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime)); | ||
| 76 | |||
| 77 | memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data)); | ||
| 78 | memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags)); | ||
| 79 | memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize)); | ||
| 80 | memswap(&ei1->i_es_tree, &ei2->i_es_tree, sizeof(ei1->i_es_tree)); | ||
| 81 | memswap(&ei1->i_es_lru_nr, &ei2->i_es_lru_nr, sizeof(ei1->i_es_lru_nr)); | ||
| 82 | |||
| 83 | isize = i_size_read(inode1); | ||
| 84 | i_size_write(inode1, i_size_read(inode2)); | ||
| 85 | i_size_write(inode2, isize); | ||
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * Swap the information from the given @inode and the inode | ||
| 90 | * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other | ||
| 91 | * important fields of the inodes. | ||
| 92 | * | ||
| 93 | * @sb: the super block of the filesystem | ||
| 94 | * @inode: the inode to swap with EXT4_BOOT_LOADER_INO | ||
| 95 | * | ||
| 96 | */ | ||
| 97 | static long swap_inode_boot_loader(struct super_block *sb, | ||
| 98 | struct inode *inode) | ||
| 99 | { | ||
| 100 | handle_t *handle; | ||
| 101 | int err; | ||
| 102 | struct inode *inode_bl; | ||
| 103 | struct ext4_inode_info *ei; | ||
| 104 | struct ext4_inode_info *ei_bl; | ||
| 105 | struct ext4_sb_info *sbi; | ||
| 106 | |||
| 107 | if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) { | ||
| 108 | err = -EINVAL; | ||
| 109 | goto swap_boot_out; | ||
| 110 | } | ||
| 111 | |||
| 112 | if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) { | ||
| 113 | err = -EPERM; | ||
| 114 | goto swap_boot_out; | ||
| 115 | } | ||
| 116 | |||
| 117 | sbi = EXT4_SB(sb); | ||
| 118 | ei = EXT4_I(inode); | ||
| 119 | |||
| 120 | inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); | ||
| 121 | if (IS_ERR(inode_bl)) { | ||
| 122 | err = PTR_ERR(inode_bl); | ||
| 123 | goto swap_boot_out; | ||
| 124 | } | ||
| 125 | ei_bl = EXT4_I(inode_bl); | ||
| 126 | |||
| 127 | filemap_flush(inode->i_mapping); | ||
| 128 | filemap_flush(inode_bl->i_mapping); | ||
| 129 | |||
| 130 | /* Protect orig inodes against a truncate and make sure, | ||
| 131 | * that only 1 swap_inode_boot_loader is running. */ | ||
| 132 | ext4_inode_double_lock(inode, inode_bl); | ||
| 133 | |||
| 134 | truncate_inode_pages(&inode->i_data, 0); | ||
| 135 | truncate_inode_pages(&inode_bl->i_data, 0); | ||
| 136 | |||
| 137 | /* Wait for all existing dio workers */ | ||
| 138 | ext4_inode_block_unlocked_dio(inode); | ||
| 139 | ext4_inode_block_unlocked_dio(inode_bl); | ||
| 140 | inode_dio_wait(inode); | ||
| 141 | inode_dio_wait(inode_bl); | ||
| 142 | |||
| 143 | handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); | ||
| 144 | if (IS_ERR(handle)) { | ||
| 145 | err = -EINVAL; | ||
| 146 | goto swap_boot_out; | ||
| 147 | } | ||
| 148 | |||
| 149 | /* Protect extent tree against block allocations via delalloc */ | ||
| 150 | ext4_double_down_write_data_sem(inode, inode_bl); | ||
| 151 | |||
| 152 | if (inode_bl->i_nlink == 0) { | ||
| 153 | /* this inode has never been used as a BOOT_LOADER */ | ||
| 154 | set_nlink(inode_bl, 1); | ||
| 155 | i_uid_write(inode_bl, 0); | ||
| 156 | i_gid_write(inode_bl, 0); | ||
| 157 | inode_bl->i_flags = 0; | ||
| 158 | ei_bl->i_flags = 0; | ||
| 159 | inode_bl->i_version = 1; | ||
| 160 | i_size_write(inode_bl, 0); | ||
| 161 | inode_bl->i_mode = S_IFREG; | ||
| 162 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | ||
| 163 | EXT4_FEATURE_INCOMPAT_EXTENTS)) { | ||
| 164 | ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS); | ||
| 165 | ext4_ext_tree_init(handle, inode_bl); | ||
| 166 | } else | ||
| 167 | memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); | ||
| 168 | } | ||
| 169 | |||
| 170 | swap_inode_data(inode, inode_bl); | ||
| 171 | |||
| 172 | inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode); | ||
| 173 | |||
| 174 | spin_lock(&sbi->s_next_gen_lock); | ||
| 175 | inode->i_generation = sbi->s_next_generation++; | ||
| 176 | inode_bl->i_generation = sbi->s_next_generation++; | ||
| 177 | spin_unlock(&sbi->s_next_gen_lock); | ||
| 178 | |||
| 179 | ext4_discard_preallocations(inode); | ||
| 180 | |||
| 181 | err = ext4_mark_inode_dirty(handle, inode); | ||
| 182 | if (err < 0) { | ||
| 183 | ext4_warning(inode->i_sb, | ||
| 184 | "couldn't mark inode #%lu dirty (err %d)", | ||
| 185 | inode->i_ino, err); | ||
| 186 | /* Revert all changes: */ | ||
| 187 | swap_inode_data(inode, inode_bl); | ||
| 188 | } else { | ||
| 189 | err = ext4_mark_inode_dirty(handle, inode_bl); | ||
| 190 | if (err < 0) { | ||
| 191 | ext4_warning(inode_bl->i_sb, | ||
| 192 | "couldn't mark inode #%lu dirty (err %d)", | ||
| 193 | inode_bl->i_ino, err); | ||
| 194 | /* Revert all changes: */ | ||
| 195 | swap_inode_data(inode, inode_bl); | ||
| 196 | ext4_mark_inode_dirty(handle, inode); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | ext4_journal_stop(handle); | ||
| 201 | |||
| 202 | ext4_double_up_write_data_sem(inode, inode_bl); | ||
| 203 | |||
| 204 | ext4_inode_resume_unlocked_dio(inode); | ||
| 205 | ext4_inode_resume_unlocked_dio(inode_bl); | ||
| 206 | |||
| 207 | ext4_inode_double_unlock(inode, inode_bl); | ||
| 208 | |||
| 209 | iput(inode_bl); | ||
| 210 | |||
| 211 | swap_boot_out: | ||
| 212 | return err; | ||
| 213 | } | ||
| 214 | |||
| 23 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 215 | long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 24 | { | 216 | { |
| 25 | struct inode *inode = file_inode(filp); | 217 | struct inode *inode = file_inode(filp); |
| @@ -353,6 +545,11 @@ group_add_out: | |||
| 353 | return err; | 545 | return err; |
| 354 | } | 546 | } |
| 355 | 547 | ||
| 548 | case EXT4_IOC_SWAP_BOOT: | ||
| 549 | if (!(filp->f_mode & FMODE_WRITE)) | ||
| 550 | return -EBADF; | ||
| 551 | return swap_inode_boot_loader(sb, inode); | ||
| 552 | |||
| 356 | case EXT4_IOC_RESIZE_FS: { | 553 | case EXT4_IOC_RESIZE_FS: { |
| 357 | ext4_fsblk_t n_blocks_count; | 554 | ext4_fsblk_t n_blocks_count; |
| 358 | struct super_block *sb = inode->i_sb; | 555 | struct super_block *sb = inode->i_sb; |
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 33e1c086858b..a2e696e16331 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c | |||
| @@ -144,12 +144,13 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | |||
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /** | 146 | /** |
| 147 | * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem | 147 | * ext4_double_down_write_data_sem - Acquire two inodes' write lock |
| 148 | * of i_data_sem | ||
| 148 | * | 149 | * |
| 149 | * Acquire write lock of i_data_sem of the two inodes | 150 | * Acquire write lock of i_data_sem of the two inodes |
| 150 | */ | 151 | */ |
| 151 | static void | 152 | void |
| 152 | double_down_write_data_sem(struct inode *first, struct inode *second) | 153 | ext4_double_down_write_data_sem(struct inode *first, struct inode *second) |
| 153 | { | 154 | { |
| 154 | if (first < second) { | 155 | if (first < second) { |
| 155 | down_write(&EXT4_I(first)->i_data_sem); | 156 | down_write(&EXT4_I(first)->i_data_sem); |
| @@ -162,14 +163,15 @@ double_down_write_data_sem(struct inode *first, struct inode *second) | |||
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | /** | 165 | /** |
| 165 | * double_up_write_data_sem - Release two inodes' write lock of i_data_sem | 166 | * ext4_double_up_write_data_sem - Release two inodes' write lock of i_data_sem |
| 166 | * | 167 | * |
| 167 | * @orig_inode: original inode structure to be released its lock first | 168 | * @orig_inode: original inode structure to be released its lock first |
| 168 | * @donor_inode: donor inode structure to be released its lock second | 169 | * @donor_inode: donor inode structure to be released its lock second |
| 169 | * Release write lock of i_data_sem of two inodes (orig and donor). | 170 | * Release write lock of i_data_sem of two inodes (orig and donor). |
| 170 | */ | 171 | */ |
| 171 | static void | 172 | void |
| 172 | double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode) | 173 | ext4_double_up_write_data_sem(struct inode *orig_inode, |
| 174 | struct inode *donor_inode) | ||
| 173 | { | 175 | { |
| 174 | up_write(&EXT4_I(orig_inode)->i_data_sem); | 176 | up_write(&EXT4_I(orig_inode)->i_data_sem); |
| 175 | up_write(&EXT4_I(donor_inode)->i_data_sem); | 177 | up_write(&EXT4_I(donor_inode)->i_data_sem); |
| @@ -976,7 +978,7 @@ again: | |||
| 976 | * necessary, just swap data blocks between orig and donor. | 978 | * necessary, just swap data blocks between orig and donor. |
| 977 | */ | 979 | */ |
| 978 | if (uninit) { | 980 | if (uninit) { |
| 979 | double_down_write_data_sem(orig_inode, donor_inode); | 981 | ext4_double_down_write_data_sem(orig_inode, donor_inode); |
| 980 | /* If any of extents in range became initialized we have to | 982 | /* If any of extents in range became initialized we have to |
| 981 | * fallback to data copying */ | 983 | * fallback to data copying */ |
| 982 | uninit = mext_check_coverage(orig_inode, orig_blk_offset, | 984 | uninit = mext_check_coverage(orig_inode, orig_blk_offset, |
| @@ -990,7 +992,7 @@ again: | |||
| 990 | goto drop_data_sem; | 992 | goto drop_data_sem; |
| 991 | 993 | ||
| 992 | if (!uninit) { | 994 | if (!uninit) { |
| 993 | double_up_write_data_sem(orig_inode, donor_inode); | 995 | ext4_double_up_write_data_sem(orig_inode, donor_inode); |
| 994 | goto data_copy; | 996 | goto data_copy; |
| 995 | } | 997 | } |
| 996 | if ((page_has_private(pagep[0]) && | 998 | if ((page_has_private(pagep[0]) && |
| @@ -1004,7 +1006,7 @@ again: | |||
| 1004 | donor_inode, orig_blk_offset, | 1006 | donor_inode, orig_blk_offset, |
| 1005 | block_len_in_page, err); | 1007 | block_len_in_page, err); |
| 1006 | drop_data_sem: | 1008 | drop_data_sem: |
| 1007 | double_up_write_data_sem(orig_inode, donor_inode); | 1009 | ext4_double_up_write_data_sem(orig_inode, donor_inode); |
| 1008 | goto unlock_pages; | 1010 | goto unlock_pages; |
| 1009 | } | 1011 | } |
| 1010 | data_copy: | 1012 | data_copy: |
| @@ -1065,11 +1067,11 @@ repair_branches: | |||
| 1065 | * Extents are swapped already, but we are not able to copy data. | 1067 | * Extents are swapped already, but we are not able to copy data. |
| 1066 | * Try to swap extents to it's original places | 1068 | * Try to swap extents to it's original places |
| 1067 | */ | 1069 | */ |
| 1068 | double_down_write_data_sem(orig_inode, donor_inode); | 1070 | ext4_double_down_write_data_sem(orig_inode, donor_inode); |
| 1069 | replaced_count = mext_replace_branches(handle, donor_inode, orig_inode, | 1071 | replaced_count = mext_replace_branches(handle, donor_inode, orig_inode, |
| 1070 | orig_blk_offset, | 1072 | orig_blk_offset, |
| 1071 | block_len_in_page, &err2); | 1073 | block_len_in_page, &err2); |
| 1072 | double_up_write_data_sem(orig_inode, donor_inode); | 1074 | ext4_double_up_write_data_sem(orig_inode, donor_inode); |
| 1073 | if (replaced_count != block_len_in_page) { | 1075 | if (replaced_count != block_len_in_page) { |
| 1074 | EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset), | 1076 | EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset), |
| 1075 | "Unable to copy data block," | 1077 | "Unable to copy data block," |
| @@ -1209,15 +1211,15 @@ mext_check_arguments(struct inode *orig_inode, | |||
| 1209 | } | 1211 | } |
| 1210 | 1212 | ||
| 1211 | /** | 1213 | /** |
| 1212 | * mext_inode_double_lock - Lock i_mutex on both @inode1 and @inode2 | 1214 | * ext4_inode_double_lock - Lock i_mutex on both @inode1 and @inode2 |
| 1213 | * | 1215 | * |
| 1214 | * @inode1: the inode structure | 1216 | * @inode1: the inode structure |
| 1215 | * @inode2: the inode structure | 1217 | * @inode2: the inode structure |
| 1216 | * | 1218 | * |
| 1217 | * Lock two inodes' i_mutex | 1219 | * Lock two inodes' i_mutex |
| 1218 | */ | 1220 | */ |
| 1219 | static void | 1221 | void |
| 1220 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | 1222 | ext4_inode_double_lock(struct inode *inode1, struct inode *inode2) |
| 1221 | { | 1223 | { |
| 1222 | BUG_ON(inode1 == inode2); | 1224 | BUG_ON(inode1 == inode2); |
| 1223 | if (inode1 < inode2) { | 1225 | if (inode1 < inode2) { |
| @@ -1230,15 +1232,15 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | |||
| 1230 | } | 1232 | } |
| 1231 | 1233 | ||
| 1232 | /** | 1234 | /** |
| 1233 | * mext_inode_double_unlock - Release i_mutex on both @inode1 and @inode2 | 1235 | * ext4_inode_double_unlock - Release i_mutex on both @inode1 and @inode2 |
| 1234 | * | 1236 | * |
| 1235 | * @inode1: the inode that is released first | 1237 | * @inode1: the inode that is released first |
| 1236 | * @inode2: the inode that is released second | 1238 | * @inode2: the inode that is released second |
| 1237 | * | 1239 | * |
| 1238 | */ | 1240 | */ |
| 1239 | 1241 | ||
| 1240 | static void | 1242 | void |
| 1241 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) | 1243 | ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2) |
| 1242 | { | 1244 | { |
| 1243 | mutex_unlock(&inode1->i_mutex); | 1245 | mutex_unlock(&inode1->i_mutex); |
| 1244 | mutex_unlock(&inode2->i_mutex); | 1246 | mutex_unlock(&inode2->i_mutex); |
| @@ -1333,7 +1335,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1333 | return -EINVAL; | 1335 | return -EINVAL; |
| 1334 | } | 1336 | } |
| 1335 | /* Protect orig and donor inodes against a truncate */ | 1337 | /* Protect orig and donor inodes against a truncate */ |
| 1336 | mext_inode_double_lock(orig_inode, donor_inode); | 1338 | ext4_inode_double_lock(orig_inode, donor_inode); |
| 1337 | 1339 | ||
| 1338 | /* Wait for all existing dio workers */ | 1340 | /* Wait for all existing dio workers */ |
| 1339 | ext4_inode_block_unlocked_dio(orig_inode); | 1341 | ext4_inode_block_unlocked_dio(orig_inode); |
| @@ -1342,7 +1344,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1342 | inode_dio_wait(donor_inode); | 1344 | inode_dio_wait(donor_inode); |
| 1343 | 1345 | ||
| 1344 | /* Protect extent tree against block allocations via delalloc */ | 1346 | /* Protect extent tree against block allocations via delalloc */ |
| 1345 | double_down_write_data_sem(orig_inode, donor_inode); | 1347 | ext4_double_down_write_data_sem(orig_inode, donor_inode); |
| 1346 | /* Check the filesystem environment whether move_extent can be done */ | 1348 | /* Check the filesystem environment whether move_extent can be done */ |
| 1347 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, | 1349 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, |
| 1348 | donor_start, &len); | 1350 | donor_start, &len); |
| @@ -1466,7 +1468,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1466 | * b. racing with ->readpage, ->write_begin, and ext4_get_block | 1468 | * b. racing with ->readpage, ->write_begin, and ext4_get_block |
| 1467 | * in move_extent_per_page | 1469 | * in move_extent_per_page |
| 1468 | */ | 1470 | */ |
| 1469 | double_up_write_data_sem(orig_inode, donor_inode); | 1471 | ext4_double_up_write_data_sem(orig_inode, donor_inode); |
| 1470 | 1472 | ||
| 1471 | while (orig_page_offset <= seq_end_page) { | 1473 | while (orig_page_offset <= seq_end_page) { |
| 1472 | 1474 | ||
| @@ -1500,7 +1502,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp, | |||
| 1500 | block_len_in_page = rest_blocks; | 1502 | block_len_in_page = rest_blocks; |
| 1501 | } | 1503 | } |
| 1502 | 1504 | ||
| 1503 | double_down_write_data_sem(orig_inode, donor_inode); | 1505 | ext4_double_down_write_data_sem(orig_inode, donor_inode); |
| 1504 | if (ret < 0) | 1506 | if (ret < 0) |
| 1505 | break; | 1507 | break; |
| 1506 | 1508 | ||
| @@ -1538,10 +1540,10 @@ out: | |||
| 1538 | ext4_ext_drop_refs(holecheck_path); | 1540 | ext4_ext_drop_refs(holecheck_path); |
| 1539 | kfree(holecheck_path); | 1541 | kfree(holecheck_path); |
| 1540 | } | 1542 | } |
| 1541 | double_up_write_data_sem(orig_inode, donor_inode); | 1543 | ext4_double_up_write_data_sem(orig_inode, donor_inode); |
| 1542 | ext4_inode_resume_unlocked_dio(orig_inode); | 1544 | ext4_inode_resume_unlocked_dio(orig_inode); |
| 1543 | ext4_inode_resume_unlocked_dio(donor_inode); | 1545 | ext4_inode_resume_unlocked_dio(donor_inode); |
| 1544 | mext_inode_double_unlock(orig_inode, donor_inode); | 1546 | ext4_inode_double_unlock(orig_inode, donor_inode); |
| 1545 | 1547 | ||
| 1546 | return ret; | 1548 | return ret; |
| 1547 | } | 1549 | } |
