transaction_t * get_transaction (journal_t * journal) { transaction_t * transaction; J_ASSERT (journal->j_locked); transaction = kmalloc (sizeof (transaction_t), GFP_KERNEL); if (!transaction) return NULL; memset (transaction, 0, sizeof (transaction_t)); transaction->t_journal = journal; transaction->t_state = T_RUNNING; transaction->t_tid = journal->j_transaction_sequence++; transaction->t_expires = jiffies + journal->j_commit_interval; /* Set up the commit timer for the new transaction. */ J_ASSERT (!journal->j_commit_timer_active); journal->j_commit_timer_active = 1; journal->j_commit_timer->expires = transaction->t_expires; add_timer(journal->j_commit_timer); J_ASSERT (journal->j_running_transaction == NULL); journal->j_running_transaction = transaction; return transaction; }
int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; tid_t tid; int need_to_start, ret; if (is_handle_aborted(handle)) return 0; J_ASSERT(atomic_read(&transaction->t_updates) > 0); J_ASSERT(journal_current_handle() == handle); read_lock(&journal->j_state_lock); spin_lock(&transaction->t_handle_lock); atomic_sub(handle->h_buffer_credits, &transaction->t_outstanding_credits); if (atomic_dec_and_test(&transaction->t_updates)) wake_up(&journal->j_wait_updates); spin_unlock(&transaction->t_handle_lock); jbd_debug(2, "restarting handle %p\n", handle); tid = transaction->t_tid; need_to_start = !tid_geq(journal->j_commit_request, tid); read_unlock(&journal->j_state_lock); if (need_to_start) jbd2_log_start_commit(journal, tid); lock_map_release(&handle->h_lockdep_map); handle->h_buffer_credits = nblocks; ret = start_this_handle(journal, handle, gfp_mask); return ret; }
void journal_refile_buffer(struct buffer_head *bh) { #ifdef __SMP__ J_ASSERT (current->lock_depth >= 0); #endif journal_unfile_buffer(bh); /* If the buffer is now unused, just drop it. If it has been modified by a later transaction, add it to the new transaction's metadata list. */ bh->b_transaction = bh->b_next_transaction; bh->b_next_transaction = NULL; if (bh->b_transaction != NULL) { int tstate; journal_file_buffer(bh, bh->b_transaction, BJ_Metadata); tstate = bh->b_transaction->t_state; J_ASSERT(tstate == T_RUNNING); } /* If necessary, remove it from the global journaled buffer list and replace it back on the main dirty buffer list. */ refile_buffer(bh); }
/* Initialise the revoke table for a given journal to a given size. */ int jbd2_journal_init_revoke(journal_t *journal, int hash_size) { J_ASSERT(journal->j_revoke_table[0] == NULL); J_ASSERT(is_power_of_2(hash_size)); journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size); if (!journal->j_revoke_table[0]) goto fail0; journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size); if (!journal->j_revoke_table[1]) goto fail1; journal->j_revoke = journal->j_revoke_table[1]; spin_lock_init(&journal->j_revoke_lock); return 0; fail1: jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]); journal->j_revoke_table[0] = NULL; fail0: return -ENOMEM; }
/** * journal_t * journal_init_inode () - creates a journal which maps to a inode. * @inode: An inode to create the journal in * * journal_init_inode creates a journal which maps an on-disk inode as * the journal. The inode must exist already, must support bmap() and * must have all data blocks preallocated. */ journal_t * journal_init_inode (struct inode *inode) { struct buffer_head *bh; journal_t *journal = journal_init_common(); int err; int n; unsigned long blocknr; if (!journal) return NULL; journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev; journal->j_inode = inode; jbd_debug(1, "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", journal, inode->i_sb->s_id, inode->i_ino, (s64) inode->i_size, inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); journal->j_maxlen = (unsigned int)(inode->i_size >> inode->i_sb->s_blocksize_bits); journal->j_blocksize = inode->i_sb->s_blocksize; /* journal descriptor can store up to n blocks -bzzz */ n = journal->j_blocksize / sizeof(journal_block_tag_t); journal->j_wbufsize = n; journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); if (!journal->j_wbuf) { printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n", __FUNCTION__); J_ASSERT(journal->j_revoke != NULL); if (journal->j_revoke) journal_destroy_revoke(journal); kfree(journal); return NULL; } err = journal_bmap(journal, 0, &blocknr); /* If that failed, give up */ if (err) { printk(KERN_ERR "%s: Cannnot locate journal superblock\n", __FUNCTION__); J_ASSERT(journal->j_revoke != NULL); if (journal->j_revoke) journal_destroy_revoke(journal); J_ASSERT(journal->j_wbuf != NULL); kfree(journal->j_wbuf); kfree(journal); return NULL; } bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); J_ASSERT(bh != NULL); journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data; return journal; }
int journal_dirty_data (handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; lock_journal(journal); mark_buffer_dirty(bh, 0); /* * What if the buffer is already part of a running transaction? * * There are two cases: * 1) It is part of the current running transaction. Refile it, * just in case we have allocated it as metadata, deallocated * it, then reallocated it as data. * 2) It is part of the previous, still-committing transaction. * If all we want to do is to guarantee that the buffer will be * written to disk before this new transaction commits, then * being sure that the *previous* transaction has this same * property is sufficient for us! Just leave it on its old * transaction. * * In case (2), the buffer must not already exist as metadata * --- that would violate write ordering (a transaction is free * to write its data at any point, even before the previous * committing transaction has committed). The caller must * never, ever allow this to happen: there's nothing we can do * about it in this layer. */ if (bh->b_transaction) { if (bh->b_transaction != handle->h_transaction) { J_ASSERT (bh->b_transaction == journal->j_committing_transaction); /* @@@ IS THIS TRUE ? */ J_ASSERT (bh->b_next_transaction == NULL); /* Special case --- the buffer might actually have been allocated and then immediately deallocated in the previous, committing transaction, so might still be left on that transaction's metadata lists. */ if (bh->b_jlist != BJ_Data) { J_ASSERT (bh->b_jlist != BJ_Shadow); J_ASSERT (test_and_clear_bit(BH_QuickFree, &bh->b_state)); journal_unfile_buffer(bh); bh->b_transaction = NULL; journal_file_buffer(bh, handle->h_transaction, BJ_Data); refile_buffer(bh); } } } else { journal_file_buffer(bh, handle->h_transaction, BJ_Data); refile_buffer(bh); } unlock_journal(journal); return 0; }
int journal_stop (handle_t *handle) { transaction_t *transaction = handle->h_transaction; journal_t *journal = transaction->t_journal; int force_sync; if (!handle) return 0; J_ASSERT (transaction->t_updates > 0); J_ASSERT (current->j_handle == handle); if (--handle->h_ref > 0) return 0; jfs_debug(4, "Handle %p going down\n", handle); current->j_handle = NULL; // current->fs_locks--; transaction->t_outstanding_credits -= handle->h_buffer_credits; transaction->t_updates--; if (!transaction->t_updates) { wake_up(&journal->j_wait_updates); if (journal->j_barrier_count) wake_up(&journal->j_wait_transaction_locked); } /* * If the journal is marked SYNC, we need to set another commit * going! We also want to force a commit if the current * transaction is occupying too much of the log, or if the * transaction is too old now. */ force_sync = (journal->j_flags & JFS_SYNC) || handle->h_sync; if (force_sync || transaction->t_outstanding_credits > journal->j_max_transaction_buffers || time_after_eq(jiffies, transaction->t_expires)) { tid_t tid = transaction->t_tid; jfs_debug(2, "transaction too old, requesting commit for handle %p\n", handle); log_start_commit(journal, transaction); /* * Special case: JFS_SYNC synchronous updates require us * to wait for the commit to complete. */ if (force_sync) log_wait_commit(journal, tid); } kfree(handle); return 0; }
void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction) { assert_spin_locked(&journal->j_list_lock); if (transaction->t_cpnext) { transaction->t_cpnext->t_cpprev = transaction->t_cpprev; transaction->t_cpprev->t_cpnext = transaction->t_cpnext; if (journal->j_checkpoint_transactions == transaction) journal->j_checkpoint_transactions = transaction->t_cpnext; if (journal->j_checkpoint_transactions == transaction) journal->j_checkpoint_transactions = NULL; } J_ASSERT(transaction->t_state == T_FINISHED); J_ASSERT(transaction->t_buffers == NULL); J_ASSERT(transaction->t_forget == NULL); J_ASSERT(transaction->t_shadow_list == NULL); J_ASSERT(transaction->t_checkpoint_list == NULL); J_ASSERT(transaction->t_checkpoint_io_list == NULL); J_ASSERT(atomic_read(&transaction->t_updates) == 0); J_ASSERT(journal->j_committing_transaction != transaction); J_ASSERT(journal->j_running_transaction != transaction); trace_jbd2_drop_transaction(journal, transaction); jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); }
void journal_unfile_buffer(struct buffer_head *buf) { struct buffer_head **list = 0; transaction_t * transaction; transaction = buf->b_transaction; #ifdef __SMP__ J_ASSERT (current->lock_depth >= 0); #endif J_ASSERT (transaction->t_journal->j_locked); J_ASSERT (buf->b_jlist < BJ_Types); if (buf->b_jlist != BJ_None) J_ASSERT (transaction != 0); switch (buf->b_jlist) { case BJ_None: return; case BJ_Data: list = &transaction->t_datalist; break; case BJ_Metadata: transaction->t_nr_buffers--; J_ASSERT(transaction->t_nr_buffers >= 0); list = &transaction->t_buffers; break; case BJ_Forget: list = &transaction->t_forget; break; case BJ_IO: list = &transaction->t_iobuf_list; break; case BJ_Shadow: list = &transaction->t_shadow_list; break; case BJ_LogCtl: list = &transaction->t_log_list; break; case BJ_Reserved: list = &transaction->t_reserved_list; break; } blist_del_buffer(list, buf); buf->b_jlist = BJ_None; if (buffer_jdirty(buf)) { set_bit(BH_Dirty, &buf->b_state); clear_bit(BH_JDirty, &buf->b_state); } }
int jbd2_cleanup_journal_tail(journal_t *journal) { tid_t first_tid; unsigned long blocknr; if (is_journal_aborted(journal)) return 1; if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr)) return 1; J_ASSERT(blocknr != 0); /* */ if (journal->j_flags & JBD2_BARRIER) blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); __jbd2_update_log_tail(journal, first_tid, blocknr); return 0; }
int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; int ret; J_ASSERT(ext3_journal_current_handle() == 0); /* * fsync_inode_buffers() just walks i_dirty_buffers and waits * on them. It's a no-op for full data journalling because * i_dirty_buffers will be ampty. * Really, we only need to start I/O on the dirty buffers - * we'll end up waiting on them in commit. */ ret = fsync_inode_buffers(inode); /* In writeback mode, we need to force out data buffers too. In * the other modes, ext3_force_commit takes care of forcing out * just the right data blocks. */ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) ret |= fsync_inode_data_buffers(inode); ext3_force_commit(inode->i_sb); return ret; }
int jbd2_journal_try_to_free_buffers(journal_t *journal, struct page *page, gfp_t gfp_mask) { struct buffer_head *head; struct buffer_head *bh; int ret = 0; J_ASSERT(PageLocked(page)); head = page_buffers(page); bh = head; do { struct journal_head *jh; jh = jbd2_journal_grab_journal_head(bh); if (!jh) continue; jbd_lock_bh_state(bh); __journal_try_to_free_buffer(journal, bh); jbd2_journal_put_journal_head(jh); jbd_unlock_bh_state(bh); if (buffer_jbd(bh)) goto busy; } while ((bh = bh->b_this_page) != head); ret = try_to_free_buffers(page); busy: return ret; }
int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) { struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; int ret, needs_barrier = 0; tid_t commit_tid; trace_ext3_sync_file_enter(file, datasync); if (inode->i_sb->s_flags & MS_RDONLY) return 0; ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (ret) goto out; J_ASSERT(ext3_journal_current_handle() == NULL); /* * data=writeback,ordered: * The caller's filemap_fdatawrite()/wait will sync the data. * Metadata is in the journal, we wait for a proper transaction * to commit here. * * data=journal: * filemap_fdatawrite won't do anything (the buffers are clean). * ext3_force_commit will write the file data into the journal and * will wait on that. * filemap_fdatawait() will encounter a ton of newly-dirtied pages * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ if (ext3_should_journal_data(inode)) { ret = ext3_force_commit(inode->i_sb); goto out; } if (datasync) commit_tid = atomic_read(&ei->i_datasync_tid); else commit_tid = atomic_read(&ei->i_sync_tid); if (test_opt(inode->i_sb, BARRIER) && !journal_trans_will_send_data_barrier(journal, commit_tid)) needs_barrier = 1; log_start_commit(journal, commit_tid); ret = log_wait_commit(journal, commit_tid); /* * In case we didn't commit a transaction, we have to flush * disk caches manually so that data really is on persistent * storage */ if (needs_barrier) blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); out: trace_ext3_sync_file_exit(inode, ret); return ret; }
static transaction_t * jbd2_get_transaction(journal_t *journal, transaction_t *transaction) { transaction->t_journal = journal; transaction->t_state = T_RUNNING; transaction->t_start_time = ktime_get(); transaction->t_tid = journal->j_transaction_sequence++; transaction->t_expires = jiffies + journal->j_commit_interval; spin_lock_init(&transaction->t_handle_lock); atomic_set(&transaction->t_updates, 0); atomic_set(&transaction->t_outstanding_credits, 0); atomic_set(&transaction->t_handle_count, 0); INIT_LIST_HEAD(&transaction->t_inode_list); INIT_LIST_HEAD(&transaction->t_private_list); journal->j_commit_timer.expires = round_jiffies_up(transaction->t_expires); add_timer(&journal->j_commit_timer); J_ASSERT(journal->j_running_transaction == NULL); journal->j_running_transaction = transaction; transaction->t_max_wait = 0; transaction->t_start = jiffies; return transaction; }
int journal_wipe(journal_t *journal, int write) { journal_superblock_t *sb; int err = 0; J_ASSERT (!(journal->j_flags & JFS_LOADED)); err = load_superblock(journal); if (err) return err; sb = journal->j_superblock; if (!journal->j_tail) goto no_recovery; printk (KERN_WARNING "JBD: %s recovery information on journal\n", write ? "Clearing" : "Ignoring"); err = journal_skip_recovery(journal); if (write) journal_update_superblock(journal, 1); no_recovery: return err; }
int jbd2_cleanup_journal_tail(journal_t *journal) { tid_t first_tid; unsigned long blocknr; if (is_journal_aborted(journal)) return -EIO; if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr)) return 1; J_ASSERT(blocknr != 0); /* * We need to make sure that any blocks that were recently written out * --- perhaps by jbd2_log_do_checkpoint() --- are flushed out before * we drop the transactions from the journal. It's unlikely this will * be necessary, especially with an appropriately sized journal, but we * need this to guarantee correctness. Fortunately * jbd2_cleanup_journal_tail() doesn't get called all that often. */ if (journal->j_flags & JBD2_BARRIER) blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL); return __jbd2_update_log_tail(journal, first_tid, blocknr); }
handle_t *journal_start(journal_t *journal, int nblocks) { handle_t *handle = journal_current_handle(); int err; if (!journal) return ERR_PTR(-EROFS); if (handle) { J_ASSERT(handle->h_transaction->t_journal == journal); handle->h_ref++; return handle; } handle = new_handle(nblocks); if (!handle) return ERR_PTR(-ENOMEM); current->journal_info = handle; err = start_this_handle(journal, handle); if (err < 0) { jbd_free_handle(handle); current->journal_info = NULL; handle = ERR_PTR(err); goto out; } out: return handle; }
void jbd2_journal_invalidatepage(journal_t *journal, struct page *page, unsigned long offset) { struct buffer_head *head, *bh, *next; unsigned int curr_off = 0; int may_free = 1; if (!PageLocked(page)) BUG(); if (!page_has_buffers(page)) return; head = bh = page_buffers(page); do { unsigned int next_off = curr_off + bh->b_size; next = bh->b_this_page; if (offset <= curr_off) { lock_buffer(bh); may_free &= journal_unmap_buffer(journal, bh); unlock_buffer(bh); } curr_off = next_off; bh = next; } while (bh != head); if (!offset) { if (may_free && try_to_free_buffers(page)) J_ASSERT(!page_has_buffers(page)); } }
void hm_async_queue_push_unlocked(JAsyncQueue *queue, void *data) { J_ASSERT(queue != NULL && data != NULL); hm_queue_push_tail(&queue->queue, data); hm_cond_signal(queue->cond); }
int journal_get_undo_access (handle_t *handle, struct buffer_head *bh) { journal_t *journal = handle->h_transaction->t_journal; int err; lock_journal_bh_wait(bh, journal); /* Do this first --- it can drop the journal lock, so we want to * make sure that obtaining the committed_data is done * atomically wrt. completion of any outstanding commits. */ err = do_get_write_access (handle, bh, 1); if (!bh->b_committed_data) { /* Copy out the current buffer contents into the * preserved, committed copy. */ bh->b_committed_data = kmalloc(bh->b_size, GFP_KERNEL); if (!bh->b_committed_data) { unlock_journal(journal); return -ENOMEM; } memcpy (bh->b_committed_data, bh->b_data, bh->b_size); } unlock_journal(journal); if (!err) J_ASSERT(bh->b_committed_data); return err; }
JAsyncQueue *hm_async_queue_ref(JAsyncQueue *queue) { J_ASSERT(queue != NULL); atomic_inc(&queue->ref_count); return queue; }
int cleanup_journal_tail(journal_t *journal) { transaction_t * transaction; tid_t first_tid; unsigned long blocknr, freed; /* OK, work out the oldest transaction remaining in the log, and * the log block it starts at. * * If the log is now empty, we need to work out which is the * next transaction ID we will write, and where it will * start. */ spin_lock(&journal->j_state_lock); spin_lock(&journal->j_list_lock); transaction = journal->j_checkpoint_transactions; if (transaction) { first_tid = transaction->t_tid; blocknr = transaction->t_log_start; } else if ((transaction = journal->j_committing_transaction) != NULL) { first_tid = transaction->t_tid; blocknr = transaction->t_log_start; } else if ((transaction = journal->j_running_transaction) != NULL) { first_tid = transaction->t_tid; blocknr = journal->j_head; } else { first_tid = journal->j_transaction_sequence; blocknr = journal->j_head; } spin_unlock(&journal->j_list_lock); J_ASSERT(blocknr != 0); /* If the oldest pinned transaction is at the tail of the log already then there's not much we can do right now. */ if (journal->j_tail_sequence == first_tid) { spin_unlock(&journal->j_state_lock); return 1; } /* OK, update the superblock to recover the freed space. * Physical blocks come first: have we wrapped beyond the end of * the log? */ freed = blocknr - journal->j_tail; if (blocknr < journal->j_tail) freed = freed + journal->j_last - journal->j_first; jbd_debug(1, "Cleaning journal tail from %d to %d (offset %lu), " "freeing %lu\n", journal->j_tail_sequence, first_tid, blocknr, freed); journal->j_free += freed; journal->j_tail_sequence = first_tid; journal->j_tail = blocknr; spin_unlock(&journal->j_state_lock); if (!(journal->j_flags & JFS_ABORT)) journal_update_superblock(journal, 1); return 0; }
void hm_thread_pool_push(JThreadPool *tp, void *data) { JRealThreadPool *_tp; J_ASSERT(tp != NULL && data != NULL); _tp = (JRealThreadPool*)tp; hm_async_queue_push(_tp->queue, data); }
void hm_async_queue_push(JAsyncQueue *queue, void *data) { J_ASSERT(queue != NULL); hm_mutex_lock(queue->mutex); hm_async_queue_push_unlocked(queue, data); hm_mutex_unlock(queue->mutex); }
/* * Release a JNetRealBuf object. */ __export void hm_net_buf_free(JNetBuf *buf) { J_ASSERT(buf != NULL); hm_mutex_free(buf->buf_lock); hm_dealloc(buf, buf->object_size); }
int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; struct ext4_inode_info *ei = EXT4_I(inode); journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; int ret; tid_t commit_tid; J_ASSERT(ext4_journal_current_handle() == NULL); trace_ext4_sync_file(file, dentry, datasync); if (inode->i_sb->s_flags & MS_RDONLY) return 0; ret = flush_aio_dio_completed_IO(inode); if (ret < 0) return ret; if (!journal) return simple_fsync(file, dentry, datasync); /* * data=writeback,ordered: * The caller's filemap_fdatawrite()/wait will sync the data. * Metadata is in the journal, we wait for proper transaction to * commit here. * * data=journal: * filemap_fdatawrite won't do anything (the buffers are clean). * ext4_force_commit will write the file data into the journal and * will wait on that. * filemap_fdatawait() will encounter a ton of newly-dirtied pages * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ if (ext4_should_journal_data(inode)) return ext4_force_commit(inode->i_sb); commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; if (jbd2_log_start_commit(journal, commit_tid)) { /* * When the journal is on a different device than the * fs data disk, we need to issue the barrier in * writeback mode. (In ordered mode, the jbd2 layer * will take care of issuing the barrier. In * data=journal, all of the data blocks are written to * the journal device.) */ if (ext4_should_writeback_data(inode) && (journal->j_fs_dev != journal->j_dev) && (journal->j_flags & JBD2_BARRIER)) blkdev_issue_flush(inode->i_sb->s_bdev, NULL); ret = jbd2_log_wait_commit(journal, commit_tid); } else if (journal->j_flags & JBD2_BARRIER) blkdev_issue_flush(inode->i_sb->s_bdev, NULL); return ret; }
/** * pause the play, return true if current are playing * */ bool OpenSLIn::pause(){ J_ASSERT(mState == SLIN_PAUSE || mState == SLIN_RECORD); tryCallBack(WHEN_PAUSE, &mState); if(mState == SLIN_PAUSE){ // goto record mState = SLIN_RECORD; }else if(mState == SLIN_RECORD){ // goto pause mState = SLIN_PAUSE; return true; }else { J_ASSERT(false); } return false; }
/** * stop the play * */ void OpenSLIn::stop(){ J_ASSERT(mState != SLIN_STOP); tryCallBack(WHEN_STOP, 0); mState = SLIN_STOP; stopInternal(); return; }
/** * void journal_destroy() - Release a journal_t structure. * @journal: Journal to act on. * * Release a journal_t structure once it is no longer in use by the * journaled object. */ void journal_destroy(journal_t *journal) { #if 0 /* Wait for the commit thread to wake up and die. */ journal_kill_thread(journal); /* Force a final log commit */ if (journal->j_running_transaction) journal_commit_transaction(journal); /* Force any old transactions to disk */ /* Totally anal locking here... */ jbd_lock(&journal->j_list_lock); while (journal->j_checkpoint_transactions != NULL) { jbd_unlock(&journal->j_list_lock); log_do_checkpoint(journal); jbd_lock(&journal->j_list_lock); } J_ASSERT(journal->j_running_transaction == NULL); J_ASSERT(journal->j_committing_transaction == NULL); J_ASSERT(journal->j_checkpoint_transactions == NULL); jbd_unlock(&journal->j_list_lock); /* We can now mark the journal as empty. */ journal->j_tail = 0; journal->j_tail_sequence = ++journal->j_transaction_sequence; if (journal->j_sb_buffer) { journal_update_superblock(journal, 1); brelse(journal->j_sb_buffer); } #endif if (journal->j_sb_buffer) { brelse(journal->j_sb_buffer); } if (journal->j_inode) iput(journal->j_inode); if (journal->j_revoke) journal_destroy_revoke(journal); kfree(journal->j_wbuf); kfree(journal); }
int ext3_sync_file(struct file * file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; int ret = 0; J_ASSERT(ext3_journal_current_handle() == 0); /* * data=writeback: * The caller's filemap_fdatawrite()/wait will sync the data. * sync_inode() will sync the metadata * * data=ordered: * The caller's filemap_fdatawrite() will write the data and * sync_inode() will write the inode if it is dirty. Then the caller's * filemap_fdatawait() will wait on the pages. * * data=journal: * filemap_fdatawrite won't do anything (the buffers are clean). * ext3_force_commit will write the file data into the journal and * will wait on that. * filemap_fdatawait() will encounter a ton of newly-dirtied pages * (they were dirtied by commit). But that's OK - the blocks are * safe in-journal, which is all fsync() needs to ensure. */ if (ext3_should_journal_data(inode)) { ret = ext3_force_commit(inode->i_sb); goto out; } if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) goto flush; /* * The VFS has written the file data. If the inode is unaltered * then we need not start a commit. */ if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) { struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, .nr_to_write = 0, /* sys_fsync did this */ }; ret = sync_inode(inode, &wbc); goto out; } flush: /* * In case we didn't commit a transaction, we have to flush * disk caches manually so that data really is on persistent * storage */ if (test_opt(inode->i_sb, BARRIER)) blkdev_issue_flush(inode->i_sb->s_bdev, NULL); out: return ret; }