Blame view

fs/nilfs2/dir.c 17.4 KB
2ba466d74   Yoshiji Amagai   nilfs2: directory...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  /*
   * dir.c - NILFS directory entry operations
   *
   * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   *
   * Modified for NILFS by Amagai Yoshiji <amagai@osrg.net>
   */
  /*
   *  linux/fs/ext2/dir.c
   *
   * 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
   *
   *  ext2 directory handling functions
   *
   *  Big-endian to little-endian byte-swapping/bitmaps by
   *        David S. Miller (davem@caip.rutgers.edu), 1995
   *
   * All code that works with directory layout had been switched to pagecache
   * and moved here. AV
   */
  
  #include <linux/pagemap.h>
2ba466d74   Yoshiji Amagai   nilfs2: directory...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  #include "nilfs.h"
  #include "page.h"
  
  /*
   * nilfs uses block-sized chunks. Arguably, sector-sized ones would be
   * more robust, but we have what we have
   */
  static inline unsigned nilfs_chunk_size(struct inode *inode)
  {
  	return inode->i_sb->s_blocksize;
  }
  
  static inline void nilfs_put_page(struct page *page)
  {
  	kunmap(page);
  	page_cache_release(page);
  }
  
  static inline unsigned long dir_pages(struct inode *inode)
  {
  	return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
  }
  
  /*
   * Return the offset into page `page_nr' of the last valid
   * byte in that page, plus one.
   */
  static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr)
  {
  	unsigned last_byte = inode->i_size;
  
  	last_byte -= page_nr << PAGE_CACHE_SHIFT;
  	if (last_byte > PAGE_CACHE_SIZE)
  		last_byte = PAGE_CACHE_SIZE;
  	return last_byte;
  }
f4e420dc4   Christoph Hellwig   clean up write_be...
82
  static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to)
2ba466d74   Yoshiji Amagai   nilfs2: directory...
83
84
  {
  	loff_t pos = page_offset(page) + from;
6e1db88d5   Christoph Hellwig   introduce __block...
85
  	return __block_write_begin(page, pos, to - from, nilfs_get_block);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
86
  }
2093abf9c   Jiro SEKIBA   nilfs2: change re...
87
88
89
  static void nilfs_commit_chunk(struct page *page,
  			       struct address_space *mapping,
  			       unsigned from, unsigned to)
