void minix_free_inode(struct inode * inode) { struct super_block *sb = inode->i_sb; struct minix_sb_info *sbi = minix_sb(inode->i_sb); struct buffer_head *bh; int k = sb->s_blocksize_bits + 3; unsigned long ino, bit; ino = inode->i_ino; if (ino < 1 || ino > sbi->s_ninodes) { ; return; } bit = ino & ((1<<k) - 1); ino >>= k; if (ino >= sbi->s_imap_blocks) { ; return; } minix_clear_inode(inode); /* clear on-disk copy */ bh = sbi->s_imap[ino]; spin_lock(&bitmap_lock); if (!minix_test_and_clear_bit(bit, bh->b_data)) ; spin_unlock(&bitmap_lock); mark_buffer_dirty(bh); }
int minix_new_block(struct inode * inode) { struct minix_sb_info *sbi = minix_sb(inode->i_sb); int bits_per_zone = 8 * inode->i_sb->s_blocksize; int i; for (i = 0; i < sbi->s_zmap_blocks; i++) { struct buffer_head *bh = sbi->s_zmap[i]; int j; spin_lock(&bitmap_lock); j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); if (j < bits_per_zone) { minix_set_bit(j, bh->b_data); spin_unlock(&bitmap_lock); mark_buffer_dirty(bh); j += i * bits_per_zone + sbi->s_firstdatazone-1; if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) break; return j; } spin_unlock(&bitmap_lock); } return 0; }
unsigned long minix_count_free_inodes(struct super_block *sb) { struct minix_sb_info *sbi = minix_sb(sb); u32 bits = sbi->s_ninodes + 1; return count_free(sbi->s_imap, sb->s_blocksize, bits); }
void minix_free_block(struct inode *inode, unsigned long block) { struct super_block *sb = inode->i_sb; struct minix_sb_info *sbi = minix_sb(sb); struct buffer_head *bh; int k = sb->s_blocksize_bits + 3; unsigned long bit, zone; if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) { printk("Trying to free block not in datazone\n"); return; } zone = block - sbi->s_firstdatazone + 1; bit = zone & ((1<<k) - 1); zone >>= k; if (zone >= sbi->s_zmap_blocks) { printk("minix_free_block: nonexistent bitmap buffer\n"); return; } bh = sbi->s_zmap[zone]; spin_lock(&bitmap_lock); if (!minix_test_and_clear_bit(bit, bh->b_data)) printk("minix_free_block (%s:%lu): bit already cleared\n", sb->s_id, block); spin_unlock(&bitmap_lock); mark_buffer_dirty(bh); return; }
void minix_free_inode(struct inode * inode) { struct super_block *sb = inode->i_sb; struct minix_sb_info *sbi = minix_sb(inode->i_sb); struct buffer_head *bh; int k = sb->s_blocksize_bits + 3; unsigned long ino, bit; ino = inode->i_ino; if (ino < 1 || ino > sbi->s_ninodes) { printk("minix_free_inode: inode 0 or nonexistent inode\n"); return; } bit = ino & ((1<<k) - 1); ino >>= k; if (ino >= sbi->s_imap_blocks) { printk("minix_free_inode: nonexistent imap in superblock\n"); return; } minix_clear_inode(inode); /* */ bh = sbi->s_imap[ino]; spin_lock(&bitmap_lock); if (!minix_test_and_clear_bit(bit, bh->b_data)) printk("minix_free_inode: bit %lu already cleared\n", bit); spin_unlock(&bitmap_lock); mark_buffer_dirty(bh); }
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; char b[BDEVNAME_SIZE]; if (block < 0) { // printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", ; } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { if (printk_ratelimit()) // printk("MINIX-fs: block_to_path: " // "block %ld too big on dev %s\n", ; } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 512) { offsets[n++] = 7; offsets[n++] = block; } else { block -= 512; offsets[n++] = 8; offsets[n++] = block>>9; offsets[n++] = block & 511; } return n; }
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; char b[BDEVNAME_SIZE]; struct super_block *sb = inode->i_sb; if (block < 0) { printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", block, bdevname(sb->s_bdev, b)); } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) { if (printk_ratelimit()) printk("MINIX-fs: block_to_path: " "block %ld too big on dev %s\n", block, bdevname(sb->s_bdev, b)); } else if (block < DIRCOUNT) { offsets[n++] = block; } else if ((block -= DIRCOUNT) < INDIRCOUNT(sb)) { offsets[n++] = DIRCOUNT; offsets[n++] = block; } else if ((block -= INDIRCOUNT(sb)) < INDIRCOUNT(sb) * INDIRCOUNT(sb)) { offsets[n++] = DIRCOUNT + 1; offsets[n++] = block / INDIRCOUNT(sb); offsets[n++] = block % INDIRCOUNT(sb); } else { block -= INDIRCOUNT(sb) * INDIRCOUNT(sb); offsets[n++] = DIRCOUNT + 2; offsets[n++] = (block / INDIRCOUNT(sb)) / INDIRCOUNT(sb); offsets[n++] = (block / INDIRCOUNT(sb)) % INDIRCOUNT(sb); offsets[n++] = block % INDIRCOUNT(sb); } return n; }
struct minix2_inode * minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) { int block; struct minix_sb_info *sbi = minix_sb(sb); struct minix2_inode *p; int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode); *bh = NULL; if (!ino || ino > sbi->s_ninodes) { printk("Bad inode number on dev %s: %ld is out of range\n", sb->s_id, (long)ino); return NULL; } ino--; block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + ino / minix2_inodes_per_block; *bh = sb_bread(sb, block); if (!*bh) { printk("Unable to read inode block\n"); return NULL; } p = (void *)(*bh)->b_data; return p + ino % minix2_inodes_per_block; }
/*return the disk address of an inode (pointer to an inode)*/ struct minix2_inode * minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) /*read an inode from disk, put the block data into buffer_head*/ { int block; struct minix_sb_info *sbi = minix_sb(sb); struct minix2_inode *p; int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode); printk(KERN_INFO "bitmap: minix_V2_raw_inode\n"); *bh = NULL; if (!ino || ino > sbi->s_ninodes) { printk("Bad inode number on dev %s: %ld is out of range\n", sb->s_id, (long)ino); return NULL; } ino--; block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + ino / minix2_inodes_per_block; /*get the block number (on disk) that contains the inode*/ *bh = sb_bread(sb, block); /*read the block by sb_read(), value is put into bh buffer_head*/ if (!*bh) { printk("Unable to read inode block\n"); return NULL; } p = (void *)(*bh)->b_data;/*address of block contain the seeking inode*/ return p + ino % minix2_inodes_per_block; }
static int minix_remount (struct super_block * sb, int * flags, char * data) { struct minix_sb_info * sbi = minix_sb(sb); struct minix_super_block * ms; ms = sbi->s_ms; if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) return 0; if (*flags & MS_RDONLY) { if (ms->s_state & MINIX_VALID_FS || !(sbi->s_mount_state & MINIX_VALID_FS)) return 0; /* Mounting a rw partition read-only. */ if (sbi->s_version != MINIX_V3) ms->s_state = sbi->s_mount_state; mark_buffer_dirty(sbi->s_sbh); } else { /* Mount a partition which is read-only, read-write. */ if (sbi->s_version != MINIX_V3) { sbi->s_mount_state = ms->s_state; ms->s_state &= ~MINIX_VALID_FS; } else { sbi->s_mount_state = MINIX_VALID_FS; } mark_buffer_dirty(sbi->s_sbh); if (!(sbi->s_mount_state & MINIX_VALID_FS)) printk("MINIX-fs warning: remounting unchecked fs, " "running fsck is recommended\n"); else if ((sbi->s_mount_state & MINIX_ERROR_FS)) printk("MINIX-fs warning: remounting fs with errors, " "running fsck is recommended\n"); } return 0; }
unsigned long minix_count_free_blocks(struct super_block *sb) { struct minix_sb_info *sbi = minix_sb(sb); u32 bits = sbi->s_nzones - (sbi->s_firstdatazone + 1); return (count_free(sbi->s_zmap, sb->s_blocksize, bits) << sbi->s_log_zone_size); }
struct inode *minix_new_inode(const struct inode *dir, int mode, int *error) { struct super_block *sb = dir->i_sb; struct minix_sb_info *sbi = minix_sb(sb); struct inode *inode = new_inode(sb); struct buffer_head * bh; int bits_per_zone = 8 * sb->s_blocksize; unsigned long j; int i; printk(KERN_INFO "bitmap: minix_new_inode\n"); if (!inode) { *error = -ENOMEM; return NULL; } j = bits_per_zone; bh = NULL; *error = -ENOSPC; spin_lock(&bitmap_lock); for (i = 0; i < sbi->s_imap_blocks; i++) { bh = sbi->s_imap[i]; j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); if (j < bits_per_zone) break; } if (!bh || j >= bits_per_zone) { spin_unlock(&bitmap_lock); iput(inode); return NULL; } if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ spin_unlock(&bitmap_lock); printk("minix_new_inode: bit already set\n"); iput(inode); return NULL; } spin_unlock(&bitmap_lock); mark_buffer_dirty(bh); j += i * bits_per_zone; if (!j || j > sbi->s_ninodes) { iput(inode); return NULL; } inode_init_owner(inode, dir, mode); inode->i_ino = j; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; inode->i_blocks = 0; memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u)); insert_inode_hash(inode); mark_inode_dirty(inode); *error = 0; return inode; }
static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) { struct inode * inode = NULL; ino_t ino; if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) return ERR_PTR(-ENAMETOOLONG); ino = minix_inode_by_name(dentry); if (ino) inode = minix_iget(dir->i_sb, ino); return d_splice_alias(inode, dentry); }
static int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { struct inode *inode = old_dentry->d_inode; if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max) return -EMLINK; inode->i_ctime = CURRENT_TIME_SEC; inc_count(inode); atomic_inc(&inode->i_count); return add_nondir(dentry, inode); }
static int minix_statfs(struct dentry *dentry, struct kstatfs *buf) { struct minix_sb_info *sbi = minix_sb(dentry->d_sb); buf->f_type = dentry->d_sb->s_magic; buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size; buf->f_bfree = minix_count_free_blocks(sbi); buf->f_bavail = buf->f_bfree; buf->f_files = sbi->s_ninodes; buf->f_ffree = minix_count_free_inodes(sbi); buf->f_namelen = sbi->s_namelen; return 0; }
static void unixfs_internal_fini(void* filsys) { unixfs_inodelayer_fini(); struct super_block* sb = (struct super_block*)filsys; if (sb) { struct minix_sb_info* sbi = minix_sb(sb); if (sbi) free(sbi); free(sb); } }
static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode = NULL; ino_t ino; if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) return ERR_PTR(-ENAMETOOLONG); ino = minix_inode_by_name(dentry); if (ino) { inode = minix_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } d_add(dentry, inode); return NULL; }
static int minix_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct minix_sb_info *sbi = minix_sb(sb); u64 id = huge_encode_dev(sb->s_bdev->bd_dev); buf->f_type = sb->s_magic; buf->f_bsize = sb->s_blocksize; buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size; buf->f_bfree = minix_count_free_blocks(sb); buf->f_bavail = buf->f_bfree; buf->f_files = sbi->s_ninodes; buf->f_ffree = minix_count_free_inodes(sb); buf->f_namelen = sbi->s_namelen; buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); return 0; }
static void minix_put_super(struct super_block *sb) { int i; struct minix_sb_info *sbi = minix_sb(sb); if (!(sb->s_flags & MS_RDONLY)) { if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ sbi->s_ms->s_state = sbi->s_mount_state; mark_buffer_dirty(sbi->s_sbh); } for (i = 0; i < sbi->s_imap_blocks; i++) brelse(sbi->s_imap[i]); for (i = 0; i < sbi->s_zmap_blocks; i++) brelse(sbi->s_zmap[i]); brelse (sbi->s_sbh); kfree(sbi->s_imap); sb->s_fs_info = NULL; kfree(sbi); }
static int minix_hash(struct dentry *dentry, struct qstr *qstr) { unsigned long hash; int i; const unsigned char *name; i = minix_sb(dentry->d_inode->i_sb)->s_namelen; if (i >= qstr->len) return 0; /* Truncate the name in place, avoids having to define a compare function. */ qstr->len = i; name = qstr->name; hash = init_name_hash(); while (i--) hash = partial_name_hash(*name++, hash); qstr->hash = end_name_hash(hash); return 0; }
static void minix_put_super(struct super_block *sb) { int i; struct minix_sb_info *sbi = minix_sb(sb); if (!(sb->s_flags & MS_RDONLY)) { sbi->s_ms->s_state = sbi->s_mount_state; mark_buffer_dirty(sbi->s_sbh); } for (i = 0; i < sbi->s_imap_blocks; i++) brelse(sbi->s_imap[i]); for (i = 0; i < sbi->s_zmap_blocks; i++) brelse(sbi->s_zmap[i]); brelse (sbi->s_sbh); kfree(sbi->s_imap); sb->s_fs_info = NULL; kfree(sbi); return; }
static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) { struct inode * inode = NULL; ino_t ino; dentry->d_op = dir->i_sb->s_root->d_op; if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) return ERR_PTR(-ENAMETOOLONG); ino = minix_inode_by_name(dentry); if (ino) { inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); } d_add(dentry, inode); return NULL; }
static int block_to_path(struct inode* inode, long block, int offsets[DEPTH]) { int n = 0; struct super_block* sb = inode->I_sb; if (block < 0) { printk("MINIX-fs: block_to_path: block %ld < 0\n", block); } else if (block >= (minix_sb(inode->I_sb)->s_max_size/sb->s_blocksize)) { if (0) printk("MINIX-fs: block_to_path: block %ld too big\n", block); } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 256) { offsets[n++] = 7; offsets[n++] = block; } else if ((block -= 256) < 256 * 256) { offsets[n++] = 8; offsets[n++] = block >> 8; offsets[n++] = block & 255; } else {
static int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) { struct inode * inode; int err = -EMLINK; if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max) goto out; inc_count(dir); inode = minix_new_inode(dir, &err); if (!inode) goto out_dir; inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; minix_set_inode(inode, 0); inc_count(inode); err = minix_make_empty(inode, dir); if (err) goto out_fail; err = minix_add_link(dentry, inode); if (err) goto out_fail; d_instantiate(dentry, inode); out: return err; out_fail: dec_count(inode); dec_count(inode); iput(inode); out_dir: dec_count(dir); goto out; }
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; if (block < 0) { printk("minix_bmap: block<0\n"); } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { printk("minix_bmap: block>big\n"); } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 512) { offsets[n++] = 7; offsets[n++] = block; } else { block -= 512; offsets[n++] = 8; offsets[n++] = block>>9; offsets[n++] = block & 511; } return n; }
struct minix_inode * minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) { int block; struct minix_sb_info *sbi = minix_sb(sb); struct minix_inode *p; if (!ino || ino > sbi->s_ninodes) { // printk("Bad inode number on dev %s: %ld is out of range\n", ; return NULL; } ino--; block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + ino / MINIX_INODES_PER_BLOCK; *bh = sb_bread(sb, block); if (!*bh) { ; return NULL; } p = (void *)(*bh)->b_data; return p + ino % MINIX_INODES_PER_BLOCK; }
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; char b[BDEVNAME_SIZE]; struct super_block *sb = inode->i_sb; if (block < 0) { printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n", block, bdevname(sb->s_bdev, b)); } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) { if (printk_ratelimit()) printk("MINIX-fs: block_to_path: " "block %ld too big on dev %s\n", block, bdevname(sb->s_bdev, b)); } else if (block < 7) { offsets[n++] = block; } else if ((block -= 7) < 256) { offsets[n++] = 7; offsets[n++] = block; } else if ((block -= 256) < 256*256) { offsets[n++] = 8; offsets[n++] = block>>8; offsets[n++] = block & 255; } else {
static int unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf) { if (parentino == OSXFUSE_ROOTINO) parentino = MINIX_ROOT_INO; stbuf->st_ino = ENOENT; struct inode* dir = unixfs_internal_iget(parentino); if (!dir) return ENOENT; if (!S_ISDIR(dir->I_mode)) { unixfs_internal_iput(dir); return ENOTDIR; } int ret = ENOENT; unsigned long namelen = strlen(name); unsigned long start, n; unsigned long npages = minix_dir_pages(dir); minix3_dirent* de3; minix_dirent* de; char page[PAGE_SIZE]; char* kaddr = NULL; struct super_block* sb = dir->I_sb; struct minix_sb_info* sbi = minix_sb(sb); unsigned chunk_size = sbi->s_dirsize; struct minix_inode_info* minix_inode = minix_i(dir); start = minix_inode->i_dir_start_lookup; if (start >= npages) start = 0; n = start; ino_t found_ino = 0; do { int error = minixfs_get_page(dir, n, page); if (!error) { kaddr = (char*)page; if (INODE_VERSION(dir) == MINIX_V3) { de3 = (minix3_dirent*)kaddr; kaddr += PAGE_CACHE_SIZE - chunk_size; for (; (char*)de3 <= kaddr; de3++) { if (!de3->inode) continue; if (minix_namecompare(namelen, chunk_size, name, de3->name)) { found_ino = de3->inode; goto found; } } } else { de = (minix_dirent*)kaddr; kaddr += PAGE_CACHE_SIZE - chunk_size; for (; (char*)de <= kaddr; de++) { if (!de->inode) continue; if (minix_namecompare(namelen, chunk_size, name, de->name)) { found_ino = de->inode; goto found; } } } } if (++n >= npages) n = 0; } while (n != start); found: if (found_ino) minix_inode->i_dir_start_lookup = n; unixfs_internal_iput(dir); if (found_ino) ret = unixfs_internal_igetattr(found_ino, stbuf); return ret; }
static void* unixfs_internal_init(const char* dmg, uint32_t flags, __unused fs_endian_t fse, char** fsname, char** volname) { int fd = -1; if ((fd = open(dmg, O_RDONLY)) < 0) { perror("open"); return NULL; } int err; struct stat stbuf; struct super_block* sb = (struct super_block*)0; if ((err = fstat(fd, &stbuf)) != 0) { perror("fstat"); goto out; } if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) { err = EINVAL; fprintf(stderr, "%s is not a disk image file\n", dmg); goto out; } if ((err = unixfs_inodelayer_init(sizeof(struct minix_inode_info))) != 0) goto out; sb = minixfs_fill_super(fd, (void*)0, 1 /* silent */); if (!sb) { err = EINVAL; goto out; } struct minix_sb_info* sbi = minix_sb(sb); unixfs = sb; unixfs->s_flags = flags; (void)minixfs_statvfs(sb, &(unixfs->s_statvfs)); unixfs->s_dentsize = 0; snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s %s", unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" : (sbi->s_version == MINIX_V2) ? "V2" : (sbi->s_version == MINIX_V1) ? "V1" : "??"); snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (%s)", unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" : (sbi->s_version == MINIX_V2) ? "V2" : (sbi->s_version == MINIX_V1) ? "V1" : "??"); *fsname = unixfs->s_fsname; *volname = unixfs->s_volname; out: if (err) { if (fd > 0) close(fd); if (sb) { free(sb); sb = NULL; } } return sb; }
static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry) { struct minix_sb_info * info = minix_sb(old_dir->i_sb); struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct page * dir_page = NULL; struct minix_dir_entry * dir_de = NULL; struct page * old_page; struct minix_dir_entry * old_de; int err = -ENOENT; old_de = minix_find_entry(old_dentry, &old_page); if (!old_de) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; dir_de = minix_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { struct page * new_page; struct minix_dir_entry * new_de; err = -ENOTEMPTY; if (dir_de && !minix_empty_dir(new_inode)) goto out_dir; err = -ENOENT; new_de = minix_find_entry(new_dentry, &new_page); if (!new_de) goto out_dir; inc_count(old_inode); minix_set_link(new_de, new_page, old_inode); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) new_inode->i_nlink--; dec_count(new_inode); } else { if (dir_de) { err = -EMLINK; if (new_dir->i_nlink >= info->s_link_max) goto out_dir; } inc_count(old_inode); err = minix_add_link(new_dentry, old_inode); if (err) { dec_count(old_inode); goto out_dir; } if (dir_de) inc_count(new_dir); } minix_delete_entry(old_de, old_page); dec_count(old_inode); if (dir_de) { minix_set_link(dir_de, dir_page, new_dir); dec_count(old_dir); } return 0; out_dir: if (dir_de) { kunmap(dir_page); page_cache_release(dir_page); } out_old: kunmap(old_page); page_cache_release(old_page); out: return err; }