Blame view

fs/reiserfs/dir.c 9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/fs.h>
f466c6fdb   Al Viro   move private bits...
7
  #include "reiserfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
  #include <linux/stat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/buffer_head.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
10
  #include <linux/slab.h>
17093991a   Fabian Frederick   fs/reiserfs: use ...
11
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12

5a1b63914   David Woodhouse   Missing 'const' f...
13
  extern const struct reiserfs_key MIN_KEY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

4acf381e1   Al Viro   [readdir] convert...
15
  static int reiserfs_readdir(struct file *, struct dir_context *);
02c24a821   Josef Bacik   fs: push i_mutex ...
16
17
  static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
  			      int datasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
19
  const struct file_operations reiserfs_dir_operations = {
ca572727d   jan Blunck   fs/: do not fallb...
20
  	.llseek = generic_file_llseek,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
21
  	.read = generic_read_dir,
c51da20c4   Al Viro   more trivial ->it...
22
  	.iterate_shared = reiserfs_readdir,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
23
  	.fsync = reiserfs_dir_fsync,
205cb37b8   Frederic Weisbecker   kill-the-bkl/reis...
24
  	.unlocked_ioctl = reiserfs_ioctl,
52b499c43   David Howells   [PATCH] BLOCK: Mo...
25
26
27
  #ifdef CONFIG_COMPAT
  	.compat_ioctl = reiserfs_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  };
02c24a821   Josef Bacik   fs: push i_mutex ...
29
30
  static int reiserfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
  			      int datasync)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