2ba466d74   Yoshiji Amagai   nilfs2: directory...
90
91
  {
  	struct inode *dir = mapping->host;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
92
93
94
95
96
97
98
  	loff_t pos = page_offset(page) + from;
  	unsigned len = to - from;
  	unsigned nr_dirty, copied;
  	int err;
  
  	nr_dirty = nilfs_page_count_clean_buffers(page, from, to);
  	copied = block_write_end(NULL, mapping, pos, len, len, page, NULL);
58d55471c   Jiro SEKIBA   nilfs2: delete ma...
99
  	if (pos + copied > dir->i_size)
2ba466d74   Yoshiji Amagai   nilfs2: directory...
100
  		i_size_write(dir, pos + copied);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
101
102
  	if (IS_DIRSYNC(dir))
  		nilfs_set_transaction_flag(NILFS_TI_SYNC);
bcbc8c648   Ryusuke Konishi   nilfs2: do not pa...
103
  	err = nilfs_set_file_dirty(dir, nr_dirty);
2093abf9c   Jiro SEKIBA   nilfs2: change re...
104
  	WARN_ON(err); /* do not happen */
2ba466d74   Yoshiji Amagai   nilfs2: directory...
105
  	unlock_page(page);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  }
  
  static void nilfs_check_page(struct page *page)
  {
  	struct inode *dir = page->mapping->host;
  	struct super_block *sb = dir->i_sb;
  	unsigned chunk_size = nilfs_chunk_size(dir);
  	char *kaddr = page_address(page);
  	unsigned offs, rec_len;
  	unsigned limit = PAGE_CACHE_SIZE;
  	struct nilfs_dir_entry *p;
  	char *error;
  
  	if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
  		limit = dir->i_size & ~PAGE_CACHE_MASK;
  		if (limit & (chunk_size - 1))
  			goto Ebadsize;
  		if (!limit)
  			goto out;
  	}
  	for (offs = 0; offs <= limit - NILFS_DIR_REC_LEN(1); offs += rec_len) {
  		p = (struct nilfs_dir_entry *)(kaddr + offs);
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
128
  		rec_len = nilfs_rec_len_from_disk(p->rec_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  
  		if (rec_len < NILFS_DIR_REC_LEN(1))
  			goto Eshort;
  		if (rec_len & 3)
  			goto Ealign;
  		if (rec_len < NILFS_DIR_REC_LEN(p->name_len))
  			goto Enamelen;
  		if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
  			goto Espan;
  	}
  	if (offs != limit)
  		goto Eend;
  out:
  	SetPageChecked(page);
  	return;
  
  	/* Too bad, we had an error */
  
  Ebadsize:
  	nilfs_error(sb, "nilfs_check_page",
  		    "size of directory #%lu is not a multiple of chunk size",
  		    dir->i_ino
  	);
  	goto fail;
  Eshort:
  	error = "rec_len is smaller than minimal";
  	goto bad_entry;
  Ealign:
  	error = "unaligned directory entry";
  	goto bad_entry;
  Enamelen:
  	error = "rec_len is too small for name_len";
  	goto bad_entry;
  Espan:
  	error = "directory entry across blocks";
  bad_entry:
  	nilfs_error(sb, "nilfs_check_page", "bad entry in directory #%lu: %s - "
  		    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
  		    dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
  		    (unsigned long) le64_to_cpu(p->inode),
  		    rec_len, p->name_len);
  	goto fail;
  Eend:
  	p = (struct nilfs_dir_entry *)(kaddr + offs);
  	nilfs_error(sb, "nilfs_check_page",
  		    "entry in directory #%lu spans the page boundary"
  		    "offset=%lu, inode=%lu",
  		    dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
  		    (unsigned long) le64_to_cpu(p->inode));
  fail:
  	SetPageChecked(page);
  	SetPageError(page);
  }
  
  static struct page *nilfs_get_page(struct inode *dir, unsigned long n)
  {
  	struct address_space *mapping = dir->i_mapping;
c28e69d93   Ryusuke Konishi   nilfs2: simplify ...
186
  	struct page *page = read_mapping_page(mapping, n, NULL);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
187
  	if (!IS_ERR(page)) {
2ba466d74   Yoshiji Amagai   nilfs2: directory...
188
  		kmap(page);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  		if (!PageChecked(page))
  			nilfs_check_page(page);
  		if (PageError(page))
  			goto fail;
  	}
  	return page;
  
  fail:
  	nilfs_put_page(page);
  	return ERR_PTR(-EIO);
  }
  
  /*
   * NOTE! unlike strncmp, nilfs_match returns 1 for success, 0 for failure.
   *
   * len <= NILFS_NAME_LEN and de != NULL are guaranteed by caller.
   */
  static int
072f98b46   Al Viro   nilfs: sanitize c...
207
  nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de)
