Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dir.c
Go to the documentation of this file.
1 /*
2  * OMFS (as used by RIO Karma) directory operations.
3  * Copyright (C) 2005 Bob Copeland <[email protected]>
4  * Released under GPL v2.
5  */
6 
7 #include <linux/fs.h>
8 #include <linux/ctype.h>
9 #include <linux/buffer_head.h>
10 #include "omfs.h"
11 
12 static int omfs_hash(const char *name, int namelen, int mod)
13 {
14  int i, hash = 0;
15  for (i = 0; i < namelen; i++)
16  hash ^= tolower(name[i]) << (i % 24);
17  return hash % mod;
18 }
19 
20 /*
21  * Finds the bucket for a given name and reads the containing block;
22  * *ofs is set to the offset of the first list entry.
23  */
24 static struct buffer_head *omfs_get_bucket(struct inode *dir,
25  const char *name, int namelen, int *ofs)
26 {
27  int nbuckets = (dir->i_size - OMFS_DIR_START)/8;
28  int bucket = omfs_hash(name, namelen, nbuckets);
29 
30  *ofs = OMFS_DIR_START + bucket * 8;
31  return omfs_bread(dir->i_sb, dir->i_ino);
32 }
33 
34 static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block,
35  const char *name, int namelen,
36  u64 *prev_block)
37 {
38  struct buffer_head *bh;
39  struct omfs_inode *oi;
40  int err = -ENOENT;
41  *prev_block = ~0;
42 
43  while (block != ~0) {
44  bh = omfs_bread(dir->i_sb, block);
45  if (!bh) {
46  err = -EIO;
47  goto err;
48  }
49 
50  oi = (struct omfs_inode *) bh->b_data;
51  if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) {
52  brelse(bh);
53  goto err;
54  }
55 
56  if (strncmp(oi->i_name, name, namelen) == 0)
57  return bh;
58 
59  *prev_block = block;
60  block = be64_to_cpu(oi->i_sibling);
61  brelse(bh);
62  }
63 err:
64  return ERR_PTR(err);
65 }
66 
67 static struct buffer_head *omfs_find_entry(struct inode *dir,
68  const char *name, int namelen)
69 {
70  struct buffer_head *bh;
71  int ofs;
72  u64 block, dummy;
73 
74  bh = omfs_get_bucket(dir, name, namelen, &ofs);
75  if (!bh)
76  return ERR_PTR(-EIO);
77 
78  block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs]));
79  brelse(bh);
80 
81  return omfs_scan_list(dir, block, name, namelen, &dummy);
82 }
83 
84 int omfs_make_empty(struct inode *inode, struct super_block *sb)
85 {
86  struct omfs_sb_info *sbi = OMFS_SB(sb);
87  struct buffer_head *bh;
88  struct omfs_inode *oi;
89 
90  bh = omfs_bread(sb, inode->i_ino);
91  if (!bh)
92  return -ENOMEM;
93 
94  memset(bh->b_data, 0, sizeof(struct omfs_inode));
95 
96  if (S_ISDIR(inode->i_mode)) {
97  memset(&bh->b_data[OMFS_DIR_START], 0xff,
99  } else
101 
102  oi = (struct omfs_inode *) bh->b_data;
103  oi->i_head.h_self = cpu_to_be64(inode->i_ino);
104  oi->i_sibling = ~cpu_to_be64(0ULL);
105 
106  mark_buffer_dirty(bh);
107  brelse(bh);
108  return 0;
109 }
110 
111 static int omfs_add_link(struct dentry *dentry, struct inode *inode)
112 {
113  struct inode *dir = dentry->d_parent->d_inode;
114  const char *name = dentry->d_name.name;
115  int namelen = dentry->d_name.len;
116  struct omfs_inode *oi;
117  struct buffer_head *bh;
118  u64 block;
119  __be64 *entry;
120  int ofs;
121 
122  /* just prepend to head of queue in proper bucket */
123  bh = omfs_get_bucket(dir, name, namelen, &ofs);
124  if (!bh)
125  goto out;
126 
127  entry = (__be64 *) &bh->b_data[ofs];
128  block = be64_to_cpu(*entry);
129  *entry = cpu_to_be64(inode->i_ino);
130  mark_buffer_dirty(bh);
131  brelse(bh);
132 
133  /* now set the sibling and parent pointers on the new inode */
134  bh = omfs_bread(dir->i_sb, inode->i_ino);
135  if (!bh)
136  goto out;
137 
138  oi = (struct omfs_inode *) bh->b_data;
139  memcpy(oi->i_name, name, namelen);
140  memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen);
141  oi->i_sibling = cpu_to_be64(block);
142  oi->i_parent = cpu_to_be64(dir->i_ino);
143  mark_buffer_dirty(bh);
144  brelse(bh);
145 
146  dir->i_ctime = CURRENT_TIME_SEC;
147 
148  /* mark affected inodes dirty to rebuild checksums */
149  mark_inode_dirty(dir);
150  mark_inode_dirty(inode);
151  return 0;
152 out:
153  return -ENOMEM;
154 }
155 
156 static int omfs_delete_entry(struct dentry *dentry)
157 {
158  struct inode *dir = dentry->d_parent->d_inode;
159  struct inode *dirty;
160  const char *name = dentry->d_name.name;
161  int namelen = dentry->d_name.len;
162  struct omfs_inode *oi;
163  struct buffer_head *bh, *bh2;
164  __be64 *entry, next;
165  u64 block, prev;
166  int ofs;
167  int err = -ENOMEM;
168 
169  /* delete the proper node in the bucket's linked list */
170  bh = omfs_get_bucket(dir, name, namelen, &ofs);
171  if (!bh)
172  goto out;
173 
174  entry = (__be64 *) &bh->b_data[ofs];
175  block = be64_to_cpu(*entry);
176 
177  bh2 = omfs_scan_list(dir, block, name, namelen, &prev);
178  if (IS_ERR(bh2)) {
179  err = PTR_ERR(bh2);
180  goto out_free_bh;
181  }
182 
183  oi = (struct omfs_inode *) bh2->b_data;
184  next = oi->i_sibling;
185  brelse(bh2);
186 
187  if (prev != ~0) {
188  /* found in middle of list, get list ptr */
189  brelse(bh);
190  bh = omfs_bread(dir->i_sb, prev);
191  if (!bh)
192  goto out;
193 
194  oi = (struct omfs_inode *) bh->b_data;
195  entry = &oi->i_sibling;
196  }
197 
198  *entry = next;
199  mark_buffer_dirty(bh);
200 
201  if (prev != ~0) {
202  dirty = omfs_iget(dir->i_sb, prev);
203  if (!IS_ERR(dirty)) {
204  mark_inode_dirty(dirty);
205  iput(dirty);
206  }
207  }
208 
209  err = 0;
210 out_free_bh:
211  brelse(bh);
212 out:
213  return err;
214 }
215 
216 static int omfs_dir_is_empty(struct inode *inode)
217 {
218  int nbuckets = (inode->i_size - OMFS_DIR_START) / 8;
219  struct buffer_head *bh;
220  u64 *ptr;
221  int i;
222 
223  bh = omfs_bread(inode->i_sb, inode->i_ino);
224 
225  if (!bh)
226  return 0;
227 
228  ptr = (u64 *) &bh->b_data[OMFS_DIR_START];
229 
230  for (i = 0; i < nbuckets; i++, ptr++)
231  if (*ptr != ~0)
232  break;
233 
234  brelse(bh);
235  return *ptr != ~0;
236 }
237 
238 static int omfs_remove(struct inode *dir, struct dentry *dentry)
239 {
240  struct inode *inode = dentry->d_inode;
241  int ret;
242 
243 
244  if (S_ISDIR(inode->i_mode) &&
245  !omfs_dir_is_empty(inode))
246  return -ENOTEMPTY;
247 
248  ret = omfs_delete_entry(dentry);
249  if (ret)
250  return ret;
251 
252  clear_nlink(inode);
253  mark_inode_dirty(inode);
254  mark_inode_dirty(dir);
255  return 0;
256 }
257 
258 static int omfs_add_node(struct inode *dir, struct dentry *dentry, umode_t mode)
259 {
260  int err;
261  struct inode *inode = omfs_new_inode(dir, mode);
262 
263  if (IS_ERR(inode))
264  return PTR_ERR(inode);
265 
266  err = omfs_make_empty(inode, dir->i_sb);
267  if (err)
268  goto out_free_inode;
269 
270  err = omfs_add_link(dentry, inode);
271  if (err)
272  goto out_free_inode;
273 
274  d_instantiate(dentry, inode);
275  return 0;
276 
277 out_free_inode:
278  iput(inode);
279  return err;
280 }
281 
282 static int omfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
283 {
284  return omfs_add_node(dir, dentry, mode | S_IFDIR);
285 }
286 
287 static int omfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
288  bool excl)
289 {
290  return omfs_add_node(dir, dentry, mode | S_IFREG);
291 }
292 
293 static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry,
294  unsigned int flags)
295 {
296  struct buffer_head *bh;
297  struct inode *inode = NULL;
298 
299  if (dentry->d_name.len > OMFS_NAMELEN)
300  return ERR_PTR(-ENAMETOOLONG);
301 
302  bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len);
303  if (!IS_ERR(bh)) {
304  struct omfs_inode *oi = (struct omfs_inode *)bh->b_data;
305  ino_t ino = be64_to_cpu(oi->i_head.h_self);
306  brelse(bh);
307  inode = omfs_iget(dir->i_sb, ino);
308  if (IS_ERR(inode))
309  return ERR_CAST(inode);
310  }
311  d_add(dentry, inode);
312  return NULL;
313 }
314 
315 /* sanity check block's self pointer */
316 int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header,
317  u64 fsblock)
318 {
319  int is_bad;
320  u64 ino = be64_to_cpu(header->h_self);
321  is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) ||
322  (ino > sbi->s_num_blocks));
323 
324  if (is_bad)
325  printk(KERN_WARNING "omfs: bad hash chain detected\n");
326 
327  return is_bad;
328 }
329 
330 static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir,
331  u64 fsblock, int hindex)
332 {
333  struct inode *dir = filp->f_dentry->d_inode;
334  struct buffer_head *bh;
335  struct omfs_inode *oi;
336  u64 self;
337  int res = 0;
338  unsigned char d_type;
339 
340  /* follow chain in this bucket */
341  while (fsblock != ~0) {
342  bh = omfs_bread(dir->i_sb, fsblock);
343  if (!bh)
344  goto out;
345 
346  oi = (struct omfs_inode *) bh->b_data;
347  if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) {
348  brelse(bh);
349  goto out;
350  }
351 
352  self = fsblock;
353  fsblock = be64_to_cpu(oi->i_sibling);
354 
355  /* skip visited nodes */
356  if (hindex) {
357  hindex--;
358  brelse(bh);
359  continue;
360  }
361 
362  d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG;
363 
364  res = filldir(dirent, oi->i_name, strnlen(oi->i_name,
365  OMFS_NAMELEN), filp->f_pos, self, d_type);
366  brelse(bh);
367  if (res < 0)
368  break;
369  filp->f_pos++;
370  }
371 out:
372  return res;
373 }
374 
375 static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
376  struct inode *new_dir, struct dentry *new_dentry)
377 {
378  struct inode *new_inode = new_dentry->d_inode;
379  struct inode *old_inode = old_dentry->d_inode;
380  int err;
381 
382  if (new_inode) {
383  /* overwriting existing file/dir */
384  err = omfs_remove(new_dir, new_dentry);
385  if (err)
386  goto out;
387  }
388 
389  /* since omfs locates files by name, we need to unlink _before_
390  * adding the new link or we won't find the old one */
391  err = omfs_delete_entry(old_dentry);
392  if (err)
393  goto out;
394 
395  mark_inode_dirty(old_dir);
396  err = omfs_add_link(new_dentry, old_inode);
397  if (err)
398  goto out;
399 
400  old_inode->i_ctime = CURRENT_TIME_SEC;
401  mark_inode_dirty(old_inode);
402 out:
403  return err;
404 }
405 
406 static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
407 {
408  struct inode *dir = filp->f_dentry->d_inode;
409  struct buffer_head *bh;
410  loff_t offset, res;
411  unsigned int hchain, hindex;
412  int nbuckets;
413  u64 fsblock;
414  int ret = -EINVAL;
415 
416  if (filp->f_pos >> 32)
417  goto success;
418 
419  switch ((unsigned long) filp->f_pos) {
420  case 0:
421  if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0)
422  goto success;
423  filp->f_pos++;
424  /* fall through */
425  case 1:
426  if (filldir(dirent, "..", 2, 1,
427  parent_ino(filp->f_dentry), DT_DIR) < 0)
428  goto success;
429  filp->f_pos = 1 << 20;
430  /* fall through */
431  }
432 
433  nbuckets = (dir->i_size - OMFS_DIR_START) / 8;
434 
435  /* high 12 bits store bucket + 1 and low 20 bits store hash index */
436  hchain = (filp->f_pos >> 20) - 1;
437  hindex = filp->f_pos & 0xfffff;
438 
439  bh = omfs_bread(dir->i_sb, dir->i_ino);
440  if (!bh)
441  goto out;
442 
443  offset = OMFS_DIR_START + hchain * 8;
444 
445  for (; hchain < nbuckets; hchain++, offset += 8) {
446  fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset]));
447 
448  res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex);
449  hindex = 0;
450  if (res < 0)
451  break;
452 
453  filp->f_pos = (hchain+2) << 20;
454  }
455  brelse(bh);
456 success:
457  ret = 0;
458 out:
459  return ret;
460 }
461 
463  .lookup = omfs_lookup,
464  .mkdir = omfs_mkdir,
465  .rename = omfs_rename,
466  .create = omfs_create,
467  .unlink = omfs_remove,
468  .rmdir = omfs_remove,
469 };
470 
472  .read = generic_read_dir,
473  .readdir = omfs_readdir,
474  .llseek = generic_file_llseek,
475 };