2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *  linux/fs/ext4/dir.c
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Copyright (C) 1992, 1993, 1994, 1995
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Remy Card (card@masi.ibp.fr)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Laboratoire MASI - Institut Blaise Pascal
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Universite Pierre et Marie Curie (Paris VI)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  from
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  linux/fs/minix/dir.c
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  Copyright (C) 1991, 1992  Linus Torvalds
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *  ext4 directory handling functions
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *  Big-endian to little-endian byte-swapping/bitmaps by
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *        David S. Miller (davem@caip.rutgers.edu), 1995
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Hash Tree Directory indexing (c) 2001  Daniel Phillips
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/fs.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:21:01 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include <linux/jbd2.h>
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/buffer_head.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/slab.h>
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#include <linux/rbtree.h>
							 | 
						
					
						
							
								
									
										
										
										
											2008-04-29 18:13:32 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include "ext4.h"
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:59 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#include "xattr.h"
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ext4_dx_readdir(struct file *, struct dir_context *);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/**
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Check if the given dir-inode refers to an htree-indexed directory
							 | 
						
					
						
							
								
									
										
										
										
											2013-08-28 14:40:12 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * (or a directory which could potentially get converted to use htree
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * indexing).
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Return 1 if it is a dx dir, 0 if not
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static int is_dx_dir(struct inode *inode)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct super_block *sb = inode->i_sb;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										     EXT4_FEATURE_COMPAT_DIR_INDEX) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
							 | 
						
					
						
							
								
									
										
										
										
											2013-04-19 17:53:09 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									     ((inode->i_size >> sb->s_blocksize_bits) == 1) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									     ext4_has_inline_data(inode)))
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Return 0 if the directory entry is OK, and 1 if there is a problem
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Note: this is the opposite of what ext2 and ext3 historically returned...
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:59 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * bh passed here can be an inode block or a dir data block, depending
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * on the inode inline data flag.
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-27 11:54:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int __ext4_check_dir_entry(const char *function, unsigned int line,
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											   struct inode *dir, struct file *filp,
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-27 11:54:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											   struct ext4_dir_entry_2 *de,
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:58 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											   struct buffer_head *bh, char *buf, int size,
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-27 11:54:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											   unsigned int offset)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									const char *error_msg = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-14 23:01:36 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									const int rlen = ext4_rec_len_from_disk(de->rec_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														dir->i_sb->s_blocksize);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (unlikely(rlen < EXT4_DIR_REC_LEN(1)))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										error_msg = "rec_len is smaller than minimal";
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else if (unlikely(rlen % 4 != 0))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										error_msg = "rec_len % 4 != 0";
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len)))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										error_msg = "rec_len is too small for name_len";
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:58 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else if (unlikely(((char *) de - buf) + rlen > size))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										error_msg = "directory entry across range";
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else if (unlikely(le32_to_cpu(de->inode) >
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count)))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										error_msg = "inode out of bounds";
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (filp)
							 | 
						
					
						
							
								
									
										
										
										
											2012-02-20 17:53:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ext4_error_file(filp, function, line, bh->b_blocknr,
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												"bad entry in directory: %s - offset=%u(%u), "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												"inode=%u, rec_len=%d, name_len=%d",
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:58 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												error_msg, (unsigned) (offset % size),
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												offset, le32_to_cpu(de->inode),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												rlen, de->name_len);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							
								
									
										
										
										
											2012-02-20 17:53:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ext4_error_inode(dir, function, line, bh->b_blocknr,
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												"bad entry in directory: %s - offset=%u(%u), "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												"inode=%u, rec_len=%d, name_len=%d",
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:58 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												error_msg, (unsigned) (offset % size),
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												offset, le32_to_cpu(de->inode),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												rlen, de->name_len);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-12-19 22:07:02 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return 1;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ext4_readdir(struct file *file, struct dir_context *ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2008-11-05 00:14:04 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									unsigned int offset;
							 | 
						
					
						
							
								
									
										
										
										
											2014-05-27 12:48:55 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int i;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct ext4_dir_entry_2 *de;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int err;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct inode *inode = file_inode(file);
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct super_block *sb = inode->i_sb;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-09 11:15:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									int dir_has_error = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (is_dx_dir(inode)) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										err = ext4_dx_readdir(file, ctx);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (err != ERR_BAD_DX_DIR) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											return err;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * We don't set the inode dirty flag since it's not
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * critical that it get flushed back to the disk.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ext4_clear_inode_flag(file_inode(file),
							 | 
						
					
						
							
								
									
										
										
										
											2010-06-14 09:54:48 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												      EXT4_INODE_INDEX);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2013-04-19 17:53:09 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (ext4_has_inline_data(inode)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										int has_inline_data = 1;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										int ret = ext4_read_inline_dir(file, ctx,
							 | 
						
					
						
							
								
									
										
										
										
											2013-04-19 17:53:09 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													   &has_inline_data);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (has_inline_data)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									offset = ctx->pos & (sb->s_blocksize - 1);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									while (ctx->pos < inode->i_size) {
							 | 
						
					
						
							
								
									
										
										
										
											2010-05-16 20:00:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										struct ext4_map_blocks map;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										struct buffer_head *bh = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
							 | 
						
					
						
							
								
									
										
										
										
											2010-05-16 20:00:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										map.m_len = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										err = ext4_map_blocks(NULL, inode, &map, 0);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (err > 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2010-05-16 20:00:00 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											pgoff_t index = map.m_pblk >>
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-19 01:48:04 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													(PAGE_CACHE_SHIFT - inode->i_blkbits);
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (!ra_has_index(&file->f_ra, index))
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-19 01:48:08 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												page_cache_sync_readahead(
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-19 01:48:04 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													sb->s_bdev->bd_inode->i_mapping,
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													&file->f_ra, file,
							 | 
						
					
						
							
								
									
										
										
										
											2007-07-19 01:48:08 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													index, 1);
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT;
							 | 
						
					
						
							
								
									
										
										
										
											2014-08-29 20:52:15 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											bh = ext4_bread(NULL, inode, map.m_lblk, 0);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (IS_ERR(bh))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												return PTR_ERR(bh);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (!bh) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-09 11:15:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (!dir_has_error) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												EXT4_ERROR_FILE(file, 0,
							 | 
						
					
						
							
								
									
										
										
										
											2011-01-10 12:10:55 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														"directory contains a "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														"hole at offset %llu",
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													   (unsigned long long) ctx->pos);
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-09 11:15:52 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												dir_has_error = 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												[PATCH] handle ext4 directory corruption better
I've been using Steve Grubb's purely evil "fsfuzzer" tool, at
http://people.redhat.com/sgrubb/files/fsfuzzer-0.4.tar.gz
Basically it makes a filesystem, splats some random bits over it, then
tries to mount it and do some simple filesystem actions.
At best, the filesystem catches the corruption gracefully.  At worst,
things spin out of control.
As you might guess, we found a couple places in ext4 where things spin out
of control :)
First, we had a corrupted directory that was never checked for
consistency...  it was corrupt, and pointed to another bad "entry" of
length 0.  The for() loop looped forever, since the length of
ext4_next_entry(de) was 0, and we kept looking at the same pointer over and
over and over and over...  I modeled this check and subsequent action on
what is done for other directory types in ext4_readdir...
(adding this check adds some computational expense; I am testing a followup
patch to reduce the number of times we check and re-check these directory
entries, in all cases.  Thanks for the idea, Andreas).
Next we had a root directory inode which had a corrupted size, claimed to
be > 200M on a 4M filesystem.  There was only really 1 block in the
directory, but because the size was so large, readdir kept coming back for
more, spewing thousands of printk's along the way.
Per Andreas' suggestion, if we're in this read error condition and we're
trying to read an offset which is greater than i_blocks worth of bytes,
stop trying, and break out of the loop.
With these two changes fsfuzz test survives quite well on ext4.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
											
										 
										
											2006-12-06 20:36:28 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											/* corrupt size?  Maybe no more blocks to read */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (ctx->pos > inode->i_blocks << 9)
							 | 
						
					
						
							
								
									
										
											 
										 
										
											
												[PATCH] handle ext4 directory corruption better