2ba466d74   Yoshiji Amagai   nilfs2: directory...
208
209
210
211
212
213
214
215
216
217
218
219
220
  {
  	if (len != de->name_len)
  		return 0;
  	if (!de->inode)
  		return 0;
  	return !memcmp(name, de->name, len);
  }
  
  /*
   * p is at least 6 bytes before the end of page
   */
  static struct nilfs_dir_entry *nilfs_next_entry(struct nilfs_dir_entry *p)
  {
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
221
222
  	return (struct nilfs_dir_entry *)((char *)p +
  					  nilfs_rec_len_from_disk(p->rec_len));
2ba466d74   Yoshiji Amagai   nilfs2: directory...
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  }
  
  static unsigned char
  nilfs_filetype_table[NILFS_FT_MAX] = {
  	[NILFS_FT_UNKNOWN]	= DT_UNKNOWN,
  	[NILFS_FT_REG_FILE]	= DT_REG,
  	[NILFS_FT_DIR]		= DT_DIR,
  	[NILFS_FT_CHRDEV]	= DT_CHR,
  	[NILFS_FT_BLKDEV]	= DT_BLK,
  	[NILFS_FT_FIFO]		= DT_FIFO,
  	[NILFS_FT_SOCK]		= DT_SOCK,
  	[NILFS_FT_SYMLINK]	= DT_LNK,
  };
  
  #define S_SHIFT 12
  static unsigned char
  nilfs_type_by_mode[S_IFMT >> S_SHIFT] = {
  	[S_IFREG >> S_SHIFT]	= NILFS_FT_REG_FILE,
  	[S_IFDIR >> S_SHIFT]	= NILFS_FT_DIR,
  	[S_IFCHR >> S_SHIFT]	= NILFS_FT_CHRDEV,
  	[S_IFBLK >> S_SHIFT]	= NILFS_FT_BLKDEV,
  	[S_IFIFO >> S_SHIFT]	= NILFS_FT_FIFO,
  	[S_IFSOCK >> S_SHIFT]	= NILFS_FT_SOCK,
  	[S_IFLNK >> S_SHIFT]	= NILFS_FT_SYMLINK,
  };
  
  static void nilfs_set_de_type(struct nilfs_dir_entry *de, struct inode *inode)
  {
c6e49e3f2   Al Viro   nilfs: propagate ...
251
  	umode_t mode = inode->i_mode;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
252
253
254
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
283
284
285
286
287
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
  
  	de->file_type = nilfs_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
  }
  
  static int nilfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
  	loff_t pos = filp->f_pos;
  	struct inode *inode = filp->f_dentry->d_inode;
  	struct super_block *sb = inode->i_sb;
  	unsigned int offset = pos & ~PAGE_CACHE_MASK;
  	unsigned long n = pos >> PAGE_CACHE_SHIFT;
  	unsigned long npages = dir_pages(inode);
  /*	unsigned chunk_mask = ~(nilfs_chunk_size(inode)-1); */
  	unsigned char *types = NULL;
  	int ret;
  
  	if (pos > inode->i_size - NILFS_DIR_REC_LEN(1))
  		goto success;
  
  	types = nilfs_filetype_table;
  
  	for ( ; n < npages; n++, offset = 0) {
  		char *kaddr, *limit;
  		struct nilfs_dir_entry *de;
  		struct page *page = nilfs_get_page(inode, n);
  
  		if (IS_ERR(page)) {
  			nilfs_error(sb, __func__, "bad page in #%lu",
  				    inode->i_ino);
  			filp->f_pos += PAGE_CACHE_SIZE - offset;
  			ret = -EIO;
  			goto done;
  		}
  		kaddr = page_address(page);
  		de = (struct nilfs_dir_entry *)(kaddr + offset);
  		limit = kaddr + nilfs_last_byte(inode, n) -
  			NILFS_DIR_REC_LEN(1);
  		for ( ; (char *)de <= limit; de = nilfs_next_entry(de)) {
  			if (de->rec_len == 0) {
  				nilfs_error(sb, __func__,
  					    "zero-length directory entry");
  				ret = -EIO;
  				nilfs_put_page(page);
  				goto done;
  			}
  			if (de->inode) {
  				int over;
  				unsigned char d_type = DT_UNKNOWN;
  
  				if (types && de->file_type < NILFS_FT_MAX)
  					d_type = types[de->file_type];
  
  				offset = (char *)de - kaddr;
  				over = filldir(dirent, de->name, de->name_len,
  						(n<<PAGE_CACHE_SHIFT) | offset,
  						le64_to_cpu(de->inode), d_type);
  				if (over) {
  					nilfs_put_page(page);
  					goto success;
  				}
  			}
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
313
  			filp->f_pos += nilfs_rec_len_from_disk(de->rec_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
  		}
  		nilfs_put_page(page);
  	}
  
  success:
  	ret = 0;
  done:
  	return ret;
  }
  
  /*
   *	nilfs_find_entry()
   *
   * finds an entry in the specified directory with the wanted name. It
   * returns the page in which the entry was found, and the entry itself
   * (as a parameter - res_dir). Page is returned mapped and unlocked.
   * Entry is guaranteed to be valid.
   */
  struct nilfs_dir_entry *
0319003d0   Al Viro   nilfs really shou...
333
  nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
