dir.c 9.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*
 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
 */

#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
8
#include "reiserfs.h"
L
Linus Torvalds 已提交
9 10
#include <linux/stat.h>
#include <linux/buffer_head.h>
11
#include <linux/slab.h>
L
Linus Torvalds 已提交
12 13
#include <asm/uaccess.h>

14
extern const struct reiserfs_key MIN_KEY;
L
Linus Torvalds 已提交
15

A
Al Viro 已提交
16
static int reiserfs_readdir(struct file *, struct dir_context *);
17 18
static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
			      int datasync);
L
Linus Torvalds 已提交
19

20
const struct file_operations reiserfs_dir_operations = {
21
	.llseek = generic_file_llseek,
22
	.read = generic_read_dir,
A
Al Viro 已提交
23
	.iterate = reiserfs_readdir,
24
	.fsync = reiserfs_dir_fsync,
25
	.unlocked_ioctl = reiserfs_ioctl,
26 27 28
#ifdef CONFIG_COMPAT
	.compat_ioctl = reiserfs_compat_ioctl,
#endif
L
Linus Torvalds 已提交
29 30
};

31 32
static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
			      int datasync)
33
{
34
	struct inode *inode = filp->f_mapping->host;
35
	int err;
36 37 38 39 40 41

	err = filemap_write_and_wait_range(inode->i_mapping, start, end);
	if (err)
		return err;

	mutex_lock(&inode->i_mutex);
42 43 44
	reiserfs_write_lock(inode->i_sb);
	err = reiserfs_commit_for_inode(inode);
	reiserfs_write_unlock(inode->i_sb);
45
	mutex_unlock(&inode->i_mutex);
46 47 48
	if (err < 0)
		return err;
	return 0;
L
Linus Torvalds 已提交
49 50 51 52
}

#define store_ih(where,what) copy_item_head (where, what)

53 54 55 56
static inline bool is_privroot_deh(struct dentry *dir,
				   struct reiserfs_de_head *deh)
{
	struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root;
57 58
	return (dir == dir->d_parent && privroot->d_inode &&
	        deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid);
59 60
}

