现在的位置: 首页 > 综合 > 正文

UBIFS文件系统分析4 – 目录项管理

2012年03月11日 ⁄ 综合 ⁄ 共 34162字 ⁄ 字号 评论关闭

传统文件系统,多个目录项集中存放在同一物理块,读取目录项就像读取文件内容一样,物理块内容是连续的目录项,因此目录文件也是有大小区分的,子目录和文件数目越多,那么目录文件尺寸越大。
而ubifs每当增加一个新的目录项,ubifs在master area中生成一个directory entry node,并把这个node插到wandering tree的某个位置,通过wandering tree保持同意目录下目录项在逻辑上的相邻。
这种特性也带来了ubifs在一些目录操作接口上的怪异行为,比如readdir和stat。

  78 /**
  79  * ubifs_new_inode - allocate new UBIFS inode object.
  80  * @c: UBIFS file-system description object
  81  * @dir: parent directory inode
  82  * @mode: inode mode flags
  83  *
  84  * This function finds an unused inode number, allocates new inode and
  85  * initializes it. Returns new inode in case of success and an error code in
  86  * case of failure.
  87  */
  88 struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
  89                   int mode)
  90 {
  91     struct inode *inode;
  92     struct ubifs_inode *ui;
  93
  94     inode = new_inode(c->vfs_sb);
  95     ui = ubifs_inode(inode);
  96     if (!inode)
  97         return ERR_PTR(-ENOMEM);
  98
  99     /*
 100      * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and
 101      * marking them dirty in file write path (see 'file_update_time()').
 102      * UBIFS has to fully control "clean <-> dirty" transitions of inodes
 103      * to make budgeting work.
 104      */
 105     inode->i_flags |= (S_NOCMTIME);
 106
 107     inode_init_owner(inode, dir, mode);
 108     inode->i_mtime = inode->i_atime = inode->i_ctime =
 109              ubifs_current_time(inode);
 110     inode->i_mapping->nrpages = 0;
 111     /* Disable readahead */
 112     inode->i_mapping->backing_dev_info = &c->bdi;
 113
 114     switch (mode & S_IFMT) {
 115     case S_IFREG:
 116         inode->i_mapping->a_ops = &ubifs_file_address_operations;
 117         inode->i_op = &ubifs_file_inode_operations;
 118         inode->i_fop = &ubifs_file_operations;
 119         break;
 120     case S_IFDIR:
 121         inode->i_op  = &ubifs_dir_inode_operations;
 122         inode->i_fop = &ubifs_dir_operations;
 123         inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ;
 124         break;
 125     case S_IFLNK:
 126         inode->i_op = &ubifs_symlink_inode_operations;
 127         break;
 128     case S_IFSOCK:
 129     case S_IFIFO:
 130     case S_IFBLK:
 131     case S_IFCHR:
 132         inode->i_op  = &ubifs_file_inode_operations;
 133         break;
 134     default:
 135         BUG();
 136     }
 137
 138     ui->flags = inherit_flags(dir, mode);
 139     ubifs_set_inode_flags(inode);
 140     if (S_ISREG(mode))
 141         ui->compr_type = c->default_compr;
 142     else
 143         ui->compr_type = UBIFS_COMPR_NONE;
 144     ui->synced_i_size = 0;
 145
 146     spin_lock(&c->cnt_lock);
 147     /* Inode number overflow is currently not supported */
 148     if (c->highest_inum >= INUM_WARN_WATERMARK) {
 149         if (c->highest_inum >= INUM_WATERMARK) {
 150             spin_unlock(&c->cnt_lock);
 151             ubifs_err("out of inode numbers");
 152             make_bad_inode(inode);
 153             iput(inode);
 154             return ERR_PTR(-EINVAL);
 155         }
 156         ubifs_warn("running out of inode numbers (current %lu, max %d)",
 157                (unsigned long)c->highest_inum, INUM_WATERMARK);
 158     }
 159
 160     inode->i_ino = ++c->highest_inum;
 161     /*
 162      * The creation sequence number remains with this inode for its
 163      * lifetime. All nodes for this inode have a greater sequence number,
 164      * and so it is possible to distinguish obsolete nodes belonging to a
 165      * previous incarnation of the same inode number - for example, for the
 166      * purpose of rebuilding the index.
 167      */
 168     ui->creat_sqnum = ++c->max_sqnum;
 169     spin_unlock(&c->cnt_lock);
 170     return inode;
 171 }

138 ~ 139 UBIFS有些inode flag是可以从父目录继承到子目录项的,比如UBIFS_COMPR_FL, UBIFS_SYNC_FL以及UBIFS_DIRSYNC_FL.
UBIFS_COMPR_FL是compression打开关闭标记
UBIFS_SYNC_FL是文件同步标记
UBIFS_DIRSYNC_FL是 是目录内容修改同步标记,这个标记只有子目录项还是目录时才会继承

