Commit e6af00f1d1697ca41ab6a55307066ef3466833a9

Authored by Boaz Harrosh
1 parent beaec07ba6

exofs: dir_inode and directory operations

implementation of directory and inode operations.

* A directory is treated as a file, and essentially contains a list
  of <file name, inode #> pairs for files that are found in that
  directory. The object IDs correspond to the files' inode numbers
  and are allocated using a 64bit incrementing global counter.
* Each file's control block (AKA on-disk inode) is stored in its
  object's attributes. This applies to both regular files and other
  types (directories, device files, symlinks, etc.).

Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>

Showing 5 changed files with 1298 additions and 1 deletions Side-by-side Diff

... ... @@ -12,6 +12,6 @@
12 12 # Kbuild - Gets included from the Kernels Makefile and build system
13 13 #
14 14  
15   -exofs-y := osd.o inode.o file.o symlink.o
  15 +exofs-y := osd.o inode.o file.o symlink.o namei.o dir.o
16 16 obj-$(CONFIG_EXOFS_FS) += exofs.o
  1 +/*
  2 + * Copyright (C) 2005, 2006
  3 + * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
  4 + * Copyright (C) 2005, 2006
  5 + * International Business Machines
  6 + * Copyright (C) 2008, 2009
  7 + * Boaz Harrosh <bharrosh@panasas.com>
  8 + *
  9 + * Copyrights for code taken from ext2:
  10 + * Copyright (C) 1992, 1993, 1994, 1995
  11 + * Remy Card (card@masi.ibp.fr)
  12 + * Laboratoire MASI - Institut Blaise Pascal
  13 + * Universite Pierre et Marie Curie (Paris VI)
  14 + * from
  15 + * linux/fs/minix/inode.c
  16 + * Copyright (C) 1991, 1992 Linus Torvalds
  17 + *
  18 + * This file is part of exofs.
  19 + *
  20 + * exofs is free software; you can redistribute it and/or modify
  21 + * it under the terms of the GNU General Public License as published by
  22 + * the Free Software Foundation. Since it is based on ext2, and the only
  23 + * valid version of GPL for the Linux kernel is version 2, the only valid
  24 + * version of GPL for exofs is version 2.
  25 + *
  26 + * exofs is distributed in the hope that it will be useful,
  27 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29 + * GNU General Public License for more details.
  30 + *
  31 + * You should have received a copy of the GNU General Public License
  32 + * along with exofs; if not, write to the Free Software
  33 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  34 + */
  35 +
  36 +#include "exofs.h"
  37 +
  38 +static inline unsigned exofs_chunk_size(struct inode *inode)
  39 +{
  40 + return inode->i_sb->s_blocksize;
  41 +}
  42 +
  43 +static inline void exofs_put_page(struct page *page)
  44 +{
  45 + kunmap(page);
  46 + page_cache_release(page);
  47 +}
  48 +
  49 +/* Accesses dir's inode->i_size must be called under inode lock */
  50 +static inline unsigned long dir_pages(struct inode *inode)
  51 +{
  52 + return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  53 +}
  54 +
  55 +static unsigned exofs_last_byte(struct inode *inode, unsigned long page_nr)
  56 +{
  57 + loff_t last_byte = inode->i_size;
  58 +
  59 + last_byte -= page_nr << PAGE_CACHE_SHIFT;
  60 + if (last_byte > PAGE_CACHE_SIZE)
  61 + last_byte = PAGE_CACHE_SIZE;
  62 + return last_byte;
  63 +}
  64 +
  65 +static int exofs_commit_chunk(struct page *page, loff_t pos, unsigned len)
  66 +{
  67 + struct address_space *mapping = page->mapping;
  68 + struct inode *dir = mapping->host;
  69 + int err = 0;
  70 +
  71 + dir->i_version++;
  72 +
  73 + if (!PageUptodate(page))
  74 + SetPageUptodate(page);
  75 +
  76 + if (pos+len > dir->i_size) {
  77 + i_size_write(dir, pos+len);
  78 + mark_inode_dirty(dir);
  79 + }
  80 + set_page_dirty(page);
  81 +
  82 + if (IS_DIRSYNC(dir))
  83 + err = write_one_page(page, 1);
  84 + else
  85 + unlock_page(page);
  86 +
  87 + return err;
  88 +}
  89 +
  90 +static void exofs_check_page(struct page *page)
  91 +{
  92 + struct inode *dir = page->mapping->host;
  93 + unsigned chunk_size = exofs_chunk_size(dir);
  94 + char *kaddr = page_address(page);
  95 + unsigned offs, rec_len;
  96 + unsigned limit = PAGE_CACHE_SIZE;
  97 + struct exofs_dir_entry *p;
  98 + char *error;
  99 +
  100 + /* if the page is the last one in the directory */
  101 + if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) {
  102 + limit = dir->i_size & ~PAGE_CACHE_MASK;
  103 + if (limit & (chunk_size - 1))
  104 + goto Ebadsize;
  105 + if (!limit)
  106 + goto out;
  107 + }
  108 + for (offs = 0; offs <= limit - EXOFS_DIR_REC_LEN(1); offs += rec_len) {
  109 + p = (struct exofs_dir_entry *)(kaddr + offs);
  110 + rec_len = le16_to_cpu(p->rec_len);
  111 +
  112 + if (rec_len < EXOFS_DIR_REC_LEN(1))
  113 + goto Eshort;
  114 + if (rec_len & 3)
  115 + goto Ealign;
  116 + if (rec_len < EXOFS_DIR_REC_LEN(p->name_len))
  117 + goto Enamelen;
  118 + if (((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))
  119 + goto Espan;
  120 + }
  121 + if (offs != limit)
  122 + goto Eend;
  123 +out:
  124 + SetPageChecked(page);
  125 + return;
  126 +
  127 +Ebadsize:
  128 + EXOFS_ERR("ERROR [exofs_check_page]: "
  129 + "size of directory #%lu is not a multiple of chunk size",
  130 + dir->i_ino
  131 + );
  132 + goto fail;
  133 +Eshort:
  134 + error = "rec_len is smaller than minimal";
  135 + goto bad_entry;
  136 +Ealign:
  137 + error = "unaligned directory entry";
  138 + goto bad_entry;
  139 +Enamelen:
  140 + error = "rec_len is too small for name_len";
  141 + goto bad_entry;
  142 +Espan:
  143 + error = "directory entry across blocks";
  144 + goto bad_entry;
  145 +bad_entry:
  146 + EXOFS_ERR(
  147 + "ERROR [exofs_check_page]: bad entry in directory #%lu: %s - "
  148 + "offset=%lu, inode=%llu, rec_len=%d, name_len=%d",
  149 + dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
  150 + _LLU(le64_to_cpu(p->inode_no)),
  151 + rec_len, p->name_len);
  152 + goto fail;
  153 +Eend:
  154 + p = (struct exofs_dir_entry *)(kaddr + offs);
  155 + EXOFS_ERR("ERROR [exofs_check_page]: "
  156 + "entry in directory #%lu spans the page boundary"
  157 + "offset=%lu, inode=%llu",
  158 + dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
  159 + _LLU(le64_to_cpu(p->inode_no)));
  160 +fail:
  161 + SetPageChecked(page);
  162 + SetPageError(page);
  163 +}
  164 +
  165 +static struct page *exofs_get_page(struct inode *dir, unsigned long n)
  166 +{
  167 + struct address_space *mapping = dir->i_mapping;
  168 + struct page *page = read_mapping_page(mapping, n, NULL);
  169 +
  170 + if (!IS_ERR(page)) {
  171 + kmap(page);
  172 + if (!PageChecked(page))
  173 + exofs_check_page(page);
  174 + if (PageError(page))
  175 + goto fail;
  176 + }
  177 + return page;
  178 +
  179 +fail:
  180 + exofs_put_page(page);
  181 + return ERR_PTR(-EIO);
  182 +}
  183 +
  184 +static inline int exofs_match(int len, const unsigned char *name,
  185 + struct exofs_dir_entry *de)
  186 +{
  187 + if (len != de->name_len)
  188 + return 0;
  189 + if (!de->inode_no)
  190 + return 0;
  191 + return !memcmp(name, de->name, len);
  192 +}
  193 +
  194 +static inline
  195 +struct exofs_dir_entry *exofs_next_entry(struct exofs_dir_entry *p)
  196 +{
  197 + return (struct exofs_dir_entry *)((char *)p + le16_to_cpu(p->rec_len));
  198 +}
  199 +
  200 +static inline unsigned
  201 +exofs_validate_entry(char *base, unsigned offset, unsigned mask)
  202 +{
  203 + struct exofs_dir_entry *de = (struct exofs_dir_entry *)(base + offset);
  204 + struct exofs_dir_entry *p =
  205 + (struct exofs_dir_entry *)(base + (offset&mask));
  206 + while ((char *)p < (char *)de) {
  207 + if (p->rec_len == 0)
  208 + break;
  209 + p = exofs_next_entry(p);
  210 + }
  211 + return (char *)p - base;
  212 +}
  213 +
  214 +static unsigned char exofs_filetype_table[EXOFS_FT_MAX] = {
  215 + [EXOFS_FT_UNKNOWN] = DT_UNKNOWN,
  216 + [EXOFS_FT_REG_FILE] = DT_REG,
  217 + [EXOFS_FT_DIR] = DT_DIR,
  218 + [EXOFS_FT_CHRDEV] = DT_CHR,
  219 + [EXOFS_FT_BLKDEV] = DT_BLK,
  220 + [EXOFS_FT_FIFO] = DT_FIFO,
  221 + [EXOFS_FT_SOCK] = DT_SOCK,
  222 + [EXOFS_FT_SYMLINK] = DT_LNK,
  223 +};
  224 +
  225 +#define S_SHIFT 12
  226 +static unsigned char exofs_type_by_mode[S_IFMT >> S_SHIFT] = {
  227 + [S_IFREG >> S_SHIFT] = EXOFS_FT_REG_FILE,
  228 + [S_IFDIR >> S_SHIFT] = EXOFS_FT_DIR,
  229 + [S_IFCHR >> S_SHIFT] = EXOFS_FT_CHRDEV,
  230 + [S_IFBLK >> S_SHIFT] = EXOFS_FT_BLKDEV,
  231 + [S_IFIFO >> S_SHIFT] = EXOFS_FT_FIFO,
  232 + [S_IFSOCK >> S_SHIFT] = EXOFS_FT_SOCK,
  233 + [S_IFLNK >> S_SHIFT] = EXOFS_FT_SYMLINK,
  234 +};
  235 +
  236 +static inline
  237 +void exofs_set_de_type(struct exofs_dir_entry *de, struct inode *inode)
  238 +{
  239 + mode_t mode = inode->i_mode;
  240 + de->file_type = exofs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
  241 +}
  242 +
  243 +static int
  244 +exofs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  245 +{
  246 + loff_t pos = filp->f_pos;
  247 + struct inode *inode = filp->f_path.dentry->d_inode;
  248 + unsigned int offset = pos & ~PAGE_CACHE_MASK;
  249 + unsigned long n = pos >> PAGE_CACHE_SHIFT;
  250 + unsigned long npages = dir_pages(inode);
  251 + unsigned chunk_mask = ~(exofs_chunk_size(inode)-1);
  252 + unsigned char *types = NULL;
  253 + int need_revalidate = (filp->f_version != inode->i_version);
  254 +
  255 + if (pos > inode->i_size - EXOFS_DIR_REC_LEN(1))
  256 + return 0;
  257 +
  258 + types = exofs_filetype_table;
  259 +
  260 + for ( ; n < npages; n++, offset = 0) {
  261 + char *kaddr, *limit;
  262 + struct exofs_dir_entry *de;
  263 + struct page *page = exofs_get_page(inode, n);
  264 +
  265 + if (IS_ERR(page)) {
  266 + EXOFS_ERR("ERROR: "
  267 + "bad page in #%lu",
  268 + inode->i_ino);
  269 + filp->f_pos += PAGE_CACHE_SIZE - offset;
  270 + return PTR_ERR(page);
  271 + }
  272 + kaddr = page_address(page);
  273 + if (unlikely(need_revalidate)) {
  274 + if (offset) {
  275 + offset = exofs_validate_entry(kaddr, offset,
  276 + chunk_mask);
  277 + filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset;
  278 + }
  279 + filp->f_version = inode->i_version;
  280 + need_revalidate = 0;
  281 + }
  282 + de = (struct exofs_dir_entry *)(kaddr + offset);
  283 + limit = kaddr + exofs_last_byte(inode, n) -
  284 + EXOFS_DIR_REC_LEN(1);
  285 + for (; (char *)de <= limit; de = exofs_next_entry(de)) {
  286 + if (de->rec_len == 0) {
  287 + EXOFS_ERR("ERROR: "
  288 + "zero-length directory entry");
  289 + exofs_put_page(page);
  290 + return -EIO;
  291 + }
  292 + if (de->inode_no) {
  293 + int over;
  294 + unsigned char d_type = DT_UNKNOWN;
  295 +
  296 + if (types && de->file_type < EXOFS_FT_MAX)
  297 + d_type = types[de->file_type];
  298 +
  299 + offset = (char *)de - kaddr;
  300 + over = filldir(dirent, de->name, de->name_len,
  301 + (n<<PAGE_CACHE_SHIFT) | offset,
  302 + le64_to_cpu(de->inode_no),
  303 + d_type);
  304 + if (over) {
  305 + exofs_put_page(page);
  306 + return 0;
  307 + }
  308 + }
  309 + filp->f_pos += le16_to_cpu(de->rec_len);
  310 + }
  311 + exofs_put_page(page);
  312 + }
  313 +
  314 + return 0;
  315 +}
  316 +
  317 +struct exofs_dir_entry *exofs_find_entry(struct inode *dir,
  318 + struct dentry *dentry, struct page **res_page)
  319 +{
  320 + const unsigned char *name = dentry->d_name.name;
  321 + int namelen = dentry->d_name.len;
  322 + unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
  323 + unsigned long start, n;
  324 + unsigned long npages = dir_pages(dir);
  325 + struct page *page = NULL;
  326 + struct exofs_i_info *oi = exofs_i(dir);
  327 + struct exofs_dir_entry *de;
  328 +
  329 + if (npages == 0)
  330 + goto out;
  331 +
  332 + *res_page = NULL;
  333 +
  334 + start = oi->i_dir_start_lookup;
  335 + if (start >= npages)
  336 + start = 0;
  337 + n = start;
  338 + do {
  339 + char *kaddr;
  340 + page = exofs_get_page(dir, n);
  341 + if (!IS_ERR(page)) {
  342 + kaddr = page_address(page);
  343 + de = (struct exofs_dir_entry *) kaddr;
  344 + kaddr += exofs_last_byte(dir, n) - reclen;
  345 + while ((char *) de <= kaddr) {
  346 + if (de->rec_len == 0) {
  347 + EXOFS_ERR(
  348 + "ERROR: exofs_find_entry: "
  349 + "zero-length directory entry");
  350 + exofs_put_page(page);
  351 + goto out;
  352 + }
  353 + if (exofs_match(namelen, name, de))
  354 + goto found;
  355 + de = exofs_next_entry(de);
  356 + }
  357 + exofs_put_page(page);
  358 + }
  359 + if (++n >= npages)
  360 + n = 0;
  361 + } while (n != start);
  362 +out:
  363 + return NULL;
  364 +
  365 +found:
  366 + *res_page = page;
  367 + oi->i_dir_start_lookup = n;
  368 + return de;
  369 +}
  370 +
  371 +struct exofs_dir_entry *exofs_dotdot(struct inode *dir, struct page **p)
  372 +{
  373 + struct page *page = exofs_get_page(dir, 0);
  374 + struct exofs_dir_entry *de = NULL;
  375 +
  376 + if (!IS_ERR(page)) {
  377 + de = exofs_next_entry(
  378 + (struct exofs_dir_entry *)page_address(page));
  379 + *p = page;
  380 + }
  381 + return de;
  382 +}
  383 +
  384 +ino_t exofs_inode_by_name(struct inode *dir, struct dentry *dentry)
  385 +{
  386 + ino_t res = 0;
  387 + struct exofs_dir_entry *de;
  388 + struct page *page;
  389 +
  390 + de = exofs_find_entry(dir, dentry, &page);
  391 + if (de) {
  392 + res = le64_to_cpu(de->inode_no);
  393 + exofs_put_page(page);
  394 + }
  395 + return res;
  396 +}
  397 +
  398 +int exofs_set_link(struct inode *dir, struct exofs_dir_entry *de,
  399 + struct page *page, struct inode *inode)
  400 +{
  401 + loff_t pos = page_offset(page) +
  402 + (char *) de - (char *) page_address(page);
  403 + unsigned len = le16_to_cpu(de->rec_len);
  404 + int err;
  405 +
  406 + lock_page(page);
  407 + err = exofs_write_begin(NULL, page->mapping, pos, len,
  408 + AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
  409 + if (err)
  410 + EXOFS_ERR("exofs_set_link: exofs_write_begin FAILD => %d\n",
  411 + err);
  412 +
  413 + de->inode_no = cpu_to_le64(inode->i_ino);
  414 + exofs_set_de_type(de, inode);
  415 + if (likely(!err))
  416 + err = exofs_commit_chunk(page, pos, len);
  417 + exofs_put_page(page);
  418 + dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  419 + mark_inode_dirty(dir);
  420 + return err;
  421 +}
  422 +
  423 +int exofs_add_link(struct dentry *dentry, struct inode *inode)
  424 +{
  425 + struct inode *dir = dentry->d_parent->d_inode;
  426 + const unsigned char *name = dentry->d_name.name;
  427 + int namelen = dentry->d_name.len;
  428 + unsigned chunk_size = exofs_chunk_size(dir);
  429 + unsigned reclen = EXOFS_DIR_REC_LEN(namelen);
  430 + unsigned short rec_len, name_len;
  431 + struct page *page = NULL;
  432 + struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
  433 + struct exofs_dir_entry *de;
  434 + unsigned long npages = dir_pages(dir);
  435 + unsigned long n;
  436 + char *kaddr;
  437 + loff_t pos;
  438 + int err;
  439 +
  440 + for (n = 0; n <= npages; n++) {
  441 + char *dir_end;
  442 +
  443 + page = exofs_get_page(dir, n);
  444 + err = PTR_ERR(page);
  445 + if (IS_ERR(page))
  446 + goto out;
  447 + lock_page(page);
  448 + kaddr = page_address(page);
  449 + dir_end = kaddr + exofs_last_byte(dir, n);
  450 + de = (struct exofs_dir_entry *)kaddr;
  451 + kaddr += PAGE_CACHE_SIZE - reclen;
  452 + while ((char *)de <= kaddr) {
  453 + if ((char *)de == dir_end) {
  454 + name_len = 0;
  455 + rec_len = chunk_size;
  456 + de->rec_len = cpu_to_le16(chunk_size);
  457 + de->inode_no = 0;
  458 + goto got_it;
  459 + }
  460 + if (de->rec_len == 0) {
  461 + EXOFS_ERR("ERROR: exofs_add_link: "
  462 + "zero-length directory entry");
  463 + err = -EIO;
  464 + goto out_unlock;
  465 + }
  466 + err = -EEXIST;
  467 + if (exofs_match(namelen, name, de))
  468 + goto out_unlock;
  469 + name_len = EXOFS_DIR_REC_LEN(de->name_len);
  470 + rec_len = le16_to_cpu(de->rec_len);
  471 + if (!de->inode_no && rec_len >= reclen)
  472 + goto got_it;
  473 + if (rec_len >= name_len + reclen)
  474 + goto got_it;
  475 + de = (struct exofs_dir_entry *) ((char *) de + rec_len);
  476 + }
  477 + unlock_page(page);
  478 + exofs_put_page(page);
  479 + }
  480 +
  481 + EXOFS_ERR("exofs_add_link: BAD dentry=%p or inode=%p", dentry, inode);
  482 + return -EINVAL;
  483 +
  484 +got_it:
  485 + pos = page_offset(page) +
  486 + (char *)de - (char *)page_address(page);
  487 + err = exofs_write_begin(NULL, page->mapping, pos, rec_len, 0,
  488 + &page, NULL);
  489 + if (err)
  490 + goto out_unlock;
  491 + if (de->inode_no) {
  492 + struct exofs_dir_entry *de1 =
  493 + (struct exofs_dir_entry *)((char *)de + name_len);
  494 + de1->rec_len = cpu_to_le16(rec_len - name_len);
  495 + de->rec_len = cpu_to_le16(name_len);
  496 + de = de1;
  497 + }
  498 + de->name_len = namelen;
  499 + memcpy(de->name, name, namelen);
  500 + de->inode_no = cpu_to_le64(inode->i_ino);
  501 + exofs_set_de_type(de, inode);
  502 + err = exofs_commit_chunk(page, pos, rec_len);
  503 + dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  504 + mark_inode_dirty(dir);
  505 + sbi->s_numfiles++;
  506 +
  507 +out_put:
  508 + exofs_put_page(page);
  509 +out:
  510 + return err;
  511 +out_unlock:
  512 + unlock_page(page);
  513 + goto out_put;
  514 +}
  515 +
  516 +int exofs_delete_entry(struct exofs_dir_entry *dir, struct page *page)
  517 +{
  518 + struct address_space *mapping = page->mapping;
  519 + struct inode *inode = mapping->host;
  520 + struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
  521 + char *kaddr = page_address(page);
  522 + unsigned from = ((char *)dir - kaddr) & ~(exofs_chunk_size(inode)-1);
  523 + unsigned to = ((char *)dir - kaddr) + le16_to_cpu(dir->rec_len);
  524 + loff_t pos;
  525 + struct exofs_dir_entry *pde = NULL;
  526 + struct exofs_dir_entry *de = (struct exofs_dir_entry *) (kaddr + from);
  527 + int err;
  528 +
  529 + while (de < dir) {
  530 + if (de->rec_len == 0) {
  531 + EXOFS_ERR("ERROR: exofs_delete_entry:"
  532 + "zero-length directory entry");
  533 + err = -EIO;
  534 + goto out;
  535 + }
  536 + pde = de;
  537 + de = exofs_next_entry(de);
  538 + }
  539 + if (pde)
  540 + from = (char *)pde - (char *)page_address(page);
  541 + pos = page_offset(page) + from;
  542 + lock_page(page);
  543 + err = exofs_write_begin(NULL, page->mapping, pos, to - from, 0,
  544 + &page, NULL);
  545 + if (err)
  546 + EXOFS_ERR("exofs_delete_entry: exofs_write_begin FAILD => %d\n",
  547 + err);
  548 + if (pde)
  549 + pde->rec_len = cpu_to_le16(to - from);
  550 + dir->inode_no = 0;
  551 + if (likely(!err))
  552 + err = exofs_commit_chunk(page, pos, to - from);
  553 + inode->i_ctime = inode->i_mtime = CURRENT_TIME;
  554 + mark_inode_dirty(inode);
  555 + sbi->s_numfiles--;
  556 +out:
  557 + exofs_put_page(page);
  558 + return err;
  559 +}
  560 +
  561 +/* kept aligned on 4 bytes */
  562 +#define THIS_DIR ".\0\0"
  563 +#define PARENT_DIR "..\0"
  564 +
  565 +int exofs_make_empty(struct inode *inode, struct inode *parent)
  566 +{
  567 + struct address_space *mapping = inode->i_mapping;
  568 + struct page *page = grab_cache_page(mapping, 0);
  569 + unsigned chunk_size = exofs_chunk_size(inode);
  570 + struct exofs_dir_entry *de;
  571 + int err;
  572 + void *kaddr;
  573 +
  574 + if (!page)
  575 + return -ENOMEM;
  576 +
  577 + err = exofs_write_begin(NULL, page->mapping, 0, chunk_size, 0,
  578 + &page, NULL);
  579 + if (err) {
  580 + unlock_page(page);
  581 + goto fail;
  582 + }
  583 +
  584 + kaddr = kmap_atomic(page, KM_USER0);
  585 + de = (struct exofs_dir_entry *)kaddr;
  586 + de->name_len = 1;
  587 + de->rec_len = cpu_to_le16(EXOFS_DIR_REC_LEN(1));
  588 + memcpy(de->name, THIS_DIR, sizeof(THIS_DIR));
  589 + de->inode_no = cpu_to_le64(inode->i_ino);
  590 + exofs_set_de_type(de, inode);
  591 +
  592 + de = (struct exofs_dir_entry *)(kaddr + EXOFS_DIR_REC_LEN(1));
  593 + de->name_len = 2;
  594 + de->rec_len = cpu_to_le16(chunk_size - EXOFS_DIR_REC_LEN(1));
  595 + de->inode_no = cpu_to_le64(parent->i_ino);
  596 + memcpy(de->name, PARENT_DIR, sizeof(PARENT_DIR));
  597 + exofs_set_de_type(de, inode);
  598 + kunmap_atomic(page, KM_USER0);
  599 + err = exofs_commit_chunk(page, 0, chunk_size);
  600 +fail:
  601 + page_cache_release(page);
  602 + return err;
  603 +}
  604 +
  605 +int exofs_empty_dir(struct inode *inode)
  606 +{
  607 + struct page *page = NULL;
  608 + unsigned long i, npages = dir_pages(inode);
  609 +
  610 + for (i = 0; i < npages; i++) {
  611 + char *kaddr;
  612 + struct exofs_dir_entry *de;
  613 + page = exofs_get_page(inode, i);
  614 +
  615 + if (IS_ERR(page))
  616 + continue;
  617 +
  618 + kaddr = page_address(page);
  619 + de = (struct exofs_dir_entry *)kaddr;
  620 + kaddr += exofs_last_byte(inode, i) - EXOFS_DIR_REC_LEN(1);
  621 +
  622 + while ((char *)de <= kaddr) {
  623 + if (de->rec_len == 0) {
  624 + EXOFS_ERR("ERROR: exofs_empty_dir: "
  625 + "zero-length directory entry"
  626 + "kaddr=%p, de=%p\n", kaddr, de);
  627 + goto not_empty;
  628 + }
  629 + if (de->inode_no != 0) {
  630 + /* check for . and .. */
  631 + if (de->name[0] != '.')
  632 + goto not_empty;
  633 + if (de->name_len > 2)
  634 + goto not_empty;
  635 + if (de->name_len < 2) {
  636 + if (le64_to_cpu(de->inode_no) !=
  637 + inode->i_ino)
  638 + goto not_empty;
  639 + } else if (de->name[1] != '.')
  640 + goto not_empty;
  641 + }
  642 + de = exofs_next_entry(de);
  643 + }
  644 + exofs_put_page(page);
  645 + }
  646 + return 1;
  647 +
  648 +not_empty:
  649 + exofs_put_page(page);
  650 + return 0;
  651 +}
  652 +
  653 +const struct file_operations exofs_dir_operations = {
  654 + .llseek = generic_file_llseek,
  655 + .read = generic_read_dir,
  656 + .readdir = exofs_readdir,
  657 +};
... ... @@ -124,6 +124,11 @@
124 124 return container_of(inode, struct exofs_i_info, vfs_inode);
125 125 }
126 126  
  127 +/*
  128 + * Maximum count of links to a file
  129 + */
  130 +#define EXOFS_LINK_MAX 32000
  131 +