31
  {
7ea808591   Christoph Hellwig   drop unused dentr...
32
  	struct inode *inode = filp->f_mapping->host;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
33
  	int err;
02c24a821   Josef Bacik   fs: push i_mutex ...
34

3b49c9a1e   Jeff Layton   fs: convert a pil...
35
  	err = file_write_and_wait_range(filp, start, end);
02c24a821   Josef Bacik   fs: push i_mutex ...
36
37
  	if (err)
  		return err;
5955102c9   Al Viro   wrappers for ->i_...
38
  	inode_lock(inode);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
39
40
41
  	reiserfs_write_lock(inode->i_sb);
  	err = reiserfs_commit_for_inode(inode);
  	reiserfs_write_unlock(inode->i_sb);
5955102c9   Al Viro   wrappers for ->i_...
42
  	inode_unlock(inode);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
43
44
45
  	if (err < 0)
  		return err;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #define store_ih(where,what) copy_item_head (where, what)
99ce4169a   Al Viro   reiserfs: is_priv...
48
  static inline bool is_privroot_deh(struct inode *dir, struct reiserfs_de_head *deh)
677c9b2e3   Jeff Mahoney   reiserfs: remove ...
49
  {
99ce4169a   Al Viro   reiserfs: is_priv...
50
  	struct dentry *privroot = REISERFS_SB(dir->i_sb)->priv_root;
2b0143b5c   David Howells   VFS: normal files...
51
52
  	return (d_really_is_positive(privroot) &&
  	        deh->deh_objectid == INODE_PKEY(d_inode(privroot))->k_objectid);
677c9b2e3   Jeff Mahoney   reiserfs: remove ...
53
  }
cd62cdae0   Al Viro   reiserfs: switch ...
54
  int reiserfs_readdir_inode(struct inode *inode, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
098297b27   Jeff Mahoney   reiserfs: cleanup...
56
57
58
  
  	/* key of current position in the directory (key of directory entry) */
  	struct cpu_key pos_key;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
59
60
61
62
63
64
65
66
67
68
69
  	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;
278f6679f   Jeff Mahoney   reiserfs: locking...
70
  	int depth;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
71
72
73
74
  
  	reiserfs_write_lock(inode->i_sb);
  
  	reiserfs_check_lock_depth(inode->i_sb, "readdir");
098297b27   Jeff Mahoney   reiserfs: cleanup...
75
76
77
78
  	/*
  	 * form key for search the next directory entry using
  	 * f_pos field of file structure
  	 */
4acf381e1   Al Viro   [readdir] convert...
79
  	make_cpu_key(&pos_key, inode, ctx->pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
80
  	next_pos = cpu_key_k_offset(&pos_key);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
81
82
  	path_to_entry.reada = PATH_READA;
  	while (1) {
cf776a7a4   Jeff Mahoney   reiserfs: cleanup...
83
  research:
098297b27   Jeff Mahoney   reiserfs: cleanup...
84
85
86
87
  		/*
  		 * search the directory item, containing entry with
  		 * specified key
  		 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
88
89
90
91
  		search_res =
  		    search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
  					&de);
  		if (search_res == IO_ERROR) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
92
93
94
95
  			/*
  			 * FIXME: we could just skip part of directory
  			 * which could not be read
  			 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
96
  			ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  		}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
99
100
101
102
103
104
105
  		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, */
a228bf8f0   Jeff Mahoney   reiserfs: cleanup...
106
  		RFALSE(COMP_SHORT_KEYS(&ih->ih_key, &pos_key),
bd4c625c0   Linus Torvalds   reiserfs: run scr...
107
108
109
110
111
  		       "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));
098297b27   Jeff Mahoney   reiserfs: cleanup...
112
113
114
115
  		/*
  		 * and entry must be not more than number of entries
  		 * in the item
  		 */
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
116
  		RFALSE(ih_entry_count(ih) < entry_num,
bd4c625c0   Linus Torvalds   reiserfs: run scr...
117
  		       "vs-9010: entry number is too big %d (%d)",
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
118
  		       entry_num, ih_entry_count(ih));
bd4c625c0   Linus Torvalds   reiserfs: run scr...
119

098297b27   Jeff Mahoney   reiserfs: cleanup...
120
121
122
123
  		/*
  		 * go through all entries in the directory item beginning
  		 * from the entry, that has been found
  		 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
124
  		if (search_res == POSITION_FOUND
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
125
  		    || entry_num < ih_entry_count(ih)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
126
127
  			struct reiserfs_de_head *deh =
  			    B_I_DEH(bh, ih) + entry_num;
4cf5f7add   Jeff Mahoney   reiserfs: cleanup...
128
  			for (; entry_num < ih_entry_count(ih);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
129
130
131
  			     entry_num++, deh++) {
  				int d_reclen;
  				char *d_name;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
132
  				ino_t d_ino;
01d888578   Jeff Mahoney   reiserfs: fix rac...
133
  				loff_t cur_pos = deh_offset(deh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
134

098297b27   Jeff Mahoney   reiserfs: cleanup...
135
  				/* it is hidden entry */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
136
  				if (!de_visible(deh))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
137
138
139
  					continue;
  				d_reclen = entry_length(bh, ih, entry_num);
  				d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
80eb68d23   Lepton Wu   reiserfs: fix ker...
140
141
142
  
  				if (d_reclen <= 0 ||
  				    d_name + d_reclen > bh->b_data + bh->b_size) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
143
144
145
146
  					/*
  					 * There is corrupted data in entry,
  					 * We'd better stop here
  					 */
80eb68d23   Lepton Wu   reiserfs: fix ker...
147
148
149
150
  					pathrelse(&path_to_entry);
  					ret = -EIO;
  					goto out;
  				}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
151
152
  				if (!d_name[d_reclen - 1])
  					d_reclen = strlen(d_name);
098297b27   Jeff Mahoney   reiserfs: cleanup...
153
  				/* too big to send back to VFS */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
154
155
156
  				if (d_reclen >
  				    REISERFS_MAX_NAME(inode->i_sb->
  						      s_blocksize)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
157
158
159
160
  					continue;
  				}
  
  				/* Ignore the .reiserfs_priv entry */
99ce4169a   Al Viro   reiserfs: is_priv...
161
  				if (is_privroot_deh(inode, deh))
bd4c625c0   Linus Torvalds   reiserfs: run scr...
162
  					continue;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
163

4acf381e1   Al Viro   [readdir] convert...
164
  				ctx->pos = deh_offset(deh);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
165
166
167
168
  				d_ino = deh_objectid(deh);
  				if (d_reclen <= 32) {
  					local_buf = small_buf;
  				} else {
d739b42b8   Pekka Enberg   [PATCH] reiserfs:...
169
170
  					local_buf = kmalloc(d_reclen,
  							    GFP_NOFS);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
171
172
173
174
175
176
  					if (!local_buf) {
  						pathrelse(&path_to_entry);
  						ret = -ENOMEM;
  						goto out;
  					}
  					if (item_moved(&tmp_ih, &path_to_entry)) {
d739b42b8   Pekka Enberg   [PATCH] reiserfs:...
177
  						kfree(local_buf);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
178
179
180
  						goto research;
  					}
  				}
098297b27   Jeff Mahoney   reiserfs: cleanup...
181
182
183
184
185
186
187
188
  
  				/*
  				 * 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
  				 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
189
  				memcpy(local_buf, d_name, d_reclen);
8ebc42323   Frederic Weisbecker   reiserfs: kill-th...
190
191
192
193
194
  
  				/*
  				 * Since filldir might sleep, we can release
  				 * the write lock here for other waiters
  				 */
278f6679f   Jeff Mahoney   reiserfs: locking...
195
  				depth = reiserfs_write_unlock_nested(inode->i_sb);
4acf381e1   Al Viro   [readdir] convert...
196
197
198
  				if (!dir_emit
  				    (ctx, local_buf, d_reclen, d_ino,
  				     DT_UNKNOWN)) {
278f6679f   Jeff Mahoney   reiserfs: locking...
199
  					reiserfs_write_lock_nested(inode->i_sb, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
200
  					if (local_buf != small_buf) {
d739b42b8   Pekka Enberg   [PATCH] reiserfs:...
201
  						kfree(local_buf);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
202
203
204
  					}
  					goto end;
  				}
278f6679f   Jeff Mahoney   reiserfs: locking...
205
  				reiserfs_write_lock_nested(inode->i_sb, depth);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
206
  				if (local_buf != small_buf) {
d739b42b8   Pekka Enberg   [PATCH] reiserfs:...
207
  					kfree(local_buf);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
208
  				}
01d888578   Jeff Mahoney   reiserfs: fix rac...
209
210
211
  
  				/* deh_offset(deh) may be invalid now. */
  				next_pos = cur_pos + 1;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
212
213
  
  				if (item_moved(&tmp_ih, &path_to_entry)) {
0bdc7acba   Jeff Mahoney   reiserfs: fix spu...
214
215
  					set_cpu_key_k_offset(&pos_key,
  							     next_pos);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
216
217
218
  					goto research;
  				}
  			}	/* for */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  		}
098297b27   Jeff Mahoney   reiserfs: cleanup...
220
  		/* end of directory has been reached */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
221
  		if (item_num != B_NR_ITEMS(bh) - 1)
bd4c625c0   Linus Torvalds   reiserfs: run scr...
222
  			goto end;
098297b27   Jeff Mahoney   reiserfs: cleanup...
223
224
225
226
  		/*
  		 * item we went through is last item of node. Using right
  		 * delimiting key check is it directory end
  		 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
227
228
  		rkey = get_rkey(&path_to_entry, inode->i_sb);
  		if (!comp_le_keys(rkey, &MIN_KEY)) {
098297b27   Jeff Mahoney   reiserfs: cleanup...
229
230
231
232
  			/*
  			 * set pos_key to key, that is the smallest and greater
  			 * that key of the last entry in the item
  			 */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
233
234
235
  			set_cpu_key_k_offset(&pos_key, next_pos);
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

098297b27   Jeff Mahoney   reiserfs: cleanup...
237
  		/* end of directory has been reached */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
238
  		if (COMP_SHORT_KEYS(rkey, &pos_key)) {
bd4c625c0   Linus Torvalds   reiserfs: run scr...
239
  			goto end;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  		}
bd4c625c0   Linus Torvalds   reiserfs: run scr...
241
242
243
244
245
246
  
  		/* directory continues in the right neighboring block */
  		set_cpu_key_k_offset(&pos_key,
  				     le_key_k_offset(KEY_FORMAT_3_5, rkey));
  
  	}			/* while */
a41f1a471   Jeff Mahoney   reiserfs: use gen...
247
  end:
4acf381e1   Al Viro   [readdir] convert...
248
  	ctx->pos = next_pos;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
249
250
  	pathrelse(&path_to_entry);
  	reiserfs_check_path(&path_to_entry);
a41f1a471   Jeff Mahoney   reiserfs: use gen...
251
  out:
bd4c625c0   Linus Torvalds   reiserfs: run scr...
252
253
  	reiserfs_write_unlock(inode->i_sb);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  }
4acf381e1   Al Viro   [readdir] convert...
255
  static int reiserfs_readdir(struct file *file, struct dir_context *ctx)
a41f1a471   Jeff Mahoney   reiserfs: use gen...
256
  {
cd62cdae0   Al Viro   reiserfs: switch ...
257
  	return reiserfs_readdir_inode(file_inode(file), ctx);
a41f1a471   Jeff Mahoney   reiserfs: use gen...
258
  }
098297b27   Jeff Mahoney   reiserfs: cleanup...
259
260
261
262
  /*
   * compose directory item containing "." and ".." entries (entries are
   * not aligned to 4 byte boundary)
   */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
263
264
  void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
  			    __le32 par_dirid, __le32 par_objid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  {
16da167c1   Jeff Mahoney   reiserfs: cleanup...
266
  	struct reiserfs_de_head *dot, *dotdot;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
267
268
  
  	memset(body, 0, EMPTY_DIR_SIZE_V1);
16da167c1   Jeff Mahoney   reiserfs: cleanup...
269
270
  	dot = (struct reiserfs_de_head *)body;
  	dotdot = dot + 1;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
271
272
  
  	/* direntry header of "." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
273
  	put_deh_offset(dot, DOT_OFFSET);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
274
  	/* these two are from make_le_item_head, and are are LE */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
275
276
277
278
279
  	dot->deh_dir_id = dirid;
  	dot->deh_objectid = objid;
  	dot->deh_state = 0;	/* Endian safe if 0 */
  	put_deh_location(dot, EMPTY_DIR_SIZE_V1 - strlen("."));
  	mark_de_visible(dot);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
280
281
  
  	/* direntry header of ".." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
282
  	put_deh_offset(dotdot, DOT_DOT_OFFSET);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
283
284
  	/* key of ".." for the root directory */
  	/* these two are from the inode, and are are LE */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
285
286
287
288
289
  	dotdot->deh_dir_id = par_dirid;
  	dotdot->deh_objectid = par_objid;
  	dotdot->deh_state = 0;	/* Endian safe if 0 */
  	put_deh_location(dotdot, deh_location(dot) - strlen(".."));
  	mark_de_visible(dotdot);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
290
291
  
  	/* copy ".." and "." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
292
293
  	memcpy(body + deh_location(dot), ".", 1);
  	memcpy(body + deh_location(dotdot), "..", 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
296
  }
  
  /* compose directory item containing "." and ".." entries */
bd4c625c0   Linus Torvalds   reiserfs: run scr...
297
298
  void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
  			 __le32 par_dirid, __le32 par_objid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  {
16da167c1   Jeff Mahoney   reiserfs: cleanup...
300
  	struct reiserfs_de_head *dot, *dotdot;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
301
302
  
  	memset(body, 0, EMPTY_DIR_SIZE);
16da167c1   Jeff Mahoney   reiserfs: cleanup...
303
304
  	dot = (struct reiserfs_de_head *)body;
  	dotdot = dot + 1;
bd4c625c0   Linus Torvalds   reiserfs: run scr...
305
306
  
  	/* direntry header of "." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
307
  	put_deh_offset(dot, DOT_OFFSET);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
308
  	/* these two are from make_le_item_head, and are are LE */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
309
310
311
312
313
  	dot->deh_dir_id = dirid;
  	dot->deh_objectid = objid;
  	dot->deh_state = 0;	/* Endian safe if 0 */
  	put_deh_location(dot, EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
  	mark_de_visible(dot);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
314
315
  
  	/* direntry header of ".." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
316
  	put_deh_offset(dotdot, DOT_DOT_OFFSET);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
317
318
  	/* key of ".." for the root directory */
  	/* these two are from the inode, and are are LE */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
319
320
321
322
323
  	dotdot->deh_dir_id = par_dirid;
  	dotdot->deh_objectid = par_objid;
  	dotdot->deh_state = 0;	/* Endian safe if 0 */
  	put_deh_location(dotdot, deh_location(dot) - ROUND_UP(strlen("..")));
  	mark_de_visible(dotdot);
bd4c625c0   Linus Torvalds   reiserfs: run scr...
324
325
  
  	/* copy ".." and "." */
16da167c1   Jeff Mahoney   reiserfs: cleanup...
326
327
  	memcpy(body + deh_location(dot), ".", 1);
  	memcpy(body + deh_location(dotdot), "..", 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
  }