diff options
author | Michael Halcrow <mhalcrow@google.com> | 2015-04-12 01:09:03 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 01:09:03 -0400 |
commit | 1f3862b5575b138e83080232706e37ee24b8093e (patch) | |
tree | 633ea79c868c96823445e2386ab68e978f3b5136 /fs | |
parent | b30984864406ad01b72eee486add103e9cb3526f (diff) |
ext4 crypto: filename encryption modifications
Modifies htree_dirblock_to_tree, dx_make_map, ext4_match search_dir,
and ext4_find_dest_de to support fname crypto. Filename encryption
feature is not yet enabled at this patch.
Signed-off-by: Uday Savagaonkar <savagaon@google.com>
Signed-off-by: Ildar Muslukhov <ildarm@google.com>
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/namei.c | 248 |
1 files changed, 204 insertions, 44 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 85add9a9e1cd..4c84db862891 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -253,8 +253,9 @@ static struct dx_frame *dx_probe(const struct qstr *d_name, | |||
253 | struct dx_hash_info *hinfo, | 253 | struct dx_hash_info *hinfo, |
254 | struct dx_frame *frame); | 254 | struct dx_frame *frame); |
255 | static void dx_release(struct dx_frame *frames); | 255 | static void dx_release(struct dx_frame *frames); |
256 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | 256 | static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, |
257 | struct dx_hash_info *hinfo, struct dx_map_entry map[]); | 257 | unsigned blocksize, struct dx_hash_info *hinfo, |
258 | struct dx_map_entry map[]); | ||
258 | static void dx_sort_map(struct dx_map_entry *map, unsigned count); | 259 | static void dx_sort_map(struct dx_map_entry *map, unsigned count); |
259 | static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, | 260 | static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, |
260 | struct dx_map_entry *offsets, int count, unsigned blocksize); | 261 | struct dx_map_entry *offsets, int count, unsigned blocksize); |
@@ -968,7 +969,8 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
968 | struct buffer_head *bh; | 969 | struct buffer_head *bh; |
969 | struct ext4_dir_entry_2 *de, *top; | 970 | struct ext4_dir_entry_2 *de, *top; |
970 | int err = 0, count = 0; | 971 | int err = 0, count = 0; |
971 | struct ext4_str tmp_str; | 972 | struct ext4_fname_crypto_ctx *ctx = NULL; |
973 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}, tmp_str; | ||
972 | 974 | ||
973 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", | 975 | dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", |
974 | (unsigned long)block)); | 976 | (unsigned long)block)); |
@@ -980,6 +982,24 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
980 | top = (struct ext4_dir_entry_2 *) ((char *) de + | 982 | top = (struct ext4_dir_entry_2 *) ((char *) de + |
981 | dir->i_sb->s_blocksize - | 983 | dir->i_sb->s_blocksize - |
982 | EXT4_DIR_REC_LEN(0)); | 984 | EXT4_DIR_REC_LEN(0)); |
985 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
986 | /* Check if the directory is encrypted */ | ||
987 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
988 | if (IS_ERR(ctx)) { | ||
989 | err = PTR_ERR(ctx); | ||
990 | brelse(bh); | ||
991 | return err; | ||
992 | } | ||
993 | if (ctx != NULL) { | ||
994 | err = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN, | ||
995 | &fname_crypto_str); | ||
996 | if (err < 0) { | ||
997 | ext4_put_fname_crypto_ctx(&ctx); | ||
998 | brelse(bh); | ||
999 | return err; | ||
1000 | } | ||
1001 | } | ||
1002 | #endif | ||
983 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { | 1003 | for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { |
984 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 1004 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
985 | bh->b_data, bh->b_size, | 1005 | bh->b_data, bh->b_size, |
@@ -988,24 +1008,52 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
988 | /* silently ignore the rest of the block */ | 1008 | /* silently ignore the rest of the block */ |
989 | break; | 1009 | break; |
990 | } | 1010 | } |
1011 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1012 | err = ext4_fname_disk_to_hash(ctx, de, hinfo); | ||
1013 | if (err < 0) { | ||
1014 | count = err; | ||
1015 | goto errout; | ||
1016 | } | ||
1017 | #else | ||
991 | ext4fs_dirhash(de->name, de->name_len, hinfo); | 1018 | ext4fs_dirhash(de->name, de->name_len, hinfo); |
1019 | #endif | ||
992 | if ((hinfo->hash < start_hash) || | 1020 | if ((hinfo->hash < start_hash) || |
993 | ((hinfo->hash == start_hash) && | 1021 | ((hinfo->hash == start_hash) && |
994 | (hinfo->minor_hash < start_minor_hash))) | 1022 | (hinfo->minor_hash < start_minor_hash))) |
995 | continue; | 1023 | continue; |
996 | if (de->inode == 0) | 1024 | if (de->inode == 0) |
997 | continue; | 1025 | continue; |
998 | tmp_str.name = de->name; | 1026 | if (ctx == NULL) { |
999 | tmp_str.len = de->name_len; | 1027 | /* Directory is not encrypted */ |
1000 | err = ext4_htree_store_dirent(dir_file, | 1028 | tmp_str.name = de->name; |
1001 | hinfo->hash, hinfo->minor_hash, de, &tmp_str); | 1029 | tmp_str.len = de->name_len; |
1030 | err = ext4_htree_store_dirent(dir_file, | ||
1031 | hinfo->hash, hinfo->minor_hash, de, | ||
1032 | &tmp_str); | ||
1033 | } else { | ||
1034 | /* Directory is encrypted */ | ||
1035 | err = ext4_fname_disk_to_usr(ctx, de, | ||
1036 | &fname_crypto_str); | ||
1037 | if (err < 0) { | ||
1038 | count = err; | ||
1039 | goto errout; | ||
1040 | } | ||
1041 | err = ext4_htree_store_dirent(dir_file, | ||
1042 | hinfo->hash, hinfo->minor_hash, de, | ||
1043 | &fname_crypto_str); | ||
1044 | } | ||
1002 | if (err != 0) { | 1045 | if (err != 0) { |
1003 | brelse(bh); | 1046 | count = err; |
1004 | return err; | 1047 | goto errout; |
1005 | } | 1048 | } |
1006 | count++; | 1049 | count++; |
1007 | } | 1050 | } |
1051 | errout: | ||
1008 | brelse(bh); | 1052 | brelse(bh); |
1053 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1054 | ext4_put_fname_crypto_ctx(&ctx); | ||
1055 | ext4_fname_crypto_free_buffer(&fname_crypto_str); | ||
1056 | #endif | ||
1009 | return count; | 1057 | return count; |
1010 | } | 1058 | } |
1011 | 1059 | ||
@@ -1138,17 +1186,33 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
1138 | * Create map of hash values, offsets, and sizes, stored at end of block. | 1186 | * Create map of hash values, offsets, and sizes, stored at end of block. |
1139 | * Returns number of entries mapped. | 1187 | * Returns number of entries mapped. |
1140 | */ | 1188 | */ |
1141 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | 1189 | static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, |
1142 | struct dx_hash_info *hinfo, | 1190 | unsigned blocksize, struct dx_hash_info *hinfo, |
1143 | struct dx_map_entry *map_tail) | 1191 | struct dx_map_entry *map_tail) |
1144 | { | 1192 | { |
1145 | int count = 0; | 1193 | int count = 0; |
1146 | char *base = (char *) de; | 1194 | char *base = (char *) de; |
1147 | struct dx_hash_info h = *hinfo; | 1195 | struct dx_hash_info h = *hinfo; |
1196 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1197 | struct ext4_fname_crypto_ctx *ctx = NULL; | ||
1198 | int err; | ||
1199 | |||
1200 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
1201 | if (IS_ERR(ctx)) | ||
1202 | return PTR_ERR(ctx); | ||
1203 | #endif | ||
1148 | 1204 | ||
1149 | while ((char *) de < base + blocksize) { | 1205 | while ((char *) de < base + blocksize) { |
1150 | if (de->name_len && de->inode) { | 1206 | if (de->name_len && de->inode) { |
1207 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1208 | err = ext4_fname_disk_to_hash(ctx, de, &h); | ||
1209 | if (err < 0) { | ||
1210 | ext4_put_fname_crypto_ctx(&ctx); | ||
1211 | return err; | ||
1212 | } | ||
1213 | #else | ||
1151 | ext4fs_dirhash(de->name, de->name_len, &h); | 1214 | ext4fs_dirhash(de->name, de->name_len, &h); |
1215 | #endif | ||
1152 | map_tail--; | 1216 | map_tail--; |
1153 | map_tail->hash = h.hash; | 1217 | map_tail->hash = h.hash; |
1154 | map_tail->offs = ((char *) de - base)>>2; | 1218 | map_tail->offs = ((char *) de - base)>>2; |
@@ -1159,6 +1223,9 @@ static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | |||
1159 | /* XXX: do we need to check rec_len == 0 case? -Chris */ | 1223 | /* XXX: do we need to check rec_len == 0 case? -Chris */ |
1160 | de = ext4_next_entry(de, blocksize); | 1224 | de = ext4_next_entry(de, blocksize); |
1161 | } | 1225 | } |
1226 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1227 | ext4_put_fname_crypto_ctx(&ctx); | ||
1228 | #endif | ||
1162 | return count; | 1229 | return count; |
1163 | } | 1230 | } |
1164 | 1231 | ||
@@ -1209,57 +1276,107 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) | |||
1209 | * `len <= EXT4_NAME_LEN' is guaranteed by caller. | 1276 | * `len <= EXT4_NAME_LEN' is guaranteed by caller. |
1210 | * `de != NULL' is guaranteed by caller. | 1277 | * `de != NULL' is guaranteed by caller. |
1211 | */ | 1278 | */ |
1212 | static inline int ext4_match (int len, const char * const name, | 1279 | static inline int ext4_match(struct ext4_fname_crypto_ctx *ctx, |
1213 | struct ext4_dir_entry_2 * de) | 1280 | struct ext4_str *fname_crypto_str, |
1281 | int len, const char * const name, | ||
1282 | struct ext4_dir_entry_2 *de) | ||
1214 | { | 1283 | { |
1215 | if (len != de->name_len) | 1284 | int res; |
1216 | return 0; | 1285 | |
1217 | if (!de->inode) | 1286 | if (!de->inode) |
1218 | return 0; | 1287 | return 0; |
1219 | return !memcmp(name, de->name, len); | 1288 | |
1289 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1290 | if (ctx) { | ||
1291 | /* Directory is encrypted */ | ||
1292 | res = ext4_fname_disk_to_usr(ctx, de, fname_crypto_str); | ||
1293 | if (res < 0) | ||
1294 | return res; | ||
1295 | if (len != res) | ||
1296 | return 0; | ||
1297 | res = memcmp(name, fname_crypto_str->name, len); | ||
1298 | return (res == 0) ? 1 : 0; | ||
1299 | } | ||
1300 | #endif | ||
1301 | if (len != de->name_len) | ||
1302 | return 0; | ||
1303 | res = memcmp(name, de->name, len); | ||
1304 | return (res == 0) ? 1 : 0; | ||
1220 | } | 1305 | } |
1221 | 1306 | ||
1222 | /* | 1307 | /* |
1223 | * Returns 0 if not found, -1 on failure, and 1 on success | 1308 | * Returns 0 if not found, -1 on failure, and 1 on success |
1224 | */ | 1309 | */ |
1225 | int search_dir(struct buffer_head *bh, | 1310 | int search_dir(struct buffer_head *bh, char *search_buf, int buf_size, |
1226 | char *search_buf, | 1311 | struct inode *dir, const struct qstr *d_name, |
1227 | int buf_size, | 1312 | unsigned int offset, struct ext4_dir_entry_2 **res_dir) |
1228 | struct inode *dir, | ||
1229 | const struct qstr *d_name, | ||
1230 | unsigned int offset, | ||
1231 | struct ext4_dir_entry_2 **res_dir) | ||
1232 | { | 1313 | { |
1233 | struct ext4_dir_entry_2 * de; | 1314 | struct ext4_dir_entry_2 * de; |
1234 | char * dlimit; | 1315 | char * dlimit; |
1235 | int de_len; | 1316 | int de_len; |
1236 | const char *name = d_name->name; | 1317 | const char *name = d_name->name; |
1237 | int namelen = d_name->len; | 1318 | int namelen = d_name->len; |
1319 | struct ext4_fname_crypto_ctx *ctx = NULL; | ||
1320 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; | ||
1321 | int res; | ||
1322 | |||
1323 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
1324 | if (IS_ERR(ctx)) | ||
1325 | return -1; | ||
1326 | |||
1327 | if (ctx != NULL) { | ||
1328 | /* Allocate buffer to hold maximum name length */ | ||
1329 | res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN, | ||
1330 | &fname_crypto_str); | ||
1331 | if (res < 0) { | ||
1332 | ext4_put_fname_crypto_ctx(&ctx); | ||
1333 | return -1; | ||
1334 | } | ||
1335 | } | ||
1238 | 1336 | ||
1239 | de = (struct ext4_dir_entry_2 *)search_buf; | 1337 | de = (struct ext4_dir_entry_2 *)search_buf; |
1240 | dlimit = search_buf + buf_size; | 1338 | dlimit = search_buf + buf_size; |
1241 | while ((char *) de < dlimit) { | 1339 | while ((char *) de < dlimit) { |
1242 | /* this code is executed quadratically often */ | 1340 | /* this code is executed quadratically often */ |
1243 | /* do minimal checking `by hand' */ | 1341 | /* do minimal checking `by hand' */ |
1342 | if ((char *) de + de->name_len <= dlimit) { | ||
1343 | res = ext4_match(ctx, &fname_crypto_str, namelen, | ||
1344 | name, de); | ||
1345 | if (res < 0) { | ||
1346 | res = -1; | ||
1347 | goto return_result; | ||
1348 | } | ||
1349 | if (res > 0) { | ||
1350 | /* found a match - just to be sure, do | ||
1351 | * a full check */ | ||
1352 | if (ext4_check_dir_entry(dir, NULL, de, bh, | ||
1353 | bh->b_data, | ||
1354 | bh->b_size, offset)) { | ||
1355 | res = -1; | ||
1356 | goto return_result; | ||
1357 | } | ||
1358 | *res_dir = de; | ||
1359 | res = 1; | ||
1360 | goto return_result; | ||
1361 | } | ||
1244 | 1362 | ||
1245 | if ((char *) de + namelen <= dlimit && | ||
1246 | ext4_match (namelen, name, de)) { | ||
1247 | /* found a match - just to be sure, do a full check */ | ||
1248 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, | ||
1249 | bh->b_size, offset)) | ||
1250 | return -1; | ||
1251 | *res_dir = de; | ||
1252 | return 1; | ||
1253 | } | 1363 | } |
1254 | /* prevent looping on a bad block */ | 1364 | /* prevent looping on a bad block */ |
1255 | de_len = ext4_rec_len_from_disk(de->rec_len, | 1365 | de_len = ext4_rec_len_from_disk(de->rec_len, |
1256 | dir->i_sb->s_blocksize); | 1366 | dir->i_sb->s_blocksize); |
1257 | if (de_len <= 0) | 1367 | if (de_len <= 0) { |
1258 | return -1; | 1368 | res = -1; |
1369 | goto return_result; | ||
1370 | } | ||
1259 | offset += de_len; | 1371 | offset += de_len; |
1260 | de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); | 1372 | de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); |
1261 | } | 1373 | } |
1262 | return 0; | 1374 | |
1375 | res = 0; | ||
1376 | return_result: | ||
1377 | ext4_put_fname_crypto_ctx(&ctx); | ||
1378 | ext4_fname_crypto_free_buffer(&fname_crypto_str); | ||
1379 | return res; | ||
1263 | } | 1380 | } |
1264 | 1381 | ||
1265 | static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, | 1382 | static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, |
@@ -1448,6 +1565,9 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q | |||
1448 | ext4_lblk_t block; | 1565 | ext4_lblk_t block; |
1449 | int retval; | 1566 | int retval; |
1450 | 1567 | ||
1568 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1569 | *res_dir = NULL; | ||
1570 | #endif | ||
1451 | frame = dx_probe(d_name, dir, &hinfo, frames); | 1571 | frame = dx_probe(d_name, dir, &hinfo, frames); |
1452 | if (IS_ERR(frame)) | 1572 | if (IS_ERR(frame)) |
1453 | return (struct buffer_head *) frame; | 1573 | return (struct buffer_head *) frame; |
@@ -1656,7 +1776,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1656 | 1776 | ||
1657 | /* create map in the end of data2 block */ | 1777 | /* create map in the end of data2 block */ |
1658 | map = (struct dx_map_entry *) (data2 + blocksize); | 1778 | map = (struct dx_map_entry *) (data2 + blocksize); |
1659 | count = dx_make_map((struct ext4_dir_entry_2 *) data1, | 1779 | count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1, |
1660 | blocksize, hinfo, map); | 1780 | blocksize, hinfo, map); |
1661 | map -= count; | 1781 | map -= count; |
1662 | dx_sort_map(map, count); | 1782 | dx_sort_map(map, count); |
@@ -1679,7 +1799,8 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1679 | hash2, split, count-split)); | 1799 | hash2, split, count-split)); |
1680 | 1800 | ||
1681 | /* Fancy dance to stay within two buffers */ | 1801 | /* Fancy dance to stay within two buffers */ |
1682 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); | 1802 | de2 = dx_move_dirents(data1, data2, map + split, count - split, |
1803 | blocksize); | ||
1683 | de = dx_pack_dirents(data1, blocksize); | 1804 | de = dx_pack_dirents(data1, blocksize); |
1684 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - | 1805 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
1685 | (char *) de, | 1806 | (char *) de, |
@@ -1735,15 +1856,48 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, | |||
1735 | int nlen, rlen; | 1856 | int nlen, rlen; |
1736 | unsigned int offset = 0; | 1857 | unsigned int offset = 0; |
1737 | char *top; | 1858 | char *top; |
1859 | struct ext4_fname_crypto_ctx *ctx = NULL; | ||
1860 | struct ext4_str fname_crypto_str = {.name = NULL, .len = 0}; | ||
1861 | int res; | ||
1862 | |||
1863 | ctx = ext4_get_fname_crypto_ctx(dir, EXT4_NAME_LEN); | ||
1864 | if (IS_ERR(ctx)) | ||
1865 | return -1; | ||
1866 | |||
1867 | if (ctx != NULL) { | ||
1868 | /* Calculate record length needed to store the entry */ | ||
1869 | res = ext4_fname_crypto_namelen_on_disk(ctx, namelen); | ||
1870 | if (res < 0) { | ||
1871 | ext4_put_fname_crypto_ctx(&ctx); | ||
1872 | return res; | ||
1873 | } | ||
1874 | reclen = EXT4_DIR_REC_LEN(res); | ||
1875 | |||
1876 | /* Allocate buffer to hold maximum name length */ | ||
1877 | res = ext4_fname_crypto_alloc_buffer(ctx, EXT4_NAME_LEN, | ||
1878 | &fname_crypto_str); | ||
1879 | if (res < 0) { | ||
1880 | ext4_put_fname_crypto_ctx(&ctx); | ||
1881 | return -1; | ||
1882 | } | ||
1883 | } | ||
1738 | 1884 | ||
1739 | de = (struct ext4_dir_entry_2 *)buf; | 1885 | de = (struct ext4_dir_entry_2 *)buf; |
1740 | top = buf + buf_size - reclen; | 1886 | top = buf + buf_size - reclen; |
1741 | while ((char *) de <= top) { | 1887 | while ((char *) de <= top) { |
1742 | if (ext4_check_dir_entry(dir, NULL, de, bh, | 1888 | if (ext4_check_dir_entry(dir, NULL, de, bh, |
1743 | buf, buf_size, offset)) | 1889 | buf, buf_size, offset)) { |
1744 | return -EIO; | 1890 | res = -EIO; |
1745 | if (ext4_match(namelen, name, de)) | 1891 | goto return_result; |
1746 | return -EEXIST; | 1892 | } |
1893 | /* Provide crypto context and crypto buffer to ext4 match */ | ||
1894 | res = ext4_match(ctx, &fname_crypto_str, namelen, name, de); | ||
1895 | if (res < 0) | ||
1896 | goto return_result; | ||
1897 | if (res > 0) { | ||
1898 | res = -EEXIST; | ||
1899 | goto return_result; | ||
1900 | } | ||
1747 | nlen = EXT4_DIR_REC_LEN(de->name_len); | 1901 | nlen = EXT4_DIR_REC_LEN(de->name_len); |
1748 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | 1902 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); |
1749 | if ((de->inode ? rlen - nlen : rlen) >= reclen) | 1903 | if ((de->inode ? rlen - nlen : rlen) >= reclen) |
@@ -1751,11 +1905,17 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode, | |||
1751 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | 1905 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); |
1752 | offset += rlen; | 1906 | offset += rlen; |
1753 | } | 1907 | } |
1754 | if ((char *) de > top) | ||
1755 | return -ENOSPC; | ||
1756 | 1908 | ||
1757 | *dest_de = de; | 1909 | if ((char *) de > top) |
1758 | return 0; | 1910 | res = -ENOSPC; |
1911 | else { | ||
1912 | *dest_de = de; | ||
1913 | res = 0; | ||
1914 | } | ||
1915 | return_result: | ||
1916 | ext4_put_fname_crypto_ctx(&ctx); | ||
1917 | ext4_fname_crypto_free_buffer(&fname_crypto_str); | ||
1918 | return res; | ||
1759 | } | 1919 | } |
1760 | 1920 | ||
1761 | int ext4_insert_dentry(struct inode *dir, | 1921 | int ext4_insert_dentry(struct inode *dir, |