现在我们来看看日志系统是怎么把数据记录到日志分区或是目录里的。日志的开是从ext4里的super.c(192)开始的,让我们来看看这个函数的真实面目
/* * Wrappers for jbd2_journal_start/end. * * The only special thing we need to do here is to make sure that all * journal_end calls result in the superblock being marked dirty, so * that sync() will call the filesystem's write_super callback if * appropriate. */ /** 这个函数是对jbd2_journal_start的封装, **/ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) { journal_t *journal;
// 如果系统是只读,那么就直接返回。
if (sb->s_flags & MS_RDONLY) return ERR_PTR(-EROFS);
/* Special case here: if the journal has aborted behind our * backs (eg. EIO in the commit thread), then we still need to * take the FS itself readonly cleanly. */ /* 获得文件系统的日志句柄*/ journal = EXT4_SB(sb)->s_journal; if (journal) { // 如果日志在其它地方被置为废除了,那就不会那傻劲了,直接返回。
if (is_journal_aborted(journal)) { ext4_abort(sb, __func__, "Detected aborted journal"); return ERR_PTR(-EROFS); } // 如果日志正常,那么就开记录日志了。这个函数是真正的日志开始记录的函数。在fs/jbd2/transaction.c(279)
return jbd2_journal_start(journal, nblocks); } /* * We're not journaling, return the appropriate indication. */ // 如果系统没有日志为之服务,那就把当前进程的日志指针置为空。
current->journal_info = EXT4_NOJOURNAL_HANDLE; return current->journal_info; }
|
上面那个函数实际上是调jdb2_journal_start来实现这个日志记录的功能的。再让我们来看看
/** * handle_t *jbd2_journal_start() - Obtain a new handle. * @journal: Journal to start transaction on. * @nblocks: number of block buffer we might modify * * We make sure that the transaction can guarantee at least nblocks of * modified buffers in the log. We block until the log can guarantee * that much space. * * This function is visible to journal users (like ext3fs), so is not * called with the journal already locked. * * Return a pointer to a newly allocated handle, or NULL on failure */ // 这是真正开始日志的函数。
handle_t *jbd2_journal_start(journal_t *journal, int nblocks) { /* 从当前运行的进程中取得日志句柄。在include/linux/sched.h(1344)行有这样的定义 / * journalling filesystem info * / void *journal_info; 实际上下面这个宏就返回这个指针。 */ handle_t *handle = journal_current_handle(); int err;
// 如果日志的指针是空,那么就直接返回。
if (!journal) return ERR_PTR(-EROFS); // 如果当前提交的事务已经在当前的日志上了,就把事务的引用加1,表示再提交一次了。
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) { jbd2_free_handle(handle); current->journal_info = NULL; handle = ERR_PTR(err); goto out; }
// 这个是调试用的锁,先不管了。
lock_map_acquire(&handle->h_lockdep_map); out: return handle; }
|
我都觉得太麻烦了,千呼万唤还没出来,又得进到另一个函数才行。
start_this_handle,下节再讲吧。
阅读(2344) | 评论(0) | 转发(0) |