A
Al Viro 已提交
61
int reiserfs_readdir_dentry(struct dentry *dentry, struct dir_context *ctx)
L
Linus Torvalds 已提交
62
{
63
	struct inode *inode = dentry->d_inode;
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
	struct cpu_key pos_key;	/* key of current position in the directory (key of directory entry) */
	INITIALIZE_PATH(path_to_entry);
	struct buffer_head *bh;
	int item_num, entry_num;
	const struct reiserfs_key *rkey;
	struct item_head *ih, tmp_ih;
	int search_res;
	char *local_buf;
	loff_t next_pos;
	char small_buf[32];	/* avoid kmalloc if we can */
	struct reiserfs_dir_entry de;
	int ret = 0;

	reiserfs_write_lock(inode->i_sb);

	reiserfs_check_lock_depth(inode->i_sb, "readdir");

	/* form key for search the next directory entry using f_pos field of
	   file structure */
A
Al Viro 已提交
83
	make_cpu_key(&pos_key, inode, ctx->pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
84 85 86 87 88 89 90 91 92 93 94 95 96
	next_pos = cpu_key_k_offset(&pos_key);

	path_to_entry.reada = PATH_READA;
	while (1) {
	      research:
		/* search the directory item, containing entry with specified key */
		search_res =
		    search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
					&de);
		if (search_res == IO_ERROR) {
			// FIXME: we could just skip part of directory which could
			// not be read
			ret = -EIO;
L
Linus Torvalds 已提交
97 98
			goto out;
		}
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
		entry_num = de.de_entry_num;
		bh = de.de_bh;
		item_num = de.de_item_num;
		ih = de.de_ih;
		store_ih(&tmp_ih, ih);

		/* we must have found item, that is item of this directory, */
		RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
		       "vs-9000: found item %h does not match to dir we readdir %K",
		       ih, &pos_key);
		RFALSE(item_num > B_NR_ITEMS(bh) - 1,
		       "vs-9005 item_num == %d, item amount == %d",
		       item_num, B_NR_ITEMS(bh));

		/* and entry must be not more than number of entries in the item */
		RFALSE(I_ENTRY_COUNT(ih) < entry_num,
		       "vs-9010: entry number is too big %d (%d)",
		       entry_num, I_ENTRY_COUNT(ih));

		if (search_res == POSITION_FOUND
		    || entry_num < I_ENTRY_COUNT(ih)) {
			/* go through all entries in the directory item beginning from the entry, that has been found */
			struct reiserfs_de_head *deh =
			    B_I_DEH(bh, ih) + entry_num;

			for (; entry_num < I_ENTRY_COUNT(ih);
			     entry_num++, deh++) {
				int d_reclen;
				char *d_name;
				ino_t d_ino;

				if (!de_visible(deh))
					/* it is hidden entry */
					continue;
				d_reclen = entry_length(bh, ih, entry_num);
				d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
135 136 137 138 139 140 141 142 143 144

				if (d_reclen <= 0 ||
				    d_name + d_reclen > bh->b_data + bh->b_size) {
					/* There is corrupted data in entry,
					 * We'd better stop here */
					pathrelse(&path_to_entry);
					ret = -EIO;
					goto out;
				}

145 146 147 148 149 150 151 152 153 154 155
				if (!d_name[d_reclen - 1])
					d_reclen = strlen(d_name);

				if (d_reclen >
				    REISERFS_MAX_NAME(inode->i_sb->
						      s_blocksize)) {
					/* too big to send back to VFS */
					continue;
				}

				/* Ignore the .reiserfs_priv entry */
156
				if (is_privroot_deh(dentry, deh))
157 158
					continue;

A
Al Viro 已提交
159
				ctx->pos = deh_offset(deh);
160 161 162 163
				d_ino = deh_objectid(deh);
				if (d_reclen <= 32) {
					local_buf = small_buf;
				} else {
164 165
					local_buf = kmalloc(d_reclen,
							    GFP_NOFS);
166 167 168 169 170 171
					if (!local_buf) {
						pathrelse(&path_to_entry);
						ret = -ENOMEM;
						goto out;
					}
					if (item_moved(&tmp_ih, &path_to_entry)) {
172
						kfree(local_buf);
173 174 175 176 177 178 179 180
						goto research;
					}
				}
				// Note, that we copy name to user space via temporary
				// buffer (local_buf) because filldir will block if
				// user space buffer is swapped out. At that time
				// entry can move to somewhere else
				memcpy(local_buf, d_name, d_reclen);
F
Frederic Weisbecker 已提交
181 182 183 184 185 186

				/*
				 * Since filldir might sleep, we can release
				 * the write lock here for other waiters
				 */
				reiserfs_write_unlock(inode->i_sb);
A
Al Viro 已提交
187 188 189
				if (!dir_emit
				    (ctx, local_buf, d_reclen, d_ino,
				     DT_UNKNOWN)) {
F
Frederic Weisbecker 已提交
190
					reiserfs_write_lock(inode->i_sb);
191
					if (local_buf != small_buf) {
192
						kfree(local_buf);
193 194 195
					}
					goto end;
				}
F
Frederic Weisbecker 已提交
196
				reiserfs_write_lock(inode->i_sb);
197
				if (local_buf != small_buf) {
198
					kfree(local_buf);
199 200 201 202 203
				}
				// next entry should be looked for with such offset
				next_pos = deh_offset(deh) + 1;

				if (item_moved(&tmp_ih, &path_to_entry)) {
204 205
					set_cpu_key_k_offset(&pos_key,
							     next_pos);
206 207 208
					goto research;
				}
			}	/* for */
L
Linus Torvalds 已提交
209 210
		}

211 212 213 214 215 216 217 218 219 220 221 222 223
		if (item_num != B_NR_ITEMS(bh) - 1)
			// end of directory has been reached
			goto end;

		/* item we went through is last item of node. Using right
		   delimiting key check is it directory end */
		rkey = get_rkey(&path_to_entry, inode->i_sb);
		if (!comp_le_keys(rkey, &MIN_KEY)) {
			/* set pos_key to key, that is the smallest and greater
			   that key of the last entry in the item */
			set_cpu_key_k_offset(&pos_key, next_pos);
			continue;
		}
L
Linus Torvalds 已提交
224

225 226 227
		if (COMP_SHORT_KEYS(rkey, &pos_key)) {
			// end of directory has been reached
			goto end;
L
Linus Torvalds 已提交
228
		}
229 230 231 232 233 234 235

		/* directory continues in the right neighboring block */
		set_cpu_key_k_offset(&pos_key,
				     le_key_k_offset(KEY_FORMAT_3_5, rkey));

	}			/* while */