127 132 /*************************
128 133 * function declarations *
129 134 *************************/
130 135  
131 136  
132 137  
... ... @@ -133,16 +138,37 @@
133 138 int exofs_write_begin(struct file *file, struct address_space *mapping,
134 139 loff_t pos, unsigned len, unsigned flags,
135 140 struct page **pagep, void **fsdata);
  141 +extern struct inode *exofs_iget(struct super_block *, unsigned long);
  142 +struct inode *exofs_new_inode(struct inode *, int);
136 143  
  144 +/* dir.c: */
  145 +int exofs_add_link(struct dentry *, struct inode *);
  146 +ino_t exofs_inode_by_name(struct inode *, struct dentry *);
  147 +int exofs_delete_entry(struct exofs_dir_entry *, struct page *);
  148 +int exofs_make_empty(struct inode *, struct inode *);
  149 +struct exofs_dir_entry *exofs_find_entry(struct inode *, struct dentry *,
  150 + struct page **);
  151 +int exofs_empty_dir(struct inode *);
  152 +struct exofs_dir_entry *exofs_dotdot(struct inode *, struct page **);
  153 +int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *,
  154 + struct inode *);
  155 +
137 156 /*********************
138 157 * operation vectors *
139 158 *********************/
  159 +/* dir.c: */
  160 +extern const struct file_operations exofs_dir_operations;
  161 +