147~160 UBIFS使用highest_inum记录已经使用过的inode number的最大值,UBIFS使用过的ino不能重复使用
168 creat_sqnum记录这个inode的sequence number,在unclean unmount发生时,ubifs可以通过这个sequence number来确定哪个inode是最新的.

 192 static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 193                    struct nameidata *nd)
 194 {
 195     int err;
 196     union ubifs_key key;
 197     struct inode *inode = NULL;
 198     struct ubifs_dent_node *dent;
 199     struct ubifs_info *c = dir->i_sb->s_fs_info;
 200
 201     dbg_gen("'%.*s' in dir ino %lu",
 202         dentry->d_name.len, dentry->d_name.name, dir->i_ino);
 203
 204     if (dentry->d_name.len > UBIFS_MAX_NLEN)
 205         return ERR_PTR(-ENAMETOOLONG);
 206
 207     dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
 208     if (!dent)
 209         return ERR_PTR(-ENOMEM);
 210
 211     dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
 212
 213     err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
 214     if (err) {
 215         if (err == -ENOENT) {
 216             dbg_gen("not found");
 217             goto done;
 218         }
 219         goto out;
 220     }
 221
 222     if (dbg_check_name(dent, &dentry->d_name)) {
 223         err = -EINVAL;
 224         goto out;
 225     }
 226
 227     inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
 228     if (IS_ERR(inode)) {
 229         /*
 230          * This should not happen. Probably the file-system needs
 231          * checking.
 232          */
 233         err = PTR_ERR(inode);
 234         ubifs_err("dead directory entry '%.*s', error %d",
 235               dentry->d_name.len, dentry->d_name.name, err);
 236         ubifs_ro_mode(c, err);
 237         goto out;
 238     }
 239
 240 done:
 241     kfree(dent);
 242     /*
 243      * Note, d_splice_alias() would be required instead if we supported
 244      * NFS.
 245      */
 246     d_add(dentry, inode);
 247     return NULL;
 248
 249 out:
 250     kfree(dent);
 251     return ERR_PTR(err);
 252 }

211 ~ 213 生成目录项的key,然后在tnc tree中查找符合这个key的node, dentry node可能已经在tnc中,那么直接返回就可以了,如果没在tnc中,则会从flash读取并加到tnc
247 不知道为什么成功了也返回NULL

254 static int ubifs_create(struct inode *dir, struct dentry *dentry, int mode,
 255             struct nameidata *nd)
 256 {
 257     struct inode *inode;
 258     struct ubifs_info *c = dir->i_sb->s_fs_info;
 259     int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 260     struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 261                     .dirtied_ino = 1 };
 262     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 263
 264     /*
 265      * Budget request settings: new inode, new direntry, changing the
 266      * parent directory inode.
 267      */
 268
 269     dbg_gen("dent '%.*s', mode %#x in dir ino %lu",
 270         dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino);
 271
 272     err = ubifs_budget_space(c, &req);
 273     if (err)
 274         return err;
 275
 276     inode = ubifs_new_inode(c, dir, mode);
 277     if (IS_ERR(inode)) {
 278         err = PTR_ERR(inode);
 279         goto out_budg;
 280     }
 281
 282     mutex_lock(&dir_ui->ui_mutex);
 283     dir->i_size += sz_change;
 284     dir_ui->ui_size = dir->i_size;
 285     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 286     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
 287     if (err)
 288         goto out_cancel;
 289     mutex_unlock(&dir_ui->ui_mutex);
 290
 291     ubifs_release_budget(c, &req);
 292     insert_inode_hash(inode);
 293     d_instantiate(dentry, inode);
 294     return 0;
 295
 296 out_cancel:
 297     dir->i_size -= sz_change;
 298     dir_ui->ui_size = dir->i_size;
 299     mutex_unlock(&dir_ui->ui_mutex);
 300     make_bad_inode(inode);
 301     iput(inode);
 302 out_budg:
 303     ubifs_release_budget(c, &req);
 304     ubifs_err("cannot create regular file, error %d", err);
 305     return err;
 306 }

