|
@@ -646,6 +646,48 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * check_journal_clean - Make sure a journal is clean for a spectator mount
|
|
|
+ * @sdp: The GFS2 superblock
|
|
|
+ * @jd: The journal descriptor
|
|
|
+ *
|
|
|
+ * Returns: 0 if the journal is clean or locked, else an error
|
|
|
+ */
|
|
|
+static int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
|
|
|
+{
|
|
|
+ int error;
|
|
|
+ struct gfs2_holder j_gh;
|
|
|
+ struct gfs2_log_header_host head;
|
|
|
+ struct gfs2_inode *ip;
|
|
|
+
|
|
|
+ ip = GFS2_I(jd->jd_inode);
|
|
|
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP |
|
|
|
+ GL_EXACT | GL_NOCACHE, &j_gh);
|
|
|
+ if (error) {
|
|
|
+ fs_err(sdp, "Error locking journal for spectator mount.\n");
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+ error = gfs2_jdesc_check(jd);
|
|
|
+ if (error) {
|
|
|
+ fs_err(sdp, "Error checking journal for spectator mount.\n");
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+ error = gfs2_find_jhead(jd, &head);
|
|
|
+ if (error) {
|
|
|
+ fs_err(sdp, "Error parsing journal for spectator mount.\n");
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
+ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
|
|
|
+ error = -EPERM;
|
|
|
+ fs_err(sdp, "jid=%u: Journal is dirty, so the first mounter "
|
|
|
+ "must not be a spectator.\n", jd->jd_jid);
|
|
|
+ }
|
|
|
+
|
|
|
+out_unlock:
|
|
|
+ gfs2_glock_dq_uninit(&j_gh);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|
|
{
|
|
|
struct inode *master = sdp->sd_master_dir->d_inode;
|
|
@@ -732,8 +774,15 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
|
|
|
if (sdp->sd_lockstruct.ls_first) {
|
|
|
unsigned int x;
|
|
|
for (x = 0; x < sdp->sd_journals; x++) {
|
|
|
- error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
|
|
|
- true);
|
|
|
+ struct gfs2_jdesc *jd = gfs2_jdesc_find(sdp, x);
|
|
|
+
|
|
|
+ if (sdp->sd_args.ar_spectator) {
|
|
|
+ error = check_journal_clean(sdp, jd);
|
|
|
+ if (error)
|
|
|
+ goto fail_jinode_gh;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ error = gfs2_recover_journal(jd, true);
|
|
|
if (error) {
|
|
|
fs_err(sdp, "error recovering journal %u: %d\n",
|
|
|
x, error);
|