2ba466d74   Yoshiji Amagai   nilfs2: directory...
334
335
  		 struct page **res_page)
  {
0319003d0   Al Viro   nilfs really shou...
336
337
  	const unsigned char *name = qstr->name;
  	int namelen = qstr->len;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  	unsigned reclen = NILFS_DIR_REC_LEN(namelen);
  	unsigned long start, n;
  	unsigned long npages = dir_pages(dir);
  	struct page *page = NULL;
  	struct nilfs_inode_info *ei = NILFS_I(dir);
  	struct nilfs_dir_entry *de;
  
  	if (npages == 0)
  		goto out;
  
  	/* OFFSET_CACHE */
  	*res_page = NULL;
  
  	start = ei->i_dir_start_lookup;
  	if (start >= npages)
  		start = 0;
  	n = start;
  	do {
  		char *kaddr;
  		page = nilfs_get_page(dir, n);
  		if (!IS_ERR(page)) {
  			kaddr = page_address(page);
  			de = (struct nilfs_dir_entry *)kaddr;
  			kaddr += nilfs_last_byte(dir, n) - reclen;
  			while ((char *) de <= kaddr) {
  				if (de->rec_len == 0) {
  					nilfs_error(dir->i_sb, __func__,
  						"zero-length directory entry");
  					nilfs_put_page(page);
  					goto out;
  				}
  				if (nilfs_match(namelen, name, de))
  					goto found;
  				de = nilfs_next_entry(de);
  			}
  			nilfs_put_page(page);
  		}
  		if (++n >= npages)
  			n = 0;
  		/* next page is past the blocks we've got */
  		if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) {
  			nilfs_error(dir->i_sb, __func__,
1621562b6   Ryusuke Konishi   nilfs2: fix typo ...
380
  			       "dir %lu size %lld exceeds block count %llu",
2ba466d74   Yoshiji Amagai   nilfs2: directory...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  			       dir->i_ino, dir->i_size,
  			       (unsigned long long)dir->i_blocks);
  			goto out;
  		}
  	} while (n != start);
  out:
  	return NULL;
  
  found:
  	*res_page = page;
  	ei->i_dir_start_lookup = n;
  	return de;
  }
  
  struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p)
  {
  	struct page *page = nilfs_get_page(dir, 0);
  	struct nilfs_dir_entry *de = NULL;
  
  	if (!IS_ERR(page)) {
  		de = nilfs_next_entry(
  			(struct nilfs_dir_entry *)page_address(page));
  		*p = page;
  	}
  	return de;
  }
0319003d0   Al Viro   nilfs really shou...
407
  ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr)
