void tux3_iattrdirty(struct inode *inode) { struct tux3_inode *tuxnode = tux_inode(inode); unsigned delta = tux3_inode_delta(inode); unsigned flags = tuxnode->flags; /* If dirtied on this delta, nothing to do */ if (tux3_iattrsta_has_delta(flags) && tux3_iattrsta_get_delta(flags) == tux3_delta(delta)) return; trace("inum %Lu, delta %u", tuxnode->inum, delta); spin_lock(&tuxnode->lock); flags = tuxnode->flags; if (S_ISREG(inode->i_mode) || tux3_iattrsta_has_delta(flags)) { unsigned old_delta; /* * For a regular file, and even if iattrs are clean, * we have to provide stable idata for backend. * * Because backend may be committing data pages. If * so, backend have to check idata->i_size, and may * save dtree root. But previous delta doesn't have * stable iattrs. * * So, this provides stable iattrs for regular file, * even if previous delta is clean. * * Other types don't have this problem, because: * - Never dirty iattr (e.g. volmap). IOW, iattrs are * always stable. * - Or dirty iattr with data, e.g. directory updates * timestamp too with data blocks. */ if (S_ISREG(inode->i_mode) && !tux3_iattrsta_has_delta(flags)) old_delta = tux3_delta(delta - 1); else old_delta = tux3_iattrsta_get_delta(flags); /* If delta is difference, iattrs was stabilized. Copy. */ if (old_delta != tux3_delta(delta)) { struct tux3_iattr_data *idata = &tux3_inode_ddc(inode, old_delta)->idata; idata_copy(inode, idata); } } /* Update iattr state to current delta */ tuxnode->flags = tux3_iattrsta_update(flags, delta); spin_unlock(&tuxnode->lock); }
/* * Read iattrs, then clear iattr dirty to tell no need to iattrfork * anymore if needed. * * Caller must hold tuxnode->lock. */ static void tux3_iattr_read_and_clear(struct inode *inode, struct tux3_iattr_data *result, unsigned delta) { struct tux3_inode *tuxnode = tux_inode(inode); unsigned long flags; trace("inum %Lu, delta %u", tuxnode->inum, delta); /* * If delta is same, iattrs are available in inode. If not, * iattrs were forked. */ flags = tuxnode->flags; if (!tux3_iattrsta_has_delta(flags) || tux3_iattrsta_get_delta(flags) == tux3_delta(delta)) { /* * If btree is only dirtied, or if dirty and no fork, * use inode. */ idata_copy(inode, result); tuxnode->flags = tux3_iattrsta_clear(flags); } else { /* If dirty and forked, use copy */ struct tux3_iattr_data *idata = &tux3_inode_ddc(inode, delta)->idata; assert(idata->present != TUX3_INVALID_PRESENT); *result = *idata; } /* For debugging, set invalid value to ->present after read */ tux3_inode_ddc(inode, delta)->idata.present = TUX3_INVALID_PRESENT; }
/* Check whether we can modify buffer atomically for delta */ int buffer_can_modify(struct buffer_head *buffer, unsigned delta) { unsigned long state = buffer->b_state; /* If buffer is clean or dirtied for same delta, we can modify */ return !tux3_bufsta_has_delta(state) || tux3_bufsta_get_delta(state) == tux3_delta(delta); }
/* * FIXME: this is hack to save delta to linux buffer_head. * Inefficient, and this is not atomic with dirty bit change. And this * may not work on all arch (If set_bit() and cmpxchg() is not * exclusive, this has race). */ static void tux3_set_bufdelta(struct buffer_head *buffer, int delta) { unsigned long state, old_state; delta = tux3_delta(delta); state = buffer->b_state; for (;;) { old_state = state; state = tux3_bufsta_update(old_state, delta); state = cmpxchg(&buffer->b_state, old_state, state); if (state == old_state) break; } }
/* * Check whether inode was dead. Then clear iattr dirty to tell no * need to iattrfork anymore if needed. */ static void tux3_dead_read_and_clear(struct inode *inode, unsigned *deleted, unsigned delta) { struct tux3_inode *tuxnode = tux_inode(inode); unsigned flags = tuxnode->flags; *deleted = 0; if (tux3_deadsta_has_delta(flags) && tux3_deadsta_get_delta(flags) == tux3_delta(delta)) { *deleted = 1; flags |= TUX3_INODE_DEAD; tuxnode->flags = tux3_deadsta_clear(flags); } }
/* Check whether buffer was already dirtied atomically for delta */ int buffer_already_dirty(struct buffer_head *buffer, unsigned delta) { unsigned long state = buffer->b_state; /* If buffer had same delta, buffer was already dirtied for delta */ return buffer_check_dirty_delta(state) == tux3_delta(delta); }