void show_tree_range(struct btree *btree, tuxkey_t start, unsigned count) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } __tux3_dbg("%i level btree at %Li:\n", btree->root.depth, btree->root.block); if (!has_root(btree)) return; struct cursor *cursor = alloc_cursor(btree, 0); if (!cursor) { tux3_err(btree->sb, "out of memory"); return; } if (btree_probe(cursor, start)) { tux3_fs_error(btree->sb, "tell me why!!!"); goto out; } struct buffer_head *buffer; do { buffer = cursor_leafbuf(cursor); assert((btree->ops->leaf_sniff)(btree, bufdata(buffer))); (btree->ops->leaf_dump)(btree, bufdata(buffer)); } while (--count && cursor_advance(cursor)); out: free_cursor(cursor); }
/* Find free atom */ static int get_freeatom(struct inode *atable, atom_t *atom) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct sb *sb = tux_sb(atable->i_sb); atom_t freeatom = sb->freeatom; if (!freeatom) { *atom = sb->atomgen++; return 0; } loff_t next = unatom_dict_read(atable, freeatom); if (next < 0) return next; if (!is_free_unatom(next)) { tux3_fs_error(sb, "something horrible happened"); return -EIO; } *atom = freeatom; sb->freeatom = next & ~UNATOM_FREE_MASK; return 0; }
/* Convert atom to name */ static int unatom(struct inode *atable, atom_t atom, char *name, unsigned size) { if(DEBUG_MODE_K==1) { printf("\t\t\t\t%25s[K] %25s %4d #in\n",__FILE__,__func__,__LINE__); } struct sb *sb = tux_sb(atable->i_sb); struct buffer_head *buffer; int err; loff_t where = unatom_dict_read(atable, atom); if (where < 0) { err = where; goto error; } buffer = blockread(mapping(atable), where >> sb->blockbits); if (!buffer) { err = -EIO; goto error; } tux_dirent *entry = bufdata(buffer) + (where & sb->blockmask); if (entry_atom(entry) != atom) { tux3_fs_error(sb, "atom %x reverse entry broken", atom); err = -EIO; goto error_blockput; } unsigned len = entry->name_len; if (size) { if (len > size) { err = -ERANGE; goto error_blockput; } memcpy(name, entry->name, len); } blockput(buffer); return len; error_blockput: blockput(buffer); error: return err; }
static int __tux3_symlink(struct inode *dir, struct dentry *dentry, struct tux_iattr *iattr, const char *symname) { struct sb *sb = tux_sb(dir->i_sb); struct inode *inode; unsigned len = strlen(symname) + 1; int err, err2; /* FIXME: We want more length? */ if (len > PAGE_CACHE_SIZE) return -ENAMETOOLONG; change_begin(sb); inode = tux_new_inode(dir, iattr, 0); err = PTR_ERR(inode); if (!IS_ERR(inode)) { err = tux_create_dirent(dir, &dentry->d_name, inode); if (!err) { /* FIXME: we may want to initialize symlink earlier */ err = page_symlink(inode, symname, len); if (!err) { d_instantiate(dentry, inode); unlock_new_inode(inode); goto out; } err2 = tux_del_dirent(dir, dentry); if (err2) tux3_fs_error(sb, "Failed to recover dir entry (err %d)", err2); clear_nlink(inode); tux3_mark_inode_dirty(inode); unlock_new_inode(inode); iput(inode); } } out: change_end(sb); return err; }
/* Find free atom */ static int get_freeatom(struct inode *atable, atom_t *atom) { struct sb *sb = tux_sb(atable->i_sb); atom_t freeatom = sb->freeatom; if (!freeatom) { *atom = sb->atomgen++; return 0; } loff_t next = unatom_dict_read(atable, freeatom); if (next < 0) return next; if (!is_free_unatom(next)) { tux3_fs_error(sb, "something horrible happened"); return -EIO; } *atom = freeatom; sb->freeatom = next & ~UNATOM_FREE_MASK; return 0; }
static int tux3_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct tux_iattr iattr = { .uid = current_fsuid(), .gid = current_fsgid(), .mode = S_IFLNK | S_IRWXUGO, }; return __tux3_symlink(dir, dentry, &iattr, symname); } #endif /* !__KERNEL__ */ static int tux3_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct sb *sb = tux_sb(inode->i_sb); change_begin(sb); int err = tux_del_dirent(dir, dentry); if (!err) { tux3_iattrdirty(inode); inode->i_ctime = dir->i_ctime; /* FIXME: we shouldn't write inode for i_nlink = 0? */ inode_dec_link_count(inode); } change_end(sb); return err; } static int tux3_rmdir(struct inode *dir, struct dentry *dentry) { struct sb *sb = tux_sb(dir->i_sb); struct inode *inode = dentry->d_inode; int err = tux_dir_is_empty(inode); if (!err) { change_begin(sb); err = tux_del_dirent(dir, dentry); if (!err) { tux3_iattrdirty(inode); inode->i_ctime = dir->i_ctime; /* FIXME: we need to do this for POSIX? */ /* inode->i_size = 0; */ clear_nlink(inode); tux3_mark_inode_dirty_sync(inode); inode_dec_link_count(dir); } change_end(sb); } return err; } static int tux3_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct sb *sb = tux_sb(old_inode->i_sb); struct buffer_head *old_buffer, *new_buffer, *clone; tux_dirent *old_entry, *new_entry; void *olddata; int err, new_subdir = 0; unsigned delta; old_entry = tux_find_dirent(old_dir, &old_dentry->d_name, &old_buffer); if (IS_ERR(old_entry)) return PTR_ERR(old_entry); /* FIXME: is this needed? */ assert(be64_to_cpu(old_entry->inum) == tux_inode(old_inode)->inum); change_begin(sb); delta = tux3_get_current_delta(); if (new_inode) { int old_is_dir = S_ISDIR(old_inode->i_mode); if (old_is_dir) { err = tux_dir_is_empty(new_inode); if (err) goto error; } new_entry = tux_find_dirent(new_dir, &new_dentry->d_name, &new_buffer); if (IS_ERR(new_entry)) { assert(PTR_ERR(new_entry) != -ENOENT); err = PTR_ERR(new_entry); goto error; } /* * The directory is protected by i_mutex. * blockdirty() should never return -EAGAIN. */ olddata = bufdata(new_buffer); clone = blockdirty(new_buffer, delta); if (IS_ERR(clone)) { assert(PTR_ERR(clone) != -EAGAIN); blockput(new_buffer); err = PTR_ERR(clone); goto error; } new_entry = ptr_redirect(new_entry, olddata, bufdata(clone)); /* this releases new_buffer */ tux_update_dirent(new_dir, clone, new_entry, old_inode); tux3_iattrdirty(new_inode); new_inode->i_ctime = new_dir->i_ctime; if (old_is_dir) drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { new_subdir = S_ISDIR(old_inode->i_mode) && new_dir != old_dir; if (new_subdir) { if (new_dir->i_nlink >= TUX_LINK_MAX) { err = -EMLINK; goto error; } } err = tux_create_dirent(new_dir, &new_dentry->d_name, old_inode); if (err) goto error; if (new_subdir) inode_inc_link_count(new_dir); } tux3_iattrdirty(old_inode); old_inode->i_ctime = new_dir->i_ctime; tux3_mark_inode_dirty(old_inode); /* * The new entry can be on same buffer with old_buffer, and * may did buffer fork in the above path. So if old_buffer is * forked buffer, we update the old_buffer in here. */ if (buffer_forked(old_buffer)) { clone = blockget(mapping(old_dir), bufindex(old_buffer)); assert(clone); old_entry = ptr_redirect(old_entry, bufdata(old_buffer), bufdata(clone)); blockput(old_buffer); old_buffer = clone; } err = tux_delete_dirent(old_dir, old_buffer, old_entry); if (err) { tux3_fs_error(sb, "couldn't delete old entry (%Lu)", tux_inode(old_inode)->inum); /* FIXME: now, we have hardlink even if it's dir. */ inode_inc_link_count(old_inode); } if (!err && new_subdir) inode_dec_link_count(old_dir); change_end(sb); return err; error: change_end(sb); blockput(old_buffer); return err; } #ifdef __KERNEL__ const struct file_operations tux_dir_fops = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = tux_readdir, .fsync = tux3_sync_file, }; const struct inode_operations tux_dir_iops = { .create = tux3_create, .lookup = tux3_lookup, .link = tux3_link, .unlink = tux3_unlink, .symlink = tux3_symlink, .mkdir = tux3_mkdir, .rmdir = tux3_rmdir, .mknod = tux3_mknod, .rename = tux3_rename, .setattr = tux3_setattr, .getattr = tux3_getattr // .setxattr = generic_setxattr, // .getxattr = generic_getxattr, // .listxattr = ext3_listxattr, // .removexattr = generic_removexattr, // .permission = ext3_permission, /* FIXME: why doesn't ext4 support this for directory? */ // .fallocate = ext4_fallocate, // .fiemap = ext4_fiemap, };