2ba466d74   Yoshiji Amagai   nilfs2: directory...
408
409
410
411
  {
  	ino_t res = 0;
  	struct nilfs_dir_entry *de;
  	struct page *page;
0319003d0   Al Viro   nilfs really shou...
412
  	de = nilfs_find_entry(dir, qstr, &page);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
413
414
415
416
417
418
419
420
421
422
423
424
425
  	if (de) {
  		res = le64_to_cpu(de->inode);
  		kunmap(page);
  		page_cache_release(page);
  	}
  	return res;
  }
  
  /* Releases the page */
  void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
  		    struct page *page, struct inode *inode)
  {
  	unsigned from = (char *) de - (char *) page_address(page);
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
426
  	unsigned to = from + nilfs_rec_len_from_disk(de->rec_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
427
428
429
430
  	struct address_space *mapping = page->mapping;
  	int err;
  
  	lock_page(page);
f4e420dc4   Christoph Hellwig   clean up write_be...
431
  	err = nilfs_prepare_chunk(page, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
432
433
434
  	BUG_ON(err);
  	de->inode = cpu_to_le64(inode->i_ino);
  	nilfs_set_de_type(de, inode);
2093abf9c   Jiro SEKIBA   nilfs2: change re...
435
  	nilfs_commit_chunk(page, mapping, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
436
437
  	nilfs_put_page(page);
  	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
438
439
440
441
442
443
444
445
  }
  
  /*
   *	Parent is locked.
   */
  int nilfs_add_link(struct dentry *dentry, struct inode *inode)
  {
  	struct inode *dir = dentry->d_parent->d_inode;
072f98b46   Al Viro   nilfs: sanitize c...
446
  	const unsigned char *name = dentry->d_name.name;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  	int namelen = dentry->d_name.len;
  	unsigned chunk_size = nilfs_chunk_size(dir);
  	unsigned reclen = NILFS_DIR_REC_LEN(namelen);
  	unsigned short rec_len, name_len;
  	struct page *page = NULL;
  	struct nilfs_dir_entry *de;
  	unsigned long npages = dir_pages(dir);
  	unsigned long n;
  	char *kaddr;
  	unsigned from, to;
  	int err;
  
  	/*
  	 * We take care of directory expansion in the same loop.
  	 * This code plays outside i_size, so it locks the page
  	 * to protect that region.
  	 */
  	for (n = 0; n <= npages; n++) {
  		char *dir_end;
  
  		page = nilfs_get_page(dir, n);
  		err = PTR_ERR(page);
  		if (IS_ERR(page))
  			goto out;
  		lock_page(page);
  		kaddr = page_address(page);
  		dir_end = kaddr + nilfs_last_byte(dir, n);
  		de = (struct nilfs_dir_entry *)kaddr;
  		kaddr += PAGE_CACHE_SIZE - reclen;
  		while ((char *)de <= kaddr) {
  			if ((char *)de == dir_end) {
  				/* We hit i_size */
  				name_len = 0;
  				rec_len = chunk_size;
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
481
  				de->rec_len = nilfs_rec_len_to_disk(chunk_size);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
482
483
484
485
486
487
488
489
490
491
492
493
494
  				de->inode = 0;
  				goto got_it;
  			}
  			if (de->rec_len == 0) {
  				nilfs_error(dir->i_sb, __func__,
  					    "zero-length directory entry");
  				err = -EIO;
  				goto out_unlock;
  			}
  			err = -EEXIST;
  			if (nilfs_match(namelen, name, de))
  				goto out_unlock;
  			name_len = NILFS_DIR_REC_LEN(de->name_len);
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
495
  			rec_len = nilfs_rec_len_from_disk(de->rec_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  			if (!de->inode && rec_len >= reclen)
  				goto got_it;
  			if (rec_len >= name_len + reclen)
  				goto got_it;
  			de = (struct nilfs_dir_entry *)((char *)de + rec_len);
  		}
  		unlock_page(page);
  		nilfs_put_page(page);
  	}
  	BUG();
  	return -EINVAL;
  
  got_it:
  	from = (char *)de - (char *)page_address(page);
  	to = from + rec_len;
f4e420dc4   Christoph Hellwig   clean up write_be...
511
  	err = nilfs_prepare_chunk(page, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
512
513
514
515
516
517
  	if (err)
  		goto out_unlock;
  	if (de->inode) {
  		struct nilfs_dir_entry *de1;
  
  		de1 = (struct nilfs_dir_entry *)((char *)de + name_len);
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
518
519
  		de1->rec_len = nilfs_rec_len_to_disk(rec_len - name_len);
  		de->rec_len = nilfs_rec_len_to_disk(name_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
520
521
522
523
524
525
  		de = de1;
  	}
  	de->name_len = namelen;
  	memcpy(de->name, name, namelen);
  	de->inode = cpu_to_le64(inode->i_ino);
  	nilfs_set_de_type(de, inode);
2093abf9c   Jiro SEKIBA   nilfs2: change re...
526
  	nilfs_commit_chunk(page, page->mapping, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
527
  	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
abdb318b7   Jiro SEKIBA   nilfs2: replace m...
528
  	nilfs_mark_inode_dirty(dir);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
  	/* OFFSET_CACHE */
  out_put:
  	nilfs_put_page(page);
  out:
  	return err;
  out_unlock:
  	unlock_page(page);
  	goto out_put;
  }
  
  /*
   * nilfs_delete_entry deletes a directory entry by merging it with the
   * previous entry. Page is up-to-date. Releases the page.
   */
  int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
  {
  	struct address_space *mapping = page->mapping;
  	struct inode *inode = mapping->host;
  	char *kaddr = page_address(page);
  	unsigned from = ((char *)dir - kaddr) & ~(nilfs_chunk_size(inode) - 1);
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
549
550
  	unsigned to = ((char *)dir - kaddr) +
  		nilfs_rec_len_from_disk(dir->rec_len);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  	struct nilfs_dir_entry *pde = NULL;
  	struct nilfs_dir_entry *de = (struct nilfs_dir_entry *)(kaddr + from);
  	int err;
  
  	while ((char *)de < (char *)dir) {
  		if (de->rec_len == 0) {
  			nilfs_error(inode->i_sb, __func__,
  				    "zero-length directory entry");
  			err = -EIO;
  			goto out;
  		}
  		pde = de;
  		de = nilfs_next_entry(de);
  	}
  	if (pde)
  		from = (char *)pde - (char *)page_address(page);
  	lock_page(page);
f4e420dc4   Christoph Hellwig   clean up write_be...
568
  	err = nilfs_prepare_chunk(page, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
569
570
  	BUG_ON(err);
  	if (pde)
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
571
  		pde->rec_len = nilfs_rec_len_to_disk(to - from);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
572
  	dir->inode = 0;
2093abf9c   Jiro SEKIBA   nilfs2: change re...
573
  	nilfs_commit_chunk(page, mapping, from, to);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
574
  	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
2ba466d74   Yoshiji Amagai   nilfs2: directory...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  out:
  	nilfs_put_page(page);
  	return err;
  }
  
  /*
   * Set the first fragment of directory.
   */
  int nilfs_make_empty(struct inode *inode, struct inode *parent)
  {
  	struct address_space *mapping = inode->i_mapping;
  	struct page *page = grab_cache_page(mapping, 0);
  	unsigned chunk_size = nilfs_chunk_size(inode);
  	struct nilfs_dir_entry *de;
  	int err;
  	void *kaddr;
  
  	if (!page)
  		return -ENOMEM;
f4e420dc4   Christoph Hellwig   clean up write_be...
594
  	err = nilfs_prepare_chunk(page, 0, chunk_size);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
595
596
597
598
599
600
601
602
  	if (unlikely(err)) {
  		unlock_page(page);
  		goto fail;
  	}
  	kaddr = kmap_atomic(page, KM_USER0);
  	memset(kaddr, 0, chunk_size);
  	de = (struct nilfs_dir_entry *)kaddr;
  	de->name_len = 1;
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
603
  	de->rec_len = nilfs_rec_len_to_disk(NILFS_DIR_REC_LEN(1));
2ba466d74   Yoshiji Amagai   nilfs2: directory...
604
605
606
607
608
609
  	memcpy(de->name, ".\0\0", 4);
  	de->inode = cpu_to_le64(inode->i_ino);
  	nilfs_set_de_type(de, inode);
  
  	de = (struct nilfs_dir_entry *)(kaddr + NILFS_DIR_REC_LEN(1));
  	de->name_len = 2;
6cda9fa25   Ryusuke Konishi   nilfs2: avoid rec...
610
  	de->rec_len = nilfs_rec_len_to_disk(chunk_size - NILFS_DIR_REC_LEN(1));
2ba466d74   Yoshiji Amagai   nilfs2: directory...
611
612
613
614
  	de->inode = cpu_to_le64(parent->i_ino);
  	memcpy(de->name, "..\0", 4);
  	nilfs_set_de_type(de, inode);
  	kunmap_atomic(kaddr, KM_USER0);
2093abf9c   Jiro SEKIBA   nilfs2: change re...
615
  	nilfs_commit_chunk(page, mapping, 0, chunk_size);
2ba466d74   Yoshiji Amagai   nilfs2: directory...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
  fail:
  	page_cache_release(page);
  	return err;
  }
  
  /*
   * routine to check that the specified directory is empty (for rmdir)
   */
  int nilfs_empty_dir(struct inode *inode)
  {
  	struct page *page = NULL;
  	unsigned long i, npages = dir_pages(inode);
  
  	for (i = 0; i < npages; i++) {
  		char *kaddr;
  		struct nilfs_dir_entry *de;
  
  		page = nilfs_get_page(inode, i);
  		if (IS_ERR(page))
  			continue;
  
  		kaddr = page_address(page);
  		de = (struct nilfs_dir_entry *)kaddr;
  		kaddr += nilfs_last_byte(inode, i) - NILFS_DIR_REC_LEN(1);
  
  		while ((char *)de <= kaddr) {
  			if (de->rec_len == 0) {
  				nilfs_error(inode->i_sb, __func__,
  					    "zero-length directory entry "
  					    "(kaddr=%p, de=%p)
  ", kaddr, de);
  				goto not_empty;
  			}
  			if (de->inode != 0) {
  				/* check for . and .. */
  				if (de->name[0] != '.')
  					goto not_empty;
  				if (de->name_len > 2)
  					goto not_empty;
  				if (de->name_len < 2) {
  					if (de->inode !=
  					    cpu_to_le64(inode->i_ino))
  						goto not_empty;
  				} else if (de->name[1] != '.')
  					goto not_empty;
  			}
  			de = nilfs_next_entry(de);
  		}
  		nilfs_put_page(page);
  	}
  	return 1;
  
  not_empty:
  	nilfs_put_page(page);
  	return 0;
  }
828c09509   Alexey Dobriyan   const: constify r...
672
  const struct file_operations nilfs_dir_operations = {
2ba466d74   Yoshiji Amagai   nilfs2: directory...
673
674
675
  	.llseek		= generic_file_llseek,
  	.read		= generic_read_dir,
  	.readdir	= nilfs_readdir,
7a9461939   Ryusuke Konishi   nilfs2: use unloc...
676
  	.unlocked_ioctl	= nilfs_ioctl,
2ba466d74   Yoshiji Amagai   nilfs2: directory...
677
  #ifdef CONFIG_COMPAT
828b1c50a   Ryusuke Konishi   nilfs2: add compa...
678
  	.compat_ioctl	= nilfs_compat_ioctl,
2ba466d74   Yoshiji Amagai   nilfs2: directory...
679
680
681
682
  #endif	/* CONFIG_COMPAT */
  	.fsync		= nilfs_sync_file,
  
  };