在调用ubifs_create前,已经创建了这个文件对应的dentry,但是相应的inode以及目录项还不存在
272 确保足够的空间进行下面的操作, 创建一个文件节点需要修改:parent inode的ctime和size, 新文件的inode和新文件对应的目录项
286 ubifs_jnl_update写新目录项,inode以及parent inode到journal

 338 /*
 339  * The classical Unix view for directory is that it is a linear array of
 340  * (name, inode number) entries. Linux/VFS assumes this model as well.
 341  * Particularly, 'readdir()' call wants us to return a directory entry offset
 342  * which later may be used to continue 'readdir()'ing the directory or to
 343  * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
 344  * model because directory entries are identified by keys, which may collide.
 345  *
 346  * UBIFS uses directory entry hash value for directory offsets, so
 347  * 'seekdir()'/'telldir()' may not always work because of possible key
 348  * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
 349  * properly by means of saving full directory entry name in the private field
 350  * of the file description object.
 351  *
 352  * This means that UBIFS cannot support NFS which requires full
 353  * 'seekdir()'/'telldir()' support.
 354  */
 355 static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir)
 356 {
 357     int err, over = 0;
 358     struct qstr nm;
 359     union ubifs_key key;
 360     struct ubifs_dent_node *dent;
 361     struct inode *dir = file->f_path.dentry->d_inode;
 362     struct ubifs_info *c = dir->i_sb->s_fs_info;
 363
 364     dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos);
 365
 366     if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2)
 367         /*
 368          * The directory was seek'ed to a senseless position or there
 369          * are no more entries.
 370          */
 371         return 0;
 372
 373     /* File positions 0 and 1 correspond to "." and ".." */
 374     if (file->f_pos == 0) {
 375         ubifs_assert(!file->private_data);
 376         over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR);
 377         if (over)
 378             return 0;
 379         file->f_pos = 1;
 380     }
 381
 382     if (file->f_pos == 1) {
 383         ubifs_assert(!file->private_data);
 384         over = filldir(dirent, "..", 2, 1,
 385                    parent_ino(file->f_path.dentry), DT_DIR);
 386         if (over)
 387             return 0;
 388
 389         /* Find the first entry in TNC and save it */
 390         lowest_dent_key(c, &key, dir->i_ino);
 391         nm.name = NULL;
 392         dent = ubifs_tnc_next_ent(c, &key, &nm);
 393         if (IS_ERR(dent)) {
 394             err = PTR_ERR(dent);
 395             goto out;
 396         }
 397
 398         file->f_pos = key_hash_flash(c, &dent->key);
 399         file->private_data = dent;
 400     }
 401
 402     dent = file->private_data;
 403     if (!dent) {
 404         /*
 405          * The directory was seek'ed to and is now readdir'ed.
 406          * Find the entry corresponding to @file->f_pos or the
 407          * closest one.
 408          */
 409         dent_key_init_hash(c, &key, dir->i_ino, file->f_pos);
 410         nm.name = NULL;
 411         dent = ubifs_tnc_next_ent(c, &key, &nm);
 412         if (IS_ERR(dent)) {
 413             err = PTR_ERR(dent);
 414             goto out;
 415         }
 416         file->f_pos = key_hash_flash(c, &dent->key);
 417         file->private_data = dent;
 418     }
 419
 420     while (1) {
 421         dbg_gen("feed '%s', ino %llu, new f_pos %#x",
 422             dent->name, (unsigned long long)le64_to_cpu(dent->inum),
 423             key_hash_flash(c, &dent->key));
 424         ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
 425                  ubifs_inode(dir)->creat_sqnum);
 426
 427         nm.len = le16_to_cpu(dent->nlen);
 428         over = filldir(dirent, dent->name, nm.len, file->f_pos,
 429                    le64_to_cpu(dent->inum),
 430                    vfs_dent_type(dent->type));
 431         if (over)
 432             return 0;
 433
 434         /* Switch to the next entry */
 435         key_read(c, &dent->key, &key);
 436         nm.name = dent->name;
 437         dent = ubifs_tnc_next_ent(c, &key, &nm);
 438         if (IS_ERR(dent)) {
 439             err = PTR_ERR(dent);
 440             goto out;
 441         }
 442
 443         kfree(file->private_data);
 444         file->f_pos = key_hash_flash(c, &dent->key);
 445         file->private_data = dent;
 446         cond_resched();
 447     }
 448
 449 out:
 450     if (err != -ENOENT) {
 451         ubifs_err("cannot find next direntry, error %d", err);
 452         return err;
 453     }
 454
 455     kfree(file->private_data);
 456     file->private_data = NULL;
 457     file->f_pos = 2;
 458     return 0;
 459 }

ubifs_readdir 读取目录@file下的目录项,内容放入@dirent,每读取一个目录项,由filldir填充@dirent,具体读取多少,由filldir的返回值决定
ubifs_readdir的问题是offset并不像传统文件系统的offset一样,因为ubifs的目录项并不是顺序排放的,dentry node没有offset,而是由key来决定在父目录中的排序位置。
从代码中可以看到,只有"."和".."目录项offset是传统的位置,其他目录项的offset就是名字的hash值
374 ~ 387 读取. 和..目录项
389 ~ 399 读取第一个目录项
403 ~ 418 由于读取的offset并不是常规的offset, 所以找一个最接近这个offset的目录项
420 ~477 ubifs_tnc_next_ent依次遍历所有的entry,直到filldir请求结束遍历

 461 /* If a directory is seeked, we have to free saved readdir() state */
 462 static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int origin)
 463 {
 464     kfree(file->private_data);
 465     file->private_data = NULL;
 466     return generic_file_llseek(file, offset, origin);
 467 }
465 由于ubifs借用来file->private_data来模拟offset,所以llseek要先清空private_data,具体参见ubifs_readdir