140 162 /* file.c */
141 163 extern const struct inode_operations exofs_file_inode_operations;
142 164 extern const struct file_operations exofs_file_operations;
143 165  
144 166 /* inode.c */
145 167 extern const struct address_space_operations exofs_aops;
  168 +
  169 +/* namei.c */
  170 +extern const struct inode_operations exofs_dir_inode_operations;
  171 +extern const struct inode_operations exofs_special_inode_operations;
146 172  
147 173 /* symlink.c */
148 174 extern const struct inode_operations exofs_symlink_inode_operations;
... ... @@ -843,4 +843,276 @@
843 843 error = inode_setattr(inode, iattr);
844 844 return error;
845 845 }
  846 +
  847 +/*
  848 + * Read an inode from the OSD, and return it as is. We also return the size
  849 + * attribute in the 'sanity' argument if we got compiled with debugging turned
  850 + * on.
  851 + */
  852 +static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
  853 + struct exofs_fcb *inode, uint64_t *sanity)
  854 +{
  855 + struct exofs_sb_info *sbi = sb->s_fs_info;
  856 + struct osd_request *or;
  857 + struct osd_attr attr;
  858 + struct osd_obj_id obj = {sbi->s_pid,
  859 + oi->vfs_inode.i_ino + EXOFS_OBJ_OFF};
  860 + int ret;
  861 +
  862 + exofs_make_credential(oi->i_cred, &obj);
  863 +
  864 + or = osd_start_request(sbi->s_dev, GFP_KERNEL);
  865 + if (unlikely(!or)) {
  866 + EXOFS_ERR("exofs_get_inode: osd_start_request failed.\n");
  867 + return -ENOMEM;
  868 + }
  869 + osd_req_get_attributes(or, &obj);
  870 +
  871 + /* we need the inode attribute */
  872 + osd_req_add_get_attr_list(or, &g_attr_inode_data, 1);
  873 +
  874 +#ifdef EXOFS_DEBUG_OBJ_ISIZE
  875 + /* we get the size attributes to do a sanity check */
  876 + osd_req_add_get_attr_list(or, &g_attr_logical_length, 1);
  877 +#endif
  878 +
  879 + ret = exofs_sync_op(or, sbi->s_timeout, oi->i_cred);
  880 + if (ret)
  881 + goto out;
  882 +
  883 + attr = g_attr_inode_data;
  884 + ret = extract_attr_from_req(or, &attr);
  885 + if (ret) {
  886 + EXOFS_ERR("exofs_get_inode: extract_attr_from_req failed\n");
  887 + goto out;
  888 + }
  889 +
  890 + WARN_ON(attr.len != EXOFS_INO_ATTR_SIZE);
  891 + memcpy(inode, attr.val_ptr, EXOFS_INO_ATTR_SIZE);
  892 +
  893 +#ifdef EXOFS_DEBUG_OBJ_ISIZE
  894 + attr = g_attr_logical_length;
  895 + ret = extract_attr_from_req(or, &attr);
  896 + if (ret) {
  897 + EXOFS_ERR("ERROR: extract attr from or failed\n");
  898 + goto out;
  899 + }
  900 + *sanity = get_unaligned_be64(attr.val_ptr);
  901 +#endif
  902 +
  903 +out:
  904 + osd_end_request(or);
  905 + return ret;
  906 +}
  907 +
  908 +/*
  909 + * Fill in an inode read from the OSD and set it up for use
  910 + */
  911 +struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
  912 +{
  913 + struct exofs_i_info *oi;
  914 + struct exofs_fcb fcb;
  915 + struct inode *inode;
  916 + uint64_t uninitialized_var(sanity);
  917 + int ret;
  918 +
  919 + inode = iget_locked(sb, ino);
  920 + if (!inode)
  921 + return ERR_PTR(-ENOMEM);
  922 + if (!(inode->i_state & I_NEW))
  923 + return inode;
  924 + oi = exofs_i(inode);
  925 +
  926 + /* read the inode from the osd */
  927 + ret = exofs_get_inode(sb, oi, &fcb, &sanity);
  928 + if (ret)
  929 + goto bad_inode;
  930 +
  931 + init_waitqueue_head(&oi->i_wq);
  932 + set_obj_created(oi);
  933 +
  934 + /* copy stuff from on-disk struct to in-memory struct */
  935 + inode->i_mode = le16_to_cpu(fcb.i_mode);
  936 + inode->i_uid = le32_to_cpu(fcb.i_uid);
  937 + inode->i_gid = le32_to_cpu(fcb.i_gid);
  938 + inode->i_nlink = le16_to_cpu(fcb.i_links_count);
  939 + inode->i_ctime.tv_sec = (signed)le32_to_cpu(fcb.i_ctime);
  940 + inode->i_atime.tv_sec = (signed)le32_to_cpu(fcb.i_atime);
  941 + inode->i_mtime.tv_sec = (signed)le32_to_cpu(fcb.i_mtime);
  942 + inode->i_ctime.tv_nsec =
  943 + inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = 0;
  944 + oi->i_commit_size = le64_to_cpu(fcb.i_size);
  945 + i_size_write(inode, oi->i_commit_size);
  946 + inode->i_blkbits = EXOFS_BLKSHIFT;
  947 + inode->i_generation = le32_to_cpu(fcb.i_generation);
  948 +
  949 +#ifdef EXOFS_DEBUG_OBJ_ISIZE
  950 + if ((inode->i_size != sanity) &&
  951 + (!exofs_inode_is_fast_symlink(inode))) {
  952 + EXOFS_ERR("WARNING: Size of object from inode and "
  953 + "attributes differ (%lld != %llu)\n",
  954 + inode->i_size, _LLU(sanity));
  955 + }
  956 +#endif
  957 +
  958 + oi->i_dir_start_lookup = 0;
  959 +
  960 + if ((inode->i_nlink == 0) && (inode->i_mode == 0)) {
  961 + ret = -ESTALE;
  962 + goto bad_inode;
  963 + }
  964 +
  965 + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
  966 + if (fcb.i_data[0])
  967 + inode->i_rdev =
  968 + old_decode_dev(le32_to_cpu(fcb.i_data[0]));
  969 + else
  970 + inode->i_rdev =
  971 + new_decode_dev(le32_to_cpu(fcb.i_data[1]));
  972 + } else {
  973 + memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
  974 + }
  975 +
  976 + if (S_ISREG(inode->i_mode)) {
  977 + inode->i_op = &exofs_file_inode_operations;
  978 + inode->i_fop = &exofs_file_operations;
  979 + inode->i_mapping->a_ops = &exofs_aops;
  980 + } else if (S_ISDIR(inode->i_mode)) {
  981 + inode->i_op = &exofs_dir_inode_operations;
  982 + inode->i_fop = &exofs_dir_operations;
  983 + inode->i_mapping->a_ops = &exofs_aops;
  984 + } else if (S_ISLNK(inode->i_mode)) {
  985 + if (exofs_inode_is_fast_symlink(inode))
  986 + inode->i_op = &exofs_fast_symlink_inode_operations;
  987 + else {
  988 + inode->i_op = &exofs_symlink_inode_operations;
  989 + inode->i_mapping->a_ops = &exofs_aops;
  990 + }
  991 + } else {
  992 + inode->i_op = &exofs_special_inode_operations;
  993 + if (fcb.i_data[0])
  994 + init_special_inode(inode, inode->i_mode,
  995 + old_decode_dev(le32_to_cpu(fcb.i_data[0])));
  996 + else
  997 + init_special_inode(inode, inode->i_mode,
  998 + new_decode_dev(le32_to_cpu(fcb.i_data[1])));
  999 + }
  1000 +
  1001 + unlock_new_inode(inode);
  1002 + return inode;
  1003 +
  1004 +bad_inode:
  1005 + iget_failed(inode);
  1006 + return ERR_PTR(ret);
  1007 +}
  1008 +
  1009 +int __exofs_wait_obj_created(struct exofs_i_info *oi)
  1010 +{
  1011 + if (!obj_created(oi)) {
  1012 + BUG_ON(!obj_2bcreated(oi));
  1013 + wait_event(oi->i_wq, obj_created(oi));
  1014 + }
  1015 + return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
  1016 +}
  1017 +/*
  1018 + * Callback function from exofs_new_inode(). The important thing is that we
  1019 + * set the obj_created flag so that other methods know that the object exists on
  1020 + * the OSD.
  1021 + */
  1022 +static void create_done(struct osd_request *or, void *p)
  1023 +{
  1024 + struct inode *inode = p;
  1025 + struct exofs_i_info *oi = exofs_i(inode);
  1026 + struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
  1027 + int ret;
  1028 +
  1029 + ret = exofs_check_ok(or);
  1030 + osd_end_request(or);
  1031 + atomic_dec(&sbi->s_curr_pending);
  1032 +
  1033 + if (unlikely(ret)) {
  1034 + EXOFS_ERR("object=0x%llx creation faild in pid=0x%llx",
  1035 + _LLU(sbi->s_pid), _LLU(inode->i_ino + EXOFS_OBJ_OFF));
  1036 + make_bad_inode(inode);
  1037 + } else
  1038 + set_obj_created(oi);
  1039 +
  1040 + atomic_dec(&inode->i_count);
  1041 + wake_up(&oi->i_wq);
  1042 +}
  1043 +
  1044 +/*
  1045 + * Set up a new inode and create an object for it on the OSD
  1046 + */
  1047 +struct inode *exofs_new_inode(struct inode *dir, int mode)
  1048 +{
  1049 + struct super_block *sb;
  1050 + struct inode *inode;
  1051 + struct exofs_i_info *oi;
  1052 + struct exofs_sb_info *sbi;
  1053 + struct osd_request *or;
  1054 + struct osd_obj_id obj;
  1055 + int ret;
  1056 +
  1057 + sb = dir->i_sb;
  1058 + inode = new_inode(sb);
  1059 + if (!inode)
  1060 + return ERR_PTR(-ENOMEM);
  1061 +
  1062 + oi = exofs_i(inode);
  1063 +
  1064 + init_waitqueue_head(&oi->i_wq);
  1065 + set_obj_2bcreated(oi);
  1066 +
  1067 + sbi = sb->s_fs_info;
  1068 +
  1069 + sb->s_dirt = 1;
  1070 + inode->i_uid = current->cred->fsuid;
  1071 + if (dir->i_mode & S_ISGID) {
  1072 + inode->i_gid = dir->i_gid;
  1073 + if (S_ISDIR(mode))
  1074 + mode |= S_ISGID;
  1075 + } else {
  1076 + inode->i_gid = current->cred->fsgid;
  1077 + }
  1078 + inode->i_mode = mode;
  1079 +
  1080 + inode->i_ino = sbi->s_nextid++;
  1081 + inode->i_blkbits = EXOFS_BLKSHIFT;
  1082 + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  1083 + oi->i_commit_size = inode->i_size = 0;
  1084 + spin_lock(&sbi->s_next_gen_lock);
  1085 + inode->i_generation = sbi->s_next_generation++;
  1086 + spin_unlock(&sbi->s_next_gen_lock);
  1087 + insert_inode_hash(inode);
  1088 +
  1089 + mark_inode_dirty(inode);
  1090 +
  1091 + obj.partition = sbi->s_pid;
  1092 + obj.id = inode->i_ino + EXOFS_OBJ_OFF;
  1093 + exofs_make_credential(oi->i_cred, &obj);
  1094 +
  1095 + or = osd_start_request(sbi->s_dev, GFP_KERNEL);
  1096 + if (unlikely(!or)) {
  1097 + EXOFS_ERR("exofs_new_inode: osd_start_request failed\n");
  1098 + return ERR_PTR(-ENOMEM);
  1099 + }
  1100 +
  1101 + osd_req_create_object(or, &obj);
  1102 +
  1103 + /* increment the refcount so that the inode will still be around when we
  1104 + * reach the callback
  1105 + */
  1106 + atomic_inc(&inode->i_count);
  1107 +
  1108 + ret = exofs_async_op(or, create_done, inode, oi->i_cred);
  1109 + if (ret) {
  1110 + atomic_dec(&inode->i_count);
  1111 + osd_end_request(or);
  1112 + return ERR_PTR(-EIO);
  1113 + }
  1114 + atomic_inc(&sbi->s_curr_pending);
  1115 +
  1116 + return inode;
  1117 +}
  1 +/*
  2 + * Copyright (C) 2005, 2006
  3 + * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com)
  4 + * Copyright (C) 2005, 2006
  5 + * International Business Machines
  6 + * Copyright (C) 2008, 2009
  7 + * Boaz Harrosh <bharrosh@panasas.com>
  8 + *
  9 + * Copyrights for code taken from ext2:
  10 + * Copyright (C) 1992, 1993, 1994, 1995
  11 + * Remy Card (card@masi.ibp.fr)
  12 + * Laboratoire MASI - Institut Blaise Pascal
  13 + * Universite Pierre et Marie Curie (Paris VI)
  14 + * from
  15 + * linux/fs/minix/inode.c
  16 + * Copyright (C) 1991, 1992 Linus Torvalds
  17 + *
  18 + * This file is part of exofs.
  19 + *
  20 + * exofs is free software; you can redistribute it and/or modify
  21 + * it under the terms of the GNU General Public License as published by
  22 + * the Free Software Foundation. Since it is based on ext2, and the only
  23 + * valid version of GPL for the Linux kernel is version 2, the only valid
  24 + * version of GPL for exofs is version 2.
  25 + *
  26 + * exofs is distributed in the hope that it will be useful,
  27 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  29 + * GNU General Public License for more details.
  30 + *
  31 + * You should have received a copy of the GNU General Public License
  32 + * along with exofs; if not, write to the Free Software
  33 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  34 + */
  35 +
  36 +#include "exofs.h"
  37 +
  38 +static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
  39 +{
  40 + int err = exofs_add_link(dentry, inode);
  41 + if (!err) {
  42 + d_instantiate(dentry, inode);
  43 + return 0;
  44 + }
  45 + inode_dec_link_count(inode);
  46 + iput(inode);
  47 + return err;
  48 +}
  49 +
  50 +static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
  51 + struct nameidata *nd)
  52 +{
  53 + struct inode *inode;
  54 + ino_t ino;
  55 +
  56 + if (dentry->d_name.len > EXOFS_NAME_LEN)
  57 + return ERR_PTR(-ENAMETOOLONG);
  58 +
  59 + ino = exofs_inode_by_name(dir, dentry);
  60 + inode = NULL;
  61 + if (ino) {
  62 + inode = exofs_iget(dir->i_sb, ino);
  63 + if (IS_ERR(inode))
  64 + return ERR_CAST(inode);
  65 + }
  66 + return d_splice_alias(inode, dentry);
  67 +}
  68 +
  69 +static int exofs_create(struct inode *dir, struct dentry *dentry, int mode,
  70 + struct nameidata *nd)
  71 +{
  72 + struct inode *inode = exofs_new_inode(dir, mode);
  73 + int err = PTR_ERR(inode);
  74 + if (!IS_ERR(inode)) {
  75 + inode->i_op = &exofs_file_inode_operations;
  76 + inode->i_fop = &exofs_file_operations;
  77 + inode->i_mapping->a_ops = &exofs_aops;
  78 + mark_inode_dirty(inode);
  79 + err = exofs_add_nondir(dentry, inode);
  80 + }
  81 + return err;
  82 +}
  83 +
  84 +static int exofs_mknod(struct inode *dir, struct dentry *dentry, int mode,
  85 + dev_t rdev)
  86 +{
  87 + struct inode *inode;
  88 + int err;
  89 +
  90 + if (!new_valid_dev(rdev))
  91 + return -EINVAL;
  92 +
  93 + inode = exofs_new_inode(dir, mode);
  94 + err = PTR_ERR(inode);
  95 + if (!IS_ERR(inode)) {
  96 + init_special_inode(inode, inode->i_mode, rdev);
  97 + mark_inode_dirty(inode);
  98 + err = exofs_add_nondir(dentry, inode);
  99 + }
  100 + return err;
  101 +}
  102 +
  103 +static int exofs_symlink(struct inode *dir, struct dentry *dentry,
  104 + const char *symname)
  105 +{
  106 + struct super_block *sb = dir->i_sb;
  107 + int err = -ENAMETOOLONG;
  108 + unsigned l = strlen(symname)+1;
  109 + struct inode *inode;
  110 + struct exofs_i_info *oi;
  111 +
  112 + if (l > sb->s_blocksize)
  113 + goto out;
  114 +
  115 + inode = exofs_new_inode(dir, S_IFLNK | S_IRWXUGO);
  116 + err = PTR_ERR(inode);
  117 + if (IS_ERR(inode))
  118 + goto out;
  119 +
  120 + oi = exofs_i(inode);
  121 + if (l > sizeof(oi->i_data)) {
  122 + /* slow symlink */
  123 + inode->i_op = &exofs_symlink_inode_operations;
  124 + inode->i_mapping->a_ops = &exofs_aops;
  125 + memset(oi->i_data, 0, sizeof(oi->i_data));
  126 +
  127 + err = page_symlink(inode, symname, l);
  128 + if (err)
  129 + goto out_fail;
  130 + } else {
  131 + /* fast symlink */
  132 + inode->i_op = &exofs_fast_symlink_inode_operations;
  133 + memcpy(oi->i_data, symname, l);
  134 + inode->i_size = l-1;
  135 + }
  136 + mark_inode_dirty(inode);
  137 +
  138 + err = exofs_add_nondir(dentry, inode);
  139 +out:
  140 + return err;
  141 +
  142 +out_fail:
  143 + inode_dec_link_count(inode);
  144 + iput(inode);
  145 + goto out;
  146 +}
  147 +
  148 +static int exofs_link(struct dentry *old_dentry, struct inode *dir,
  149 + struct dentry *dentry)
  150 +{
  151 + struct inode *inode = old_dentry->d_inode;
  152 +
  153 + if (inode->i_nlink >= EXOFS_LINK_MAX)
  154 + return -EMLINK;
  155 +
  156 + inode->i_ctime = CURRENT_TIME;
  157 + inode_inc_link_count(inode);
  158 + atomic_inc(&inode->i_count);
  159 +
  160 + return exofs_add_nondir(dentry, inode);
  161 +}
  162 +
  163 +static int exofs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  164 +{
  165 + struct inode *inode;
  166 + int err = -EMLINK;
  167 +
  168 + if (dir->i_nlink >= EXOFS_LINK_MAX)
  169 + goto out;
  170 +
  171 + inode_inc_link_count(dir);
  172 +
  173 + inode = exofs_new_inode(dir, S_IFDIR | mode);
  174 + err = PTR_ERR(inode);
  175 + if (IS_ERR(inode))
  176 + goto out_dir;
  177 +
  178 + inode->i_op = &exofs_dir_inode_operations;
  179 + inode->i_fop = &exofs_dir_operations;
  180 + inode->i_mapping->a_ops = &exofs_aops;
  181 +
  182 + inode_inc_link_count(inode);
  183 +
  184 + err = exofs_make_empty(inode, dir);
  185 + if (err)
  186 + goto out_fail;
  187 +
  188 + err = exofs_add_link(dentry, inode);
  189 + if (err)
  190 + goto out_fail;
  191 +
  192 + d_instantiate(dentry, inode);
  193 +out:
  194 + return err;
  195 +
  196 +out_fail:
  197 + inode_dec_link_count(inode);
  198 + inode_dec_link_count(inode);
  199 + iput(inode);
  200 +out_dir:
  201 + inode_dec_link_count(dir);
  202 + goto out;
  203 +}
  204 +
  205 +static int exofs_unlink(struct inode *dir, struct dentry *dentry)
  206 +{
  207 + struct inode *inode = dentry->d_inode;
  208 + struct exofs_dir_entry *de;
  209 + struct page *page;
  210 + int err = -ENOENT;
  211 +
  212 + de = exofs_find_entry(dir, dentry, &page);
  213 + if (!de)
  214 + goto out;
  215 +
  216 + err = exofs_delete_entry(de, page);
  217 + if (err)
  218 + goto out;
  219 +
  220 + inode->i_ctime = dir->i_ctime;
  221 + inode_dec_link_count(inode);
  222 + err = 0;
  223 +out:
  224 + return err;
  225 +}
  226 +
  227 +static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
  228 +{
  229 + struct inode *inode = dentry->d_inode;
  230 + int err = -ENOTEMPTY;
  231 +
  232 + if (exofs_empty_dir(inode)) {
  233 + err = exofs_unlink(dir, dentry);
  234 + if (!err) {
  235 + inode->i_size = 0;
  236 + inode_dec_link_count(inode);
  237 + inode_dec_link_count(dir);
  238 + }
  239 + }
  240 + return err;
  241 +}
  242 +
  243 +static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
  244 + struct inode *new_dir, struct dentry *new_dentry)
  245 +{
  246 + struct inode *old_inode = old_dentry->d_inode;
  247 + struct inode *new_inode = new_dentry->d_inode;
  248 + struct page *dir_page = NULL;
  249 + struct exofs_dir_entry *dir_de = NULL;
  250 + struct page *old_page;
  251 + struct exofs_dir_entry *old_de;
  252 + int err = -ENOENT;
  253 +
  254 + old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
  255 + if (!old_de)
  256 + goto out;
  257 +
  258 + if (S_ISDIR(old_inode->i_mode)) {
  259 + err = -EIO;
  260 + dir_de = exofs_dotdot(old_inode, &dir_page);
  261 + if (!dir_de)
  262 + goto out_old;
  263 + }
  264 +
  265 + if (new_inode) {
  266 + struct page *new_page;
  267 + struct exofs_dir_entry *new_de;
  268 +
  269 + err = -ENOTEMPTY;
  270 + if (dir_de && !exofs_empty_dir(new_inode))
  271 + goto out_dir;
  272 +
  273 + err = -ENOENT;
  274 + new_de = exofs_find_entry(new_dir, new_dentry, &new_page);
  275 + if (!new_de)
  276 + goto out_dir;
  277 + inode_inc_link_count(old_inode);
  278 + err = exofs_set_link(new_dir, new_de, new_page, old_inode);
  279 + new_inode->i_ctime = CURRENT_TIME;
  280 + if (dir_de)
  281 + drop_nlink(new_inode);
  282 + inode_dec_link_count(new_inode);
  283 + if (err)
  284 + goto out_dir;
  285 + } else {
  286 + if (dir_de) {
  287 + err = -EMLINK;
  288 + if (new_dir->i_nlink >= EXOFS_LINK_MAX)
  289 + goto out_dir;
  290 + }
  291 + inode_inc_link_count(old_inode);
  292 + err = exofs_add_link(new_dentry, old_inode);
  293 + if (err) {
  294 + inode_dec_link_count(old_inode);
  295 + goto out_dir;
  296 + }
  297 + if (dir_de)
  298 + inode_inc_link_count(new_dir);
  299 + }
  300 +
  301 + old_inode->i_ctime = CURRENT_TIME;
  302 +
  303 + exofs_delete_entry(old_de, old_page);
  304 + inode_dec_link_count(old_inode);
  305 +
  306 + if (dir_de) {
  307 + err = exofs_set_link(old_inode, dir_de, dir_page, new_dir);
  308 + inode_dec_link_count(old_dir);
  309 + if (err)
  310 + goto out_dir;
  311 + }
  312 + return 0;
  313 +
  314 +
  315 +out_dir:
  316 + if (dir_de) {
  317 + kunmap(dir_page);
  318 + page_cache_release(dir_page);
  319 + }
  320 +out_old:
  321 + kunmap(old_page);
  322 + page_cache_release(old_page);
  323 +out:
  324 + return err;
  325 +}
  326 +
  327 +const struct inode_operations exofs_dir_inode_operations = {
  328 + .create = exofs_create,
  329 + .lookup = exofs_lookup,
  330 + .link = exofs_link,
  331 + .unlink = exofs_unlink,
  332 + .symlink = exofs_symlink,
  333 + .mkdir = exofs_mkdir,
  334 + .rmdir = exofs_rmdir,
  335 + .mknod = exofs_mknod,
  336 + .rename = exofs_rename,
  337 + .setattr = exofs_setattr,
  338 +};
  339 +
  340 +const struct inode_operations exofs_special_inode_operations = {
  341 + .setattr = exofs_setattr,
  342 +};