static struct inode *__logfs_iget(struct super_block *sb, ino_t ino) { struct inode *inode = iget_locked(sb, ino); int err; if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; err = logfs_read_inode(inode); if (err || inode->i_nlink == 0) { /* inode->i_nlink == 0 can be true when called from * block validator */ /* set i_nlink to 0 to prevent caching */ clear_nlink(inode); logfs_inode(inode)->li_flags |= LOGFS_IF_ZOMBIE; iget_failed(inode); if (!err) err = -ENOENT; return ERR_PTR(err); } logfs_inode_setops(inode); unlock_new_inode(inode); return inode; }
static struct inode *__logfs_iget(struct super_block *sb, ino_t ino) { struct inode *inode = iget_locked(sb, ino); int err; if (!inode) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) return inode; err = logfs_read_inode(inode); if (err || inode->i_nlink == 0) { clear_nlink(inode); logfs_inode(inode)->li_flags |= LOGFS_IF_ZOMBIE; iget_failed(inode); if (!err) err = -ENOENT; return ERR_PTR(err); } logfs_inode_setops(inode); unlock_new_inode(inode); return inode; }
static void __logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); BUG_ON(li->li_block); list_del(&li->li_freeing_list); call_rcu(&inode->i_rcu, logfs_i_callback); }
static void __logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); BUG_ON(li->li_block); list_del(&li->li_freeing_list); kmem_cache_free(logfs_inode_cache, li); }
static int __logfs_create(struct inode *dir, struct dentry *dentry, struct inode *inode, const char *dest, long destlen) { struct logfs_super *super = logfs_super(dir->i_sb); struct logfs_inode *li = logfs_inode(inode); struct logfs_transaction *ta; int ret; ta = kzalloc(sizeof(*ta), GFP_KERNEL); if (!ta) { inode->i_nlink--; iput(inode); return -ENOMEM; } ta->state = CREATE_1; ta->ino = inode->i_ino; mutex_lock(&super->s_dirop_mutex); logfs_add_transaction(inode, ta); if (dest) { /* symlink */ ret = logfs_inode_write(inode, dest, destlen, 0, WF_LOCK, NULL); if (!ret) ret = write_inode(inode); } else { /* creat/mkdir/mknod */ ret = write_inode(inode); } if (ret) { abort_transaction(inode, ta); li->li_flags |= LOGFS_IF_STILLBORN; /* FIXME: truncate symlink */ inode->i_nlink--; iput(inode); goto out; } ta->state = CREATE_2; logfs_add_transaction(dir, ta); ret = logfs_write_dir(dir, dentry, inode); /* sync directory */ if (!ret) ret = write_inode(dir); if (ret) { logfs_del_transaction(dir, ta); ta->state = CREATE_2; logfs_add_transaction(inode, ta); logfs_remove_inode(inode); iput(inode); goto out; } d_instantiate(dentry, inode); out: mutex_unlock(&super->s_dirop_mutex); return ret; }
/* called with inode->i_lock held */ static int logfs_drop_inode(struct inode *inode) { struct logfs_super *super = logfs_super(inode->i_sb); struct logfs_inode *li = logfs_inode(inode); spin_lock(&logfs_inode_lock); list_move(&li->li_freeing_list, &super->s_freeing_list); spin_unlock(&logfs_inode_lock); return generic_drop_inode(inode); }
static void logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); BUG_ON(list_empty(&li->li_freeing_list)); spin_lock(&logfs_inode_lock); li->li_refcount--; if (li->li_refcount == 0) __logfs_destroy_inode(inode); spin_unlock(&logfs_inode_lock); }
static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc) { int ret; long flags = WF_LOCK; /* Can only happen if creat() failed. Safe to skip. */ if (logfs_inode(inode)->li_flags & LOGFS_IF_STILLBORN) return 0; ret = __logfs_write_inode(inode, NULL, flags); LOGFS_BUG_ON(ret, inode->i_sb); return ret; }
static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc) { int ret; long flags = WF_LOCK; if (logfs_inode(inode)->li_flags & LOGFS_IF_STILLBORN) return 0; ret = __logfs_write_inode(inode, NULL, flags); LOGFS_BUG_ON(ret, inode->i_sb); return ret; }
struct inode *logfs_new_inode(struct inode *dir, umode_t mode) { struct super_block *sb = dir->i_sb; struct inode *inode; inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); logfs_init_inode(sb, inode); /* inherit parent flags */ logfs_inode(inode)->li_flags |= logfs_inode(dir)->li_flags & LOGFS_FL_INHERITED; inode->i_mode = mode; logfs_set_ino_generation(sb, inode); inode_init_owner(inode, dir, mode); logfs_inode_setops(inode); insert_inode_hash(inode); return inode; }
static void read_anchor(struct super_block *sb, struct logfs_je_anchor *da) { struct logfs_super *super = logfs_super(sb); struct inode *inode = super->s_master_inode; struct logfs_inode *li = logfs_inode(inode); int i; super->s_last_ino = be64_to_cpu(da->da_last_ino); li->li_flags = 0; li->li_height = da->da_height; i_size_write(inode, be64_to_cpu(da->da_size)); li->li_used_bytes = be64_to_cpu(da->da_used_bytes); for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) li->li_data[i] = be64_to_cpu(da->da_data[i]); }
static void account_shadows(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); struct inode *inode = super->s_master_inode; struct logfs_inode *li = logfs_inode(inode); struct shadow_tree *tree = &super->s_shadow_tree; btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); btree_grim_visitor32(&tree->segment_map, 0, NULL); tree->no_shadowed_segments = 0; if (li->li_block) { li->li_block->ops->free_block(sb, li->li_block); } BUG_ON((s64)li->li_used_bytes < 0); }
static void *__logfs_write_anchor(struct super_block *sb, void *_da, u16 *type, size_t *len) { struct logfs_super *super = logfs_super(sb); struct logfs_je_anchor *da = _da; struct inode *inode = super->s_master_inode; struct logfs_inode *li = logfs_inode(inode); int i; da->da_height = li->li_height; da->da_last_ino = cpu_to_be64(super->s_last_ino); da->da_size = cpu_to_be64(i_size_read(inode)); da->da_used_bytes = cpu_to_be64(li->li_used_bytes); for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) da->da_data[i] = cpu_to_be64(li->li_data[i]); *type = JE_ANCHOR; *len = sizeof(*da); return da; }
static void logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); if (inode->i_ino < LOGFS_RESERVED_INOS) { /* * The reserved inodes are never destroyed unless we are in * unmont path. */ __logfs_destroy_meta_inode(inode); return; } BUG_ON(list_empty(&li->li_freeing_list)); spin_lock(&logfs_inode_lock); li->li_refcount--; if (li->li_refcount == 0) __logfs_destroy_inode(inode); spin_unlock(&logfs_inode_lock); }
static void account_shadows(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); struct inode *inode = super->s_master_inode; struct logfs_inode *li = logfs_inode(inode); struct shadow_tree *tree = &super->s_shadow_tree; btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); if (li->li_block) { /* * We never actually use the structure, when attached to the * master inode. But it is easier to always free it here than * to have checks in several places elsewhere when allocating * it. */ li->li_block->ops->free_block(sb, li->li_block); } BUG_ON((s64)li->li_used_bytes < 0); }
static void logfs_init_inode(struct super_block *sb, struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); int i; li->li_flags = 0; li->li_height = 0; li->li_used_bytes = 0; li->li_block = NULL; inode->i_uid = 0; inode->i_gid = 0; inode->i_size = 0; inode->i_blocks = 0; inode->i_ctime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME; li->li_refcount = 1; INIT_LIST_HEAD(&li->li_freeing_list); for (i = 0; i < LOGFS_EMBEDDED_FIELDS; i++) li->li_data[i] = 0; return; }
static void abort_transaction(struct inode *inode, struct logfs_transaction *ta) { if (logfs_inode(inode)->li_block) logfs_inode(inode)->li_block->ta = NULL; kfree(ta); }
static void __logfs_destroy_meta_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); BUG_ON(li->li_block); call_rcu(&inode->i_rcu, logfs_i_callback); }
static void logfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); kmem_cache_free(logfs_inode_cache, logfs_inode(inode)); }
static void logfs_i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); INIT_LIST_HEAD(&inode->i_dentry); kmem_cache_free(logfs_inode_cache, logfs_inode(inode)); }