236
end:
A
Al Viro 已提交
237
	ctx->pos = next_pos;
238 239
	pathrelse(&path_to_entry);
	reiserfs_check_path(&path_to_entry);
240
out:
241 242
	reiserfs_write_unlock(inode->i_sb);
	return ret;
L
Linus Torvalds 已提交
243 244
}

A
Al Viro 已提交
245
static int reiserfs_readdir(struct file *file, struct dir_context *ctx)
246
{
A
Al Viro 已提交
247
	return reiserfs_readdir_dentry(file->f_path.dentry, ctx);
248 249
}

L
Linus Torvalds 已提交
250 251 252
/* compose directory item containing "." and ".." entries (entries are
   not aligned to 4 byte boundary) */
/* the last four params are LE */
253 254
void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
			    __le32 par_dirid, __le32 par_objid)
L
Linus Torvalds 已提交
255
{
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
	struct reiserfs_de_head *deh;

	memset(body, 0, EMPTY_DIR_SIZE_V1);
	deh = (struct reiserfs_de_head *)body;

	/* direntry header of "." */
	put_deh_offset(&(deh[0]), DOT_OFFSET);
	/* these two are from make_le_item_head, and are are LE */
	deh[0].deh_dir_id = dirid;
	deh[0].deh_objectid = objid;
	deh[0].deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(&(deh[0]), EMPTY_DIR_SIZE_V1 - strlen("."));
	mark_de_visible(&(deh[0]));

	/* direntry header of ".." */
	put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
	/* key of ".." for the root directory */
	/* these two are from the inode, and are are LE */
	deh[1].deh_dir_id = par_dirid;
	deh[1].deh_objectid = par_objid;
	deh[1].deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(&(deh[1]), deh_location(&(deh[0])) - strlen(".."));
	mark_de_visible(&(deh[1]));

	/* copy ".." and "." */
	memcpy(body + deh_location(&(deh[0])), ".", 1);
	memcpy(body + deh_location(&(deh[1])), "..", 2);
L
Linus Torvalds 已提交
283 284 285
}

/* compose directory item containing "." and ".." entries */
286 287
void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
			 __le32 par_dirid, __le32 par_objid)
L
Linus Torvalds 已提交
288
{
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	struct reiserfs_de_head *deh;

	memset(body, 0, EMPTY_DIR_SIZE);
	deh = (struct reiserfs_de_head *)body;

	/* direntry header of "." */
	put_deh_offset(&(deh[0]), DOT_OFFSET);
	/* these two are from make_le_item_head, and are are LE */
	deh[0].deh_dir_id = dirid;
	deh[0].deh_objectid = objid;
	deh[0].deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(&(deh[0]), EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
	mark_de_visible(&(deh[0]));

	/* direntry header of ".." */
	put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
	/* key of ".." for the root directory */
	/* these two are from the inode, and are are LE */
	deh[1].deh_dir_id = par_dirid;
	deh[1].deh_objectid = par_objid;
	deh[1].deh_state = 0;	/* Endian safe if 0 */
	put_deh_location(&(deh[1]),
			 deh_location(&(deh[0])) - ROUND_UP(strlen("..")));
	mark_de_visible(&(deh[1]));

	/* copy ".." and "." */
	memcpy(body + deh_location(&(deh[0])), ".", 1);
	memcpy(body + deh_location(&(deh[1])), "..", 2);
L
Linus Torvalds 已提交
317
}