static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
 504               struct dentry *dentry)
 505 {
 506     struct ubifs_info *c = dir->i_sb->s_fs_info;
 507     struct inode *inode = old_dentry->d_inode;
 508     struct ubifs_inode *ui = ubifs_inode(inode);
 509     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 510     int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 511     struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
 512                 .dirtied_ino_d = ALIGN(ui->data_len, 8) };
 513
 514     /*
 515      * Budget request settings: new direntry, changing the target inode,
 516      * changing the parent inode.
 517      */
 518
 519     dbg_gen("dent '%.*s' to ino %lu (nlink %d) in dir ino %lu",
 520         dentry->d_name.len, dentry->d_name.name, inode->i_ino,
 521         inode->i_nlink, dir->i_ino);
 522     ubifs_assert(mutex_is_locked(&dir->i_mutex));
 523     ubifs_assert(mutex_is_locked(&inode->i_mutex));
 524
 525     /*
 526      * Return -ENOENT if we've raced with unlink and i_nlink is 0.  Doing
 527      * otherwise has the potential to corrupt the orphan inode list.
 528      *
 529      * Indeed, consider a scenario when 'vfs_link(dirA/fileA)' and
 530      * 'vfs_unlink(dirA/fileA, dirB/fileB)' race. 'vfs_link()' does not
 531      * lock 'dirA->i_mutex', so this is possible. Both of the functions
 532      * lock 'fileA->i_mutex' though. Suppose 'vfs_unlink()' wins, and takes
 533      * 'fileA->i_mutex' mutex first. Suppose 'fileA->i_nlink' is 1. In this
 534      * case 'ubifs_unlink()' will drop the last reference, and put 'inodeA'
 535      * to the list of orphans. After this, 'vfs_link()' will link
 536      * 'dirB/fileB' to 'inodeA'. This is a problem because, for example,
 537      * the subsequent 'vfs_unlink(dirB/fileB)' will add the same inode
 538      * to the list of orphans.
 539      */
 540      if (inode->i_nlink == 0)
 541          return -ENOENT;
 542
 543     err = dbg_check_synced_i_size(inode);
 544     if (err)
 545         return err;
 546
 547     err = ubifs_budget_space(c, &req);
 548     if (err)
 549         return err;
 550
 551     lock_2_inodes(dir, inode);
 552     inc_nlink(inode);
 554     inode->i_ctime = ubifs_current_time(inode);
 555     dir->i_size += sz_change;
 556     dir_ui->ui_size = dir->i_size;
 557     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 558     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
 559     if (err)
 560         goto out_cancel;
 561     unlock_2_inodes(dir, inode);
 562
 563     ubifs_release_budget(c, &req);
 564     d_instantiate(dentry, inode);
 565     return 0;
 566
 567 out_cancel:
 568     dir->i_size -= sz_change;
 569     dir_ui->ui_size = dir->i_size;
 570     drop_nlink(inode);
 571     unlock_2_inodes(dir, inode);
 572     ubifs_release_budget(c, &req);
 573     iput(inode);
 574     return err;
 575 }

ubifs_link用来把@old_dentry对应的文件,链接到@dentry这个目录项上,是文件系统硬链接的底层实现
ubifs_link和ubifs_create类似,都会修改parent inode,增加一个新的目录项。
ubifs_link不需要创建inode,因为inode已经存在了,但是需要修改inode的link和修改inode的ctime

552 增加inode的nlink,因为一个新的dentry指向了这个文件

577 static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
 578 {
 579     struct ubifs_info *c = dir->i_sb->s_fs_info;
 580     struct inode *inode = dentry->d_inode;
 581     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 582     int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 583     int err, budgeted = 1;
 584     struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
 585
 586     /*
 587      * Budget request settings: deletion direntry, deletion inode (+1 for
 588      * @dirtied_ino), changing the parent directory inode. If budgeting
 589      * fails, go ahead anyway because we have extra space reserved for
 590      * deletions.
 591      */
 592
 593     dbg_gen("dent '%.*s' from ino %lu (nlink %d) in dir ino %lu",
 594         dentry->d_name.len, dentry->d_name.name, inode->i_ino,
 595         inode->i_nlink, dir->i_ino);
 596     ubifs_assert(mutex_is_locked(&dir->i_mutex));
 597     ubifs_assert(mutex_is_locked(&inode->i_mutex));
 598     err = dbg_check_synced_i_size(inode);
 599     if (err)
 600         return err;
 601
 602     err = ubifs_budget_space(c, &req);
 603     if (err) {
 604         if (err != -ENOSPC)
 605             return err;
 606         budgeted = 0;
 607     }
 608
 609     lock_2_inodes(dir, inode);
 610     inode->i_ctime = ubifs_current_time(dir);
 611     drop_nlink(inode);
 612     dir->i_size -= sz_change;
 613     dir_ui->ui_size = dir->i_size;
 614     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 615     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
 616     if (err)
 617         goto out_cancel;
 618     unlock_2_inodes(dir, inode);
 619
 620     if (budgeted)
 621         ubifs_release_budget(c, &req);
 622     else {
 623         /* We've deleted something - clean the "no space" flags */
 624         c->nospace = c->nospace_rp = 0;
 625         smp_wmb();
 626     }
 627     return 0;
 628
 629 out_cancel:
 630     dir->i_size += sz_change;
 631     dir_ui->ui_size = dir->i_size;
 632     inc_nlink(inode);
 633     unlock_2_inodes(dir, inode);
 634     if (budgeted)
 635         ubifs_release_budget(c, &req);
 636     return err;
 637 }

