aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/dir.c25
-rw-r--r--fs/ext4/ext4.h12
-rw-r--r--fs/ext4/inline.c136
-rw-r--r--fs/ext4/xattr.h9
4 files changed, 169 insertions, 13 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 7c9d08b0f2fe..b8d877f6c1fa 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -27,23 +27,11 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/rbtree.h> 28#include <linux/rbtree.h>
29#include "ext4.h" 29#include "ext4.h"
30 30#include "xattr.h"
31static unsigned char ext4_filetype_table[] = {
32 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
33};
34 31
35static int ext4_dx_readdir(struct file *filp, 32static int ext4_dx_readdir(struct file *filp,
36 void *dirent, filldir_t filldir); 33 void *dirent, filldir_t filldir);
37 34
38static unsigned char get_dtype(struct super_block *sb, int filetype)
39{
40 if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
41 (filetype >= EXT4_FT_MAX))
42 return DT_UNKNOWN;
43
44 return (ext4_filetype_table[filetype]);
45}
46
47/** 35/**
48 * Check if the given dir-inode refers to an htree-indexed directory 36 * Check if the given dir-inode refers to an htree-indexed directory
49 * (or a directory which chould potentially get coverted to use htree 37 * (or a directory which chould potentially get coverted to use htree
@@ -68,6 +56,9 @@ static int is_dx_dir(struct inode *inode)
68 * Return 0 if the directory entry is OK, and 1 if there is a problem 56 * Return 0 if the directory entry is OK, and 1 if there is a problem
69 * 57 *
70 * Note: this is the opposite of what ext2 and ext3 historically returned... 58 * Note: this is the opposite of what ext2 and ext3 historically returned...
59 *
60 * bh passed here can be an inode block or a dir data block, depending
61 * on the inode inline data flag.
71 */ 62 */
72int __ext4_check_dir_entry(const char *function, unsigned int line, 63int __ext4_check_dir_entry(const char *function, unsigned int line,
73 struct inode *dir, struct file *filp, 64 struct inode *dir, struct file *filp,
@@ -124,6 +115,14 @@ static int ext4_readdir(struct file *filp,
124 int ret = 0; 115 int ret = 0;
125 int dir_has_error = 0; 116 int dir_has_error = 0;
126 117
118 if (ext4_has_inline_data(inode)) {
119 int has_inline_data = 1;
120 ret = ext4_read_inline_dir(filp, dirent, filldir,
121 &has_inline_data);
122 if (has_inline_data)
123 return ret;
124 }
125
127 if (is_dx_dir(inode)) { 126 if (is_dx_dir(inode)) {
128 err = ext4_dx_readdir(filp, dirent, filldir); 127 err = ext4_dx_readdir(filp, dirent, filldir);
129 if (err != ERR_BAD_DX_DIR) { 128 if (err != ERR_BAD_DX_DIR) {
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 689ce1d696b8..e3a74658c63c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1989,6 +1989,18 @@ static inline void ext4_update_dx_flag(struct inode *inode)
1989 EXT4_FEATURE_COMPAT_DIR_INDEX)) 1989 EXT4_FEATURE_COMPAT_DIR_INDEX))
1990 ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); 1990 ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
1991} 1991}
1992static unsigned char ext4_filetype_table[] = {
1993 DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
1994};
1995
1996static inline unsigned char get_dtype(struct super_block *sb, int filetype)
1997{
1998 if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
1999 (filetype >= EXT4_FT_MAX))
2000 return DT_UNKNOWN;
2001
2002 return ext4_filetype_table[filetype];
2003}
1992 2004
1993/* fsync.c */ 2005/* fsync.c */
1994extern int ext4_sync_file(struct file *, loff_t, loff_t, int); 2006extern int ext4_sync_file(struct file *, loff_t, loff_t, int);
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index bf7322818738..471504133c76 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1288,6 +1288,142 @@ out:
1288 return ret; 1288 return ret;
1289} 1289}
1290 1290
1291int ext4_read_inline_dir(struct file *filp,
1292 void *dirent, filldir_t filldir,
1293 int *has_inline_data)
1294{
1295 int error = 0;
1296 unsigned int offset, parent_ino;
1297 int i, stored;
1298 struct ext4_dir_entry_2 *de;
1299 struct super_block *sb;
1300 struct inode *inode = filp->f_path.dentry->d_inode;
1301 int ret, inline_size = 0;
1302 struct ext4_iloc iloc;
1303 void *dir_buf = NULL;
1304
1305 ret = ext4_get_inode_loc(inode, &iloc);
1306 if (ret)
1307 return ret;
1308
1309 down_read(&EXT4_I(inode)->xattr_sem);
1310 if (!ext4_has_inline_data(inode)) {
1311 up_read(&EXT4_I(inode)->xattr_sem);
1312 *has_inline_data = 0;
1313 goto out;
1314 }
1315
1316 inline_size = ext4_get_inline_size(inode);
1317 dir_buf = kmalloc(inline_size, GFP_NOFS);
1318 if (!dir_buf) {
1319 ret = -ENOMEM;
1320 up_read(&EXT4_I(inode)->xattr_sem);
1321 goto out;
1322 }
1323
1324 ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc);
1325 up_read(&EXT4_I(inode)->xattr_sem);
1326 if (ret < 0)
1327 goto out;
1328
1329 sb = inode->i_sb;
1330 stored = 0;
1331 parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
1332
1333 while (!error && !stored && filp->f_pos < inode->i_size) {
1334revalidate:
1335 /*
1336 * If the version has changed since the last call to
1337 * readdir(2), then we might be pointing to an invalid
1338 * dirent right now. Scan from the start of the inline
1339 * dir to make sure.
1340 */
1341 if (filp->f_version != inode->i_version) {
1342 for (i = 0;
1343 i < inode->i_size && i < offset;) {
1344 if (!i) {
1345 /* skip "." and ".." if needed. */
1346 i += EXT4_INLINE_DOTDOT_SIZE;
1347 continue;
1348 }
1349 de = (struct ext4_dir_entry_2 *)
1350 (dir_buf + i);
1351 /* It's too expensive to do a full
1352 * dirent test each time round this
1353 * loop, but we do have to test at
1354 * least that it is non-zero. A
1355 * failure will be detected in the
1356 * dirent test below. */
1357 if (ext4_rec_len_from_disk(de->rec_len,
1358 inline_size) < EXT4_DIR_REC_LEN(1))
1359 break;
1360 i += ext4_rec_len_from_disk(de->rec_len,
1361 inline_size);
1362 }
1363 offset = i;
1364 filp->f_pos = offset;
1365 filp->f_version = inode->i_version;
1366 }
1367
1368 while (!error && filp->f_pos < inode->i_size) {
1369 if (filp->f_pos == 0) {
1370 error = filldir(dirent, ".", 1, 0, inode->i_ino,
1371 DT_DIR);
1372 if (error)
1373 break;
1374 stored++;
1375
1376 error = filldir(dirent, "..", 2, 0, parent_ino,
1377 DT_DIR);
1378 if (error)
1379 break;
1380 stored++;
1381
1382 filp->f_pos = offset = EXT4_INLINE_DOTDOT_SIZE;
1383 continue;
1384 }
1385
1386 de = (struct ext4_dir_entry_2 *)(dir_buf + offset);
1387 if (ext4_check_dir_entry(inode, filp, de,
1388 iloc.bh, dir_buf,
1389 inline_size, offset)) {
1390 ret = stored;
1391 goto out;
1392 }
1393 offset += ext4_rec_len_from_disk(de->rec_len,
1394 inline_size);
1395 if (le32_to_cpu(de->inode)) {
1396 /* We might block in the next section
1397 * if the data destination is
1398 * currently swapped out. So, use a
1399 * version stamp to detect whether or
1400 * not the directory has been modified
1401 * during the copy operation.
1402 */
1403 u64 version = filp->f_version;
1404
1405 error = filldir(dirent, de->name,
1406 de->name_len,
1407 filp->f_pos,
1408 le32_to_cpu(de->inode),
1409 get_dtype(sb, de->file_type));
1410 if (error)
1411 break;
1412 if (version != filp->f_version)
1413 goto revalidate;
1414 stored++;
1415 }
1416 filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
1417 inline_size);
1418 }
1419 offset = 0;
1420 }
1421out:
1422 kfree(dir_buf);
1423 brelse(iloc.bh);
1424 return ret;
1425}
1426
1291/* 1427/*
1292 * Try to create the inline data for the new dir. 1428 * Try to create the inline data for the new dir.
1293 * If it succeeds, return 0, otherwise return the error. 1429 * If it succeeds, return 0, otherwise return the error.
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 397ef4bbaf1e..539e6a08c95f 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -168,6 +168,9 @@ extern int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry,
168extern int ext4_try_create_inline_dir(handle_t *handle, 168extern int ext4_try_create_inline_dir(handle_t *handle,
169 struct inode *parent, 169 struct inode *parent,
170 struct inode *inode); 170 struct inode *inode);
171extern int ext4_read_inline_dir(struct file *filp,
172 void *dirent, filldir_t filldir,
173 int *has_inline_data);
171# else /* CONFIG_EXT4_FS_XATTR */ 174# else /* CONFIG_EXT4_FS_XATTR */
172 175
173static inline int 176static inline int
@@ -346,6 +349,12 @@ static inline int ext4_try_create_inline_dir(handle_t *handle,
346{ 349{
347 return 0; 350 return 0;
348} 351}
352static inline int ext4_read_inline_dir(struct file *filp,
353 void *dirent, filldir_t filldir,
354 int *has_inline_data)
355{
356 return 0;
357}
349# endif /* CONFIG_EXT4_FS_XATTR */ 358# endif /* CONFIG_EXT4_FS_XATTR */
350 359
351#ifdef CONFIG_EXT4_FS_SECURITY 360#ifdef CONFIG_EXT4_FS_SECURITY