I've been using Steve Grubb's purely evil "fsfuzzer" tool, at
http://people.redhat.com/sgrubb/files/fsfuzzer-0.4.tar.gz
Basically it makes a filesystem, splats some random bits over it, then
tries to mount it and do some simple filesystem actions.
At best, the filesystem catches the corruption gracefully.  At worst,
things spin out of control.
As you might guess, we found a couple places in ext4 where things spin out
of control :)
First, we had a corrupted directory that was never checked for
consistency...  it was corrupt, and pointed to another bad "entry" of
length 0.  The for() loop looped forever, since the length of
ext4_next_entry(de) was 0, and we kept looking at the same pointer over and
over and over and over...  I modeled this check and subsequent action on
what is done for other directory types in ext4_readdir...
(adding this check adds some computational expense; I am testing a followup
patch to reduce the number of times we check and re-check these directory
entries, in all cases.  Thanks for the idea, Andreas).
Next we had a root directory inode which had a corrupted size, claimed to
be > 200M on a 4M filesystem.  There was only really 1 block in the
directory, but because the size was so large, readdir kept coming back for
more, spewing thousands of printk's along the way.
Per Andreas' suggestion, if we're in this read error condition and we're
trying to read an offset which is greater than i_blocks worth of bytes,
stop trying, and break out of the loop.
With these two changes fsfuzz test survives quite well on ext4.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
											
										 
										
											2006-12-06 20:36:28 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												break;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											ctx->pos += sb->s_blocksize - offset;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-29 18:41:10 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										/* Check the checksum */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (!buffer_verified(bh) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    !ext4_dirent_csum_verify(inode,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												(struct ext4_dir_entry *)bh->b_data)) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											EXT4_ERROR_FILE(file, 0, "directory fails checksum "
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-29 18:41:10 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													"at offset %llu",
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
													(unsigned long long)ctx->pos);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											ctx->pos += sb->s_blocksize - offset;
							 | 
						
					
						
							
								
									
										
										
										
											2013-01-28 21:23:24 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											brelse(bh);
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-29 18:41:10 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											continue;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										set_buffer_verified(bh);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/* If the dir block has changed since the last call to
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * readdir(2), then we might be pointing to an invalid
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * dirent right now.  Scan from the start of the block
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * to make sure. */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (file->f_version != inode->i_version) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											for (i = 0; i < sb->s_blocksize && i < offset; ) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												de = (struct ext4_dir_entry_2 *)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
													(bh->b_data + i);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												/* It's too expensive to do a full
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 * dirent test each time round this
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 * loop, but we do have to test at
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 * least that it is non-zero.  A
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 * failure will be detected in the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												 * dirent test below. */
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-14 23:01:36 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												if (ext4_rec_len_from_disk(de->rec_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													sb->s_blocksize) < EXT4_DIR_REC_LEN(1))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
													break;
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-14 23:01:36 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												i += ext4_rec_len_from_disk(de->rec_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
															    sb->s_blocksize);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											offset = i;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												| offset;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											file->f_version = inode->i_version;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										while (ctx->pos < inode->i_size
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										       && offset < sb->s_blocksize) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											if (ext4_check_dir_entry(inode, file, de, bh,
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-10 14:05:58 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														 bh->b_data, bh->b_size,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														 offset)) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:21:24 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												/*
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												 * On error, skip to the next block
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:21:24 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												 */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												ctx->pos = (ctx->pos |
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
														(sb->s_blocksize - 1)) + 1;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												break;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-14 23:01:36 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											offset += ext4_rec_len_from_disk(de->rec_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													sb->s_blocksize);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (le32_to_cpu(de->inode)) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												if (!dir_emit(ctx, de->name,
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
														de->name_len,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														le32_to_cpu(de->inode),
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														get_dtype(sb, de->file_type))) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													brelse(bh);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												}
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											ctx->pos += ext4_rec_len_from_disk(de->rec_len,
							 | 
						
					
						
							
								
									
										
										
										
											2009-02-14 23:01:36 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														sb->s_blocksize);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										offset = 0;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										brelse(bh);
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (ctx->pos < inode->i_size) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (!dir_relax(inode))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static inline int is_32bit_api(void)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#ifdef CONFIG_COMPAT
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return is_compat_task();
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return (BITS_PER_LONG == 32);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * These functions convert from the major/minor hash to an f_pos
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * value for dx directories
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Upper layer (for example NFS) should specify FMODE_32BITHASH or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * directly on both 32-bit and 64-bit nodes, under such case, neither
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * FMODE_32BITHASH nor FMODE_64BITHASH is specified.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((filp->f_mode & FMODE_32BITHASH) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return major >> 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return ((__u64)(major >> 1) << 32) | (__u64)minor;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline __u32 pos2maj_hash(struct file *filp, loff_t pos)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((filp->f_mode & FMODE_32BITHASH) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return (pos << 1) & 0xffffffff;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return ((pos >> 32) << 1) & 0xffffffff;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline __u32 pos2min_hash(struct file *filp, loff_t pos)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((filp->f_mode & FMODE_32BITHASH) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return pos & 0xffffffff;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Return 32- or 64-bit end-of-file for dx directories
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static inline loff_t ext4_get_htree_eof(struct file *filp)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((filp->f_mode & FMODE_32BITHASH) ||
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return EXT4_HTREE_EOF_32BIT;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return EXT4_HTREE_EOF_64BIT;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-30 13:14:03 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * ext4_dir_llseek() calls generic_file_llseek_size to handle htree
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * directories, where the "offset" is in terms of the filename hash
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * value instead of the byte offset.
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-30 13:14:03 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * Because we may return a 64-bit hash that is well beyond offset limits,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * we need to pass the max hash as the maximum allowable offset in
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * the htree directory case.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 *
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * For non-htree, ext4_llseek already chooses the proper max offset.
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2013-03-02 17:24:05 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence)
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct inode *inode = file->f_mapping->host;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int dx_dir = is_dx_dir(inode);
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-30 13:14:03 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									loff_t htree_max = ext4_get_htree_eof(file);
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-30 13:14:03 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (likely(dx_dir))
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-17 15:59:39 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return generic_file_llseek_size(file, offset, whence,
							 | 
						
					
						
							
								
									
										
										
										
											2012-04-30 13:14:03 -05:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
														    htree_max, htree_max);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									else
							 | 
						
					
						
							
								
									
										
										
										
											2012-12-17 15:59:39 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										return ext4_llseek(file, offset, whence);
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * This structure holds the nodes of the red-black tree used to store
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * the directory entry in hash order.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								struct fname {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									__u32		hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									__u32		minor_hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct rb_node	rb_hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct fname	*next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									__u32		inode;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									__u8		name_len;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									__u8		file_type;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									char		name[0];
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * This functoin implements a non-recursive way of freeing all of the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * nodes in the red-black tree.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								static void free_rb_tree_fname(struct rb_root *root)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2014-01-23 15:56:10 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct fname *fname, *next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										while (fname) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											struct fname *old = fname;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											fname = fname->next;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											kfree(old);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							
								
									
										
										
										
											2014-01-23 15:56:10 -08:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									*root = RB_ROOT;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
															   loff_t pos)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct dir_private_info *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-07-11 19:27:31 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!p)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									p->curr_hash = pos2maj_hash(filp, pos);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									p->curr_minor_hash = pos2min_hash(filp, pos);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								void ext4_htree_free_dir_info(struct dir_private_info *p)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									free_rb_tree_fname(&p->root);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									kfree(p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * Given a directory entry, enter it into the fname rb tree.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											     __u32 minor_hash,
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											     struct ext4_dir_entry_2 *dirent)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct rb_node **p, *parent = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct fname *fname, *new_fn;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct dir_private_info *info;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int len;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2010-07-27 11:56:04 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									info = dir_file->private_data;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									p = &info->root.rb_node;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Create and allocate the fname structure */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									len = sizeof(struct fname) + dirent->name_len + 1;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn = kzalloc(len, GFP_KERNEL);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!new_fn)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -ENOMEM;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->hash = hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->minor_hash = minor_hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->inode = le32_to_cpu(dirent->inode);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->name_len = dirent->name_len;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->file_type = dirent->file_type;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									memcpy(new_fn->name, dirent->name, dirent->name_len);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									new_fn->name[dirent->name_len] = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									while (*p) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										parent = *p;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										fname = rb_entry(parent, struct fname, rb_hash);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * If the hash and minor hash match up, then we put
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * them on a linked list.  This rarely happens...
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if ((new_fn->hash == fname->hash) &&
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										    (new_fn->minor_hash == fname->minor_hash)) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											new_fn->next = fname->next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											fname->next = new_fn;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (new_fn->hash < fname->hash)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											p = &(*p)->rb_left;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										else if (new_fn->hash > fname->hash)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											p = &(*p)->rb_right;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										else if (new_fn->minor_hash < fname->minor_hash)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											p = &(*p)->rb_left;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										else /* if (new_fn->minor_hash > fname->minor_hash) */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											p = &(*p)->rb_right;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									rb_link_node(&new_fn->rb_hash, parent, p);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									rb_insert_color(&new_fn->rb_hash, &info->root);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								/*
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								 * This is a helper function for ext4_dx_readdir.  It calls filldir
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * for all entres on the fname linked list.  (Normally there is only
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 * one entry on the linked list, unless there are 62 bit hash collisions.)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								 */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int call_filldir(struct file *file, struct dir_context *ctx,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											struct fname *fname)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct dir_private_info *info = file->private_data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct inode *inode = file_inode(file);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct super_block *sb = inode->i_sb;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!fname) {
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-19 23:41:49 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: "
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 "called with null fname?!?", __func__, __LINE__,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											 inode->i_ino, current->comm);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									ctx->pos = hash2pos(file, fname->hash, fname->minor_hash);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									while (fname) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (!dir_emit(ctx, fname->name,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												fname->name_len,
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												fname->inode,
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												get_dtype(sb, fname->file_type))) {
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-19 21:57:43 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											info->extra_fname = fname;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											return 1;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										fname = fname->next;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ext4_dx_readdir(struct file *file, struct dir_context *ctx)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									struct dir_private_info *info = file->private_data;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct inode *inode = file_inode(file);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct fname *fname;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int	ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if (!info) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										info = ext4_htree_create_dir_info(file, ctx->pos);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (!info)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -ENOMEM;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										file->private_data = info;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (ctx->pos == ext4_get_htree_eof(file))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return 0;	/* EOF */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/* Some one has messed with f_pos; reset the world */
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (info->last_pos != ctx->pos) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										free_rb_tree_fname(&info->root);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_node = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->extra_fname = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										info->curr_hash = pos2maj_hash(file, ctx->pos);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_minor_hash = pos2min_hash(file, ctx->pos);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * If there are any leftover names on the hash collision
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 * chain, return them first.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									 */
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-19 21:57:43 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (info->extra_fname) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (call_filldir(file, ctx, info->extra_fname))
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-19 21:57:43 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											goto finished;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->extra_fname = NULL;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-25 11:39:08 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										goto next_node;
							 | 
						
					
						
							
								
									
										
										
										
											2008-08-19 21:57:43 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									} else if (!info->curr_node)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_node = rb_first(&info->root);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									while (1) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										/*
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * Fill the rbtree if we have no more entries,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * or the inode has changed since we last read in the
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 * cached entries.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										 */
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if ((!info->curr_node) ||
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										    (file->f_version != inode->i_version)) {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_node = NULL;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											free_rb_tree_fname(&info->root);
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
											file->f_version = inode->i_version;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											ret = ext4_htree_fill_tree(file, info->curr_hash,
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
														   info->curr_minor_hash,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
														   &info->next_hash);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (ret < 0)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
												return ret;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (ret == 0) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												ctx->pos = ext4_get_htree_eof(file);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_node = rb_first(&info->root);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										fname = rb_entry(info->curr_node, struct fname, rb_hash);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_hash = fname->hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_minor_hash = fname->minor_hash;
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (call_filldir(file, ctx, fname))
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											break;
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-25 11:39:08 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									next_node:
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
										info->curr_node = rb_next(info->curr_node);
							 | 
						
					
						
							
								
									
										
										
										
											2008-10-25 11:39:08 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										if (info->curr_node) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											fname = rb_entry(info->curr_node, struct fname,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													 rb_hash);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_hash = fname->hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_minor_hash = fname->minor_hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										} else {
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
											if (info->next_hash == ~0) {
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
												ctx->pos = ext4_get_htree_eof(file);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
												break;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_hash = info->next_hash;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											info->curr_minor_hash = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								finished:
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									info->last_pos = ctx->pos;
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2008-09-08 22:25:24 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								static int ext4_release_dir(struct inode *inode, struct file *filp)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:21:24 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									if (filp->private_data)
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:53 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
										ext4_htree_free_dir_info(filp->private_data);
							 | 
						
					
						
							
								
									
										
										
										
											2006-10-11 01:20:50 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2014-07-28 13:06:26 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										      int buf_size)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								{
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									struct ext4_dir_entry_2 *de;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									int nlen, rlen;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									unsigned int offset = 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									char *top;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									de = (struct ext4_dir_entry_2 *)buf;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									top = buf + buf_size;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									while ((char *) de < top) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										if (ext4_check_dir_entry(dir, NULL, de, bh,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
													 buf, buf_size, offset))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
											return -EIO;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										nlen = EXT4_DIR_REC_LEN(de->name_len);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										offset += rlen;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									if ((char *) de > top)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
										return -EIO;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									return 0;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								const struct file_operations ext4_dir_operations = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.llseek		= ext4_dir_llseek,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.read		= generic_read_dir,
							 | 
						
					
						
							
								
									
										
										
										
											2013-05-17 16:08:53 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									.iterate	= ext4_readdir,
							 | 
						
					
						
							
								
									
										
										
										
											2012-03-18 22:44:40 -04:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
									.unlocked_ioctl = ext4_ioctl,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#ifdef CONFIG_COMPAT
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.compat_ioctl	= ext4_compat_ioctl,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								#endif
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.fsync		= ext4_sync_file,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
									.release	= ext4_release_dir,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 |