ubifs_unlink是ubifs_link的逆操作,把@dentry目录项从@dir中删除掉
这个操作涉及到一个目录项的删除,以及parent inode和child inode的修改
611 由于少了一个到child inode的目录项, 减少child inode的链接数
612 由于删除了目录项,父目录inode的尺寸减去目录项node的尺寸
615 ubifs_jnl_update第五个参数1 用来指定对目录项的删除

 639 /**
 640  * check_dir_empty - check if a directory is empty or not.
 641  * @c: UBIFS file-system description object
 642  * @dir: VFS inode object of the directory to check
 643  *
 644  * This function checks if directory @dir is empty. Returns zero if the
 645  * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes
 646  * in case of of errors.
 647  */
 648 static int check_dir_empty(struct ubifs_info *c, struct inode *dir)
 649 {
 650     struct qstr nm = { .name = NULL };
 651     struct ubifs_dent_node *dent;
 652     union ubifs_key key;
 653     int err;
 654
 655     lowest_dent_key(c, &key, dir->i_ino);
 656     dent = ubifs_tnc_next_ent(c, &key, &nm);
 657     if (IS_ERR(dent)) {
 658         err = PTR_ERR(dent);
 659         if (err == -ENOENT)
 660             err = 0;
 661     } else {
 662         kfree(dent);
 663         err = -ENOTEMPTY;
 664     }
 665     return err;
 666 }
这个函数检测给定的目录@dir是否为空
655 首先计算出这个目录下最小的dentry key
656 ubifs_tnc_next_ent 找到并返回@key后面的一个目录项,如果不存在,说明没有目录项,否则有

668 static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
 669 {
 670     struct ubifs_info *c = dir->i_sb->s_fs_info;
 671     struct inode *inode = dentry->d_inode;
 672     int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 673     int err, budgeted = 1;
 674     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 675     struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
 676
 677     /*
 678      * Budget request settings: deletion direntry, deletion inode and
 679      * changing the parent inode. If budgeting fails, go ahead anyway
 680      * because we have extra space reserved for deletions.
 681      */
 682
 683     dbg_gen("directory '%.*s', ino %lu in dir ino %lu", dentry->d_name.len,
 684         dentry->d_name.name, inode->i_ino, dir->i_ino);
 685     ubifs_assert(mutex_is_locked(&dir->i_mutex));
 686     ubifs_assert(mutex_is_locked(&inode->i_mutex));
 687     err = check_dir_empty(c, dentry->d_inode);
 688     if (err)
 689         return err;
 690
 691     err = ubifs_budget_space(c, &req);
 692     if (err) {
 693         if (err != -ENOSPC)
 694             return err;
 695         budgeted = 0;
 696     }
 697
 698     lock_2_inodes(dir, inode);
 699     inode->i_ctime = ubifs_current_time(dir);
 700     clear_nlink(inode);
 701     drop_nlink(dir);
 702     dir->i_size -= sz_change;
 703     dir_ui->ui_size = dir->i_size;
 704     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 705     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
 706     if (err)
 707         goto out_cancel;
708     unlock_2_inodes(dir, inode);
 709
 710     if (budgeted)
 711         ubifs_release_budget(c, &req);
 712     else {
 713         /* We've deleted something - clean the "no space" flags */
 714         c->nospace = c->nospace_rp = 0;
 715         smp_wmb();
 716     }
 717     return 0;
 718
 719 out_cancel:
 720     dir->i_size += sz_change;
 721     dir_ui->ui_size = dir->i_size;
 722     inc_nlink(dir);
 723     inc_nlink(inode);
 724     inc_nlink(inode);
 725     unlock_2_inodes(dir, inode);
 726     if (budgeted)
 727         ubifs_release_budget(c, &req);
 728     return err;
 729 }
ubifs_rmdir删除@dir下的目录项@dentry,这个函数和ubifs_unlink的区别是前者删除的是子目录,后者删除的是非子目录
677 ~ 681 该操作涉及到删除目录项,删除子目录的inode,更改父目录的inode
687 判断待删除目录是否包含除"." ".."外的目录项,非空目录是不能删除的。
700 clear_nlink直接设置inode的nlink为0,事实上我觉得使用drop_nlink也可
701 减少父目录inode的nlink

731 static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 732 {
 733     struct inode *inode;
 734     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 735     struct ubifs_info *c = dir->i_sb->s_fs_info;
 736     int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 737     struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
 738
 739     /*
 740      * Budget request settings: new inode, new direntry and changing parent
 741      * directory inode.
 742      */
 743
 744     dbg_gen("dent '%.*s', mode %#x in dir ino %lu",
 745         dentry->d_name.len, dentry->d_name.name, mode, dir->i_ino);
 746
 747     err = ubifs_budget_space(c, &req);
 748     if (err)
 749         return err;
 750
 751     inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
 752     if (IS_ERR(inode)) {
 753         err = PTR_ERR(inode);
 754         goto out_budg;
 755     }
 756
 757     mutex_lock(&dir_ui->ui_mutex);
 758     insert_inode_hash(inode);
 759     inc_nlink(inode);
 760     inc_nlink(dir);
 761     dir->i_size += sz_change;
 762     dir_ui->ui_size = dir->i_size;
 763     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 764     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
 765     if (err) {
 766         ubifs_err("cannot create directory, error %d", err);
 767         goto out_cancel;
 768     }
 769     mutex_unlock(&dir_ui->ui_mutex);
 770
 771     ubifs_release_budget(c, &req);
 772     d_instantiate(dentry, inode);
 773     return 0;
 774
 775 out_cancel:
 776     dir->i_size -= sz_change;
 777     dir_ui->ui_size = dir->i_size;
 778     drop_nlink(dir);
 779     mutex_unlock(&dir_ui->ui_mutex);
 780     make_bad_inode(inode);
 781     iput(inode);
 782 out_budg:
 783     ubifs_release_budget(c, &req);
 784     return err;
 785 }
ubifs_mkdir 在父目录@dir下创建@dentry对应的子目录,该函数需要分配子目录的inode
ubifs涉及到新目录项的添加,子inode的创建以及父inode的修改
751 为子目录创建inode
758 把新创建的inode加到hash table中
759 ~ 760 增加父子inode的nlink
772 把dentry和新创建的inode关联起来

787 static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
 788                int mode, dev_t rdev)
 789 {
 790     struct inode *inode;
 791     struct ubifs_inode *ui;
 792     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 793     struct ubifs_info *c = dir->i_sb->s_fs_info;
 794     union ubifs_dev_desc *dev = NULL;
 795     int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 796     int err, devlen = 0;
 797     struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 798                     .new_ino_d = ALIGN(devlen, 8),
 799                     .dirtied_ino = 1 };
 800
 801     /*
 802      * Budget request settings: new inode, new direntry and changing parent
 803      * directory inode.
 804      */
 805
 806     dbg_gen("dent '%.*s' in dir ino %lu",
 807         dentry->d_name.len, dentry->d_name.name, dir->i_ino);
 808
 809     if (!new_valid_dev(rdev))
 810         return -EINVAL;
 811
 812     if (S_ISBLK(mode) || S_ISCHR(mode)) {
 813         dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
 814         if (!dev)
 815             return -ENOMEM;
 816         devlen = ubifs_encode_dev(dev, rdev);
 817     }
 818
 819     err = ubifs_budget_space(c, &req);
 820     if (err) {
 821         kfree(dev);
 822         return err;
 823     }
 824
 825     inode = ubifs_new_inode(c, dir, mode);
 826     if (IS_ERR(inode)) {
 827         kfree(dev);
 828         err = PTR_ERR(inode);
 829         goto out_budg;
 830     }
 831
 832     init_special_inode(inode, inode->i_mode, rdev);
 833     inode->i_size = ubifs_inode(inode)->ui_size = devlen;
 834     ui = ubifs_inode(inode);
 835     ui->data = dev;
 836     ui->data_len = devlen;
 837
 838     mutex_lock(&dir_ui->ui_mutex);
 839     dir->i_size += sz_change;
 840     dir_ui->ui_size = dir->i_size;
 841     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 842     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
 843     if (err)
 844         goto out_cancel;
 845     mutex_unlock(&dir_ui->ui_mutex);
 846
 847     ubifs_release_budget(c, &req);
 848     insert_inode_hash(inode);
 849     d_instantiate(dentry, inode);
 850     return 0;
 851
 852 out_cancel:
 853     dir->i_size -= sz_change;
 854     dir_ui->ui_size = dir->i_size;
 855     mutex_unlock(&dir_ui->ui_mutex);
 856     make_bad_inode(inode);
 857     iput(inode);
 858 out_budg:
 859     ubifs_release_budget(c, &req);
 860     return err;
 861 }
ubifs_mknod和ubifs_mkdir非常类似,只是前者创建的是设备节点而后者创建的是子目录,ubifs_mknod不会增加父母录的连接数

 863 static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
 864              const char *symname)
 865 {
 866     struct inode *inode;
 867     struct ubifs_inode *ui;
 868     struct ubifs_inode *dir_ui = ubifs_inode(dir);
 869     struct ubifs_info *c = dir->i_sb->s_fs_info;
 870     int err, len = strlen(symname);
 871     int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
 872     struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
 873                     .new_ino_d = ALIGN(len, 8),
 874                     .dirtied_ino = 1 };
 875
 876     /*
 877      * Budget request settings: new inode, new direntry and changing parent
 878      * directory inode.
 879      */
 880
 881     dbg_gen("dent '%.*s', target '%s' in dir ino %lu", dentry->d_name.len,
 882         dentry->d_name.name, symname, dir->i_ino);
 883
 884     if (len > UBIFS_MAX_INO_DATA)
 885         return -ENAMETOOLONG;
 886
 887     err = ubifs_budget_space(c, &req);
 888     if (err)
 889         return err;
 890
 891     inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
 892     if (IS_ERR(inode)) {
 893         err = PTR_ERR(inode);
 894         goto out_budg;
 895     }
 896
 897     ui = ubifs_inode(inode);
 898     ui->data = kmalloc(len + 1, GFP_NOFS);
 899     if (!ui->data) {
 900         err = -ENOMEM;
 901         goto out_inode;
 902     }
 903
 904     memcpy(ui->data, symname, len);
 905     ((char *)ui->data)[len] = '\0';
 906     /*
 907      * The terminating zero byte is not written to the flash media and it
 908      * is put just to make later in-memory string processing simpler. Thus,
 909      * data length is @len, not @len + %1.
 910      */
 911     ui->data_len = len;
 912     inode->i_size = ubifs_inode(inode)->ui_size = len;
 913
 914     mutex_lock(&dir_ui->ui_mutex);
 915     dir->i_size += sz_change;
 916     dir_ui->ui_size = dir->i_size;
 917     dir->i_mtime = dir->i_ctime = inode->i_ctime;
 918     err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0);
 919     if (err)
 920         goto out_cancel;
 921     mutex_unlock(&dir_ui->ui_mutex);
 922
 923     ubifs_release_budget(c, &req);
 924     insert_inode_hash(inode);
 925     d_instantiate(dentry, inode);
 926     return 0;
 927
 928 out_cancel:
 929     dir->i_size -= sz_change;
 930     dir_ui->ui_size = dir->i_size;
 931     mutex_unlock(&dir_ui->ui_mutex);
 932 out_inode:
 933     make_bad_inode(inode);
 934     iput(inode);
 935 out_budg:
 936     ubifs_release_budget(c, &req);
 937     return err;
 938 }
ubifs_symlink在父目录@dir下增加@dentry指定的目录项,这个函数需要创建一个新的inode,增加一个新的目录项,修改parent inode
新创建的inode数据内容为@symname指定的路径,放在ui->data内,由ui->data_len指定长度
该函数不增加parent inode和child inode的nlink
884 该行限制了符号链接的最大长度不能超过UBIFS_MAX_INO_DATA,注意这只是存储方面的限制,对symlink名最大长度的限制来自多方面

979 static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
 980             struct inode *new_dir, struct dentry *new_dentry)
 981 {
 982     struct ubifs_info *c = old_dir->i_sb->s_fs_info;
 983     struct inode *old_inode = old_dentry->d_inode;
 984     struct inode *new_inode = new_dentry->d_inode;
 985     struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode);
 986     int err, release, sync = 0, move = (new_dir != old_dir);
 987     int is_dir = S_ISDIR(old_inode->i_mode);
 988     int unlink = !!new_inode;
 989     int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
 990     int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
 991     struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
 992                     .dirtied_ino = 3 };
 993     struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
 994             .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
 995     struct timespec time;
 996
 997     /*
 998      * Budget request settings: deletion direntry, new direntry, removing
 999      * the old inode, and changing old and new parent directory inodes.
1000      *
1001      * However, this operation also marks the target inode as dirty and
1002      * does not write it, so we allocate budget for the target inode
1003      * separately.
1004      */
1005
1006     dbg_gen("dent '%.*s' ino %lu in dir ino %lu to dent '%.*s' in "
1007         "dir ino %lu", old_dentry->d_name.len, old_dentry->d_name.name,
1008         old_inode->i_ino, old_dir->i_ino, new_dentry->d_name.len,
1009         new_dentry->d_name.name, new_dir->i_ino);
1010     ubifs_assert(mutex_is_locked(&old_dir->i_mutex));
1011     ubifs_assert(mutex_is_locked(&new_dir->i_mutex));
1012     if (unlink)
1013         ubifs_assert(mutex_is_locked(&new_inode->i_mutex));
1014
1015
1016     if (unlink && is_dir) {
1017         err = check_dir_empty(c, new_inode);
1018         if (err)
1019             return err;
1020     }
1021
1022     err = ubifs_budget_space(c, &req);
1023     if (err)
1024         return err;
1025     err = ubifs_budget_space(c, &ino_req);
1026     if (err) {
1027         ubifs_release_budget(c, &req);
1028         return err;
1029     }
1030
1031     lock_3_inodes(old_dir, new_dir, new_inode);
1032
1033     /*
1034      * Like most other Unix systems, set the @i_ctime for inodes on a
1035      * rename.
1036      */
1037     time = ubifs_current_time(old_dir);
1038     old_inode->i_ctime = time;
1039
1040     /* We must adjust parent link count when renaming directories */
1041     if (is_dir) {
1042         if (move) {
1043             /*
1044              * @old_dir loses a link because we are moving
1045              * @old_inode to a different directory.
1046              */
1047             drop_nlink(old_dir);
1048             /*
1049              * @new_dir only gains a link if we are not also
1050              * overwriting an existing directory.
1051              */
1052             if (!unlink)
1053                 inc_nlink(new_dir);
1054         } else {
1055             /*
1056              * @old_inode is not moving to a different directory,
1057              * but @old_dir still loses a link if we are
1058              * overwriting an existing directory.
1059              */
1060             if (unlink)
1061                 drop_nlink(old_dir);
1062         }
1063     }
1064
1065     old_dir->i_size -= old_sz;
1066     ubifs_inode(old_dir)->ui_size = old_dir->i_size;
1067     old_dir->i_mtime = old_dir->i_ctime = time;
1068     new_dir->i_mtime = new_dir->i_ctime = time;
1069
1070     /*
1071      * And finally, if we unlinked a direntry which happened to have the
1072      * same name as the moved direntry, we have to decrement @i_nlink of
1073      * the unlinked inode and change its ctime.
1074      */
1075     if (unlink) {
1076         /*
1077          * Directories cannot have hard-links, so if this is a
1078          * directory, decrement its @i_nlink twice because an empty
1079          * directory has @i_nlink 2.
1080          */
1081         if (is_dir)
1082             drop_nlink(new_inode);
1083         new_inode->i_ctime = time;
1084         drop_nlink(new_inode);
1085     } else {
1086         new_dir->i_size += new_sz;
1087         ubifs_inode(new_dir)->ui_size = new_dir->i_size;
1088     }
1089
1090     /*
1091      * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode
1092      * is dirty, because this will be done later on at the end of
1093      * 'ubifs_rename()'.
1094      */
1095     if (IS_SYNC(old_inode)) {
1096         sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
1097         if (unlink && IS_SYNC(new_inode))
1098             sync = 1;
1099     }
1100     err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry,
1101                    sync);
1102     if (err)
1103         goto out_cancel;
1104
1105     unlock_3_inodes(old_dir, new_dir, new_inode);
1106     ubifs_release_budget(c, &req);
1107
1108     mutex_lock(&old_inode_ui->ui_mutex);
1109     release = old_inode_ui->dirty;
1110     mark_inode_dirty_sync(old_inode);
1111     mutex_unlock(&old_inode_ui->ui_mutex);
1112
1113     if (release)
1114         ubifs_release_budget(c, &ino_req);
1115     if (IS_SYNC(old_inode))
1116         err = old_inode->i_sb->s_op->write_inode(old_inode, NULL);
1117     return err;
1118
1119 out_cancel:
1120     if (unlink) {
1121         if (is_dir)
1122             inc_nlink(new_inode);
1123         inc_nlink(new_inode);
1124     } else {
1125         new_dir->i_size -= new_sz;
1126         ubifs_inode(new_dir)->ui_size = new_dir->i_size;
1127     }
1128     old_dir->i_size += old_sz;
1129     ubifs_inode(old_dir)->ui_size = old_dir->i_size;
1130     if (is_dir) {
1131         if (move) {
1132             inc_nlink(old_dir);
1133             if (!unlink)
1134                 drop_nlink(new_dir);
1135         } else {
1136             if (unlink)
1137                 inc_nlink(old_dir);
1138         }
1139     }
1140     unlock_3_inodes(old_dir, new_dir, new_inode);
1141     ubifs_release_budget(c, &ino_req);
1142     ubifs_release_budget(c, &req);
1143     return err;
1144 }

ubifs_rename 重命名@old_dentry为@new_dentry,@old_dir为原目录,@new_dir为新目录
注意@new_dentry可能在改名前就对应着一个文件或目录,因此改名后相当于减少了这个inode的nlink

984 new_inode可能为空或者不为空,为空表明这个文件名原本就不存在,处理起来要简单一些;不为空,表明这个文件名原来就存在,那么rename会覆盖掉@new_dentry原来指向的文件。
1016 ~ 1020 ubifs要求@new_dentry不能对应一个不为空的目录,即rename禁止非空目录覆盖
1041 ~ 1042 is_dir表示@new_dentry是一个目录,move表明old_dir new_dir不是相同的目录(跨目录rename)
1043 ~ 1061 处理nlink
1065 ~ 1068 修改@old_dir的尺寸
1070 ~ 1088 如果@new_dentry本来就对应着一个文件或目录,如果是目录nlink -= 2来释放这个目录inode(前面已经确保这个目录肯定为空);如果是文件,只需-1

rename 看起来稍微复杂,主要有以下几种分支情况需要仔细处理
1. old_dir new_dir是不是同一个目录
2. new_dentry, old_dentry是不是同一个路径
3. new_dentry old_dentry是目录还是文件

1146 int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1147           struct kstat *stat)
1148 {               
1149     loff_t size;
1150     struct inode *inode = dentry->d_inode;
1151     struct ubifs_inode *ui = ubifs_inode(inode);
1152
1153     mutex_lock(&ui->ui_mutex);
1154     stat->dev = inode->i_sb->s_dev;
1155     stat->ino = inode->i_ino;
1156     stat->mode = inode->i_mode;
1157     stat->nlink = inode->i_nlink;
1158     stat->uid = inode->i_uid;
1159     stat->gid = inode->i_gid;
1160     stat->rdev = inode->i_rdev;
1161     stat->atime = inode->i_atime;
1162     stat->mtime = inode->i_mtime;
1163     stat->ctime = inode->i_ctime;
1164     stat->blksize = UBIFS_BLOCK_SIZE;
1165     stat->size = ui->ui_size;
1166
1167     /*
1168      * Unfortunately, the 'stat()' system call was designed for block
1169      * device based file systems, and it is not appropriate for UBIFS,
1170      * because UBIFS does not have notion of "block". For example, it is
1171      * difficult to tell how many block a directory takes - it actually
1172      * takes less than 300 bytes, but we have to round it to block size,
1173      * which introduces large mistake. This makes utilities like 'du' to
1174      * report completely senseless numbers. This is the reason why UBIFS
1175      * goes the same way as JFFS2 - it reports zero blocks for everything
1176      * but regular files, which makes more sense than reporting completely
1177      * wrong sizes.
1178      */
1179     if (S_ISREG(inode->i_mode)) {
1180         size = ui->xattr_size;
1181         size += stat->size;
1182         size = ALIGN(size, UBIFS_BLOCK_SIZE);
1183         /*
1184          * Note, user-space expects 512-byte blocks count irrespectively
1185          * of what was reported in @stat->size.
1186          */
1187         stat->blocks = size >> 9;
1188     } else
1189         stat->blocks = 0;
1190     mutex_unlock(&ui->ui_mutex);
1191     return 0;
1192 }
这个函数需要注意1168行开始的代码注释部分,ubifs不像传统的block filesystem,因此在汇报stat->blocks时有些问题,需要应用程序小心使用stat在ubifs文件系统的返回值

抱歉!评论已关闭.