Exemple #1
0
static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
	struct super_block *sb = vfs->mnt_sb;
	struct nilfs_sb_info *sbi = NILFS_SB(sb);

	if (!nilfs_test_opt(sbi, BARRIER))
		seq_printf(seq, ",nobarrier");
	if (nilfs_test_opt(sbi, SNAPSHOT))
		seq_printf(seq, ",cp=%llu",
			   (unsigned long long int)sbi->s_snapshot_cno);
	if (nilfs_test_opt(sbi, ERRORS_RO))
		seq_printf(seq, ",errors=remount-ro");
	if (nilfs_test_opt(sbi, ERRORS_PANIC))
		seq_printf(seq, ",errors=panic");
	if (nilfs_test_opt(sbi, STRICT_ORDER))
		seq_printf(seq, ",order=strict");
	if (nilfs_test_opt(sbi, NORECOVERY))
		seq_printf(seq, ",norecovery");

	return 0;
}
Exemple #2
0
static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
	struct super_block *sb = vfs->mnt_sb;
	struct nilfs_sb_info *sbi = NILFS_SB(sb);
	struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root;

	if (!nilfs_test_opt(sbi, BARRIER))
		seq_puts(seq, ",nobarrier");
	if (root->cno != NILFS_CPTREE_CURRENT_CNO)
		seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno);
	if (nilfs_test_opt(sbi, ERRORS_PANIC))
		seq_puts(seq, ",errors=panic");
	if (nilfs_test_opt(sbi, ERRORS_CONT))
		seq_puts(seq, ",errors=continue");
	if (nilfs_test_opt(sbi, STRICT_ORDER))
		seq_puts(seq, ",order=strict");
	if (nilfs_test_opt(sbi, NORECOVERY))
		seq_puts(seq, ",norecovery");
	if (nilfs_test_opt(sbi, DISCARD))
		seq_puts(seq, ",discard");

	return 0;
}
Exemple #3
0
static int nilfs_show_options(struct seq_file *seq, struct dentry *dentry)
{
	struct super_block *sb = dentry->d_sb;
	struct the_nilfs *nilfs = sb->s_fs_info;
	struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root;

	if (!nilfs_test_opt(nilfs, BARRIER))
		seq_puts(seq, ",nobarrier");
	if (root->cno != NILFS_CPTREE_CURRENT_CNO)
		seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno);
	if (nilfs_test_opt(nilfs, ERRORS_PANIC))
		seq_puts(seq, ",errors=panic");
	if (nilfs_test_opt(nilfs, ERRORS_CONT))
		seq_puts(seq, ",errors=continue");
	if (nilfs_test_opt(nilfs, STRICT_ORDER))
		seq_puts(seq, ",order=strict");
	if (nilfs_test_opt(nilfs, NORECOVERY))
		seq_puts(seq, ",norecovery");
	if (nilfs_test_opt(nilfs, DISCARD))
		seq_puts(seq, ",discard");

	return 0;
}
Exemple #4
0
static int nilfs_remount(struct super_block *sb, int *flags, char *data)
{
	struct nilfs_sb_info *sbi = NILFS_SB(sb);
	struct nilfs_super_block *sbp;
	struct the_nilfs *nilfs = sbi->s_nilfs;
	unsigned long old_sb_flags;
	struct nilfs_mount_options old_opts;
	int was_snapshot, err;

	down_write(&nilfs->ns_super_sem);
	old_sb_flags = sb->s_flags;
	old_opts.mount_opt = sbi->s_mount_opt;
	old_opts.snapshot_cno = sbi->s_snapshot_cno;
	was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);

	if (!parse_options(data, sb)) {
		err = -EINVAL;
		goto restore_opts;
	}
	sb->s_flags = (sb->s_flags & ~MS_POSIXACL);

	err = -EINVAL;
	if (was_snapshot) {
		if (!(*flags & MS_RDONLY)) {
			printk(KERN_ERR "NILFS (device %s): cannot remount "
			       "snapshot read/write.\n",
			       sb->s_id);
			goto restore_opts;
		} else if (sbi->s_snapshot_cno != old_opts.snapshot_cno) {
			printk(KERN_ERR "NILFS (device %s): cannot "
			       "remount to a different snapshot.\n",
			       sb->s_id);
			goto restore_opts;
		}
	} else {
		if (nilfs_test_opt(sbi, SNAPSHOT)) {
			printk(KERN_ERR "NILFS (device %s): cannot change "
			       "a regular mount to a snapshot.\n",
			       sb->s_id);
			goto restore_opts;
		}
	}

	if (!nilfs_valid_fs(nilfs)) {
		printk(KERN_WARNING "NILFS (device %s): couldn't "
		       "remount because the filesystem is in an "
		       "incomplete recovery state.\n", sb->s_id);
		goto restore_opts;
	}

	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
		goto out;
	if (*flags & MS_RDONLY) {
		/* Shutting down the segment constructor */
		nilfs_detach_segment_constructor(sbi);
		sb->s_flags |= MS_RDONLY;

		/*
		 * Remounting a valid RW partition RDONLY, so set
		 * the RDONLY flag and then mark the partition as valid again.
		 */
		down_write(&nilfs->ns_sem);
		sbp = nilfs->ns_sbp[0];
		if (!(sbp->s_state & le16_to_cpu(NILFS_VALID_FS)) &&
		    (nilfs->ns_mount_state & NILFS_VALID_FS))
			sbp->s_state = cpu_to_le16(nilfs->ns_mount_state);
		sbp->s_mtime = cpu_to_le64(get_seconds());
		nilfs_commit_super(sbi, 1);
		up_write(&nilfs->ns_sem);
	} else {
		/*
		 * Mounting a RDONLY partition read-write, so reread and
		 * store the current valid flag.  (It may have been changed
		 * by fsck since we originally mounted the partition.)
		 */
		sb->s_flags &= ~MS_RDONLY;

		err = nilfs_attach_segment_constructor(sbi);
		if (err)
			goto restore_opts;

		down_write(&nilfs->ns_sem);
		nilfs_setup_super(sbi);
		up_write(&nilfs->ns_sem);
	}
 out:
	up_write(&nilfs->ns_super_sem);
	return 0;

 restore_opts:
	sb->s_flags = old_sb_flags;
	sbi->s_mount_opt = old_opts.mount_opt;
	sbi->s_snapshot_cno = old_opts.snapshot_cno;
	up_write(&nilfs->ns_super_sem);
	return err;
}
Exemple #5
0
/**
 * nilfs_fill_super() - initialize a super block instance
 * @sb: super_block
 * @data: mount options
 * @silent: silent mode flag
 * @nilfs: the_nilfs struct
 *
 * This function is called exclusively by nilfs->ns_mount_mutex.
 * So, the recovery process is protected from other simultaneous mounts.
 */
static int
nilfs_fill_super(struct super_block *sb, void *data, int silent,
		 struct the_nilfs *nilfs)
{
	struct nilfs_sb_info *sbi;
	struct inode *root;
	__u64 cno;
	int err;

	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
	if (!sbi)
		return -ENOMEM;

	sb->s_fs_info = sbi;

	get_nilfs(nilfs);
	sbi->s_nilfs = nilfs;
	sbi->s_super = sb;
	atomic_set(&sbi->s_count, 1);

	err = init_nilfs(nilfs, sbi, (char *)data);
	if (err)
		goto failed_sbi;

	spin_lock_init(&sbi->s_inode_lock);
	INIT_LIST_HEAD(&sbi->s_dirty_files);
	INIT_LIST_HEAD(&sbi->s_list);

	/*
	 * Following initialization is overlapped because
	 * nilfs_sb_info structure has been cleared at the beginning.
	 * But we reserve them to keep our interest and make ready
	 * for the future change.
	 */
	get_random_bytes(&sbi->s_next_generation,
			 sizeof(sbi->s_next_generation));
	spin_lock_init(&sbi->s_next_gen_lock);

	sb->s_op = &nilfs_sops;
	sb->s_export_op = &nilfs_export_ops;
	sb->s_root = NULL;
	sb->s_time_gran = 1;
	sb->s_bdi = nilfs->ns_bdi;

	err = load_nilfs(nilfs, sbi);
	if (err)
		goto failed_sbi;

	cno = nilfs_last_cno(nilfs);

	if (sb->s_flags & MS_RDONLY) {
		if (nilfs_test_opt(sbi, SNAPSHOT)) {
			down_read(&nilfs->ns_segctor_sem);
			err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile,
						       sbi->s_snapshot_cno);
			up_read(&nilfs->ns_segctor_sem);
			if (err < 0) {
				if (err == -ENOENT)
					err = -EINVAL;
				goto failed_sbi;
			}
			if (!err) {
				printk(KERN_ERR
				       "NILFS: The specified checkpoint is "
				       "not a snapshot "
				       "(checkpoint number=%llu).\n",
				       (unsigned long long)sbi->s_snapshot_cno);
				err = -EINVAL;
				goto failed_sbi;
			}
			cno = sbi->s_snapshot_cno;
		}
	}

	err = nilfs_attach_checkpoint(sbi, cno);
	if (err) {
		printk(KERN_ERR "NILFS: error loading a checkpoint"
		       " (checkpoint number=%llu).\n", (unsigned long long)cno);
		goto failed_sbi;
	}

	if (!(sb->s_flags & MS_RDONLY)) {
		err = nilfs_attach_segment_constructor(sbi);
		if (err)
			goto failed_checkpoint;
	}

	root = nilfs_iget(sb, NILFS_ROOT_INO);
	if (IS_ERR(root)) {
		printk(KERN_ERR "NILFS: get root inode failed\n");
		err = PTR_ERR(root);
		goto failed_segctor;
	}
	if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
		iput(root);
		printk(KERN_ERR "NILFS: corrupt root inode.\n");
		err = -EINVAL;
		goto failed_segctor;
	}
	sb->s_root = d_alloc_root(root);
	if (!sb->s_root) {
		iput(root);
		printk(KERN_ERR "NILFS: get root dentry failed\n");
		err = -ENOMEM;
		goto failed_segctor;
	}

	if (!(sb->s_flags & MS_RDONLY)) {
		down_write(&nilfs->ns_sem);
		nilfs_setup_super(sbi);
		up_write(&nilfs->ns_sem);
	}

	down_write(&nilfs->ns_super_sem);
	if (!nilfs_test_opt(sbi, SNAPSHOT))
		nilfs->ns_current = sbi;
	up_write(&nilfs->ns_super_sem);

	return 0;

 failed_segctor:
	nilfs_detach_segment_constructor(sbi);

 failed_checkpoint:
	nilfs_detach_checkpoint(sbi);

 failed_sbi:
	put_nilfs(nilfs);
	sb->s_fs_info = NULL;
	nilfs_put_sbinfo(sbi);
	return err;
}
Exemple #6
0
static int nilfs_remount(struct super_block *sb, int *flags, char *data)
{
	struct the_nilfs *nilfs = sb->s_fs_info;
	unsigned long old_sb_flags;
	unsigned long old_mount_opt;
	int err;

	lock_kernel();

	old_sb_flags = sb->s_flags;
	old_mount_opt = nilfs->ns_mount_opt;

	if (!parse_options(data, sb, 1)) {
		err = -EINVAL;
		goto restore_opts;
	}
	sb->s_flags = (sb->s_flags & ~MS_POSIXACL);

	err = -EINVAL;

	if (!nilfs_valid_fs(nilfs)) {
		printk(KERN_WARNING "NILFS (device %s): couldn't "
		       "remount because the filesystem is in an "
		       "incomplete recovery state.\n", sb->s_id);
		goto restore_opts;
	}

	if (nilfs_test_opt(nilfs, BARRIER))
		set_nilfs_sb_barrier(nilfs);
	else
		clear_nilfs_sb_barrier(nilfs);

	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
		goto out;
	if (*flags & MS_RDONLY) {
		/* Shutting down log writer */
		nilfs_detach_log_writer(sb);
		sb->s_flags |= MS_RDONLY;

		/*
		 * Remounting a valid RW partition RDONLY, so set
		 * the RDONLY flag and then mark the partition as valid again.
		 */
		down_write(&nilfs->ns_sem);
		nilfs_cleanup_super(sb);
		up_write(&nilfs->ns_sem);
	} else {
		__u64 features;
		struct nilfs_root *root;

		/*
		 * Mounting a RDONLY partition read-write, so reread and
		 * store the current valid flag.  (It may have been changed
		 * by fsck since we originally mounted the partition.)
		 */
		down_read(&nilfs->ns_sem);
		features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
			~NILFS_FEATURE_COMPAT_RO_SUPP;
		up_read(&nilfs->ns_sem);
		if (features) {
			printk(KERN_WARNING "NILFS (device %s): couldn't "
			       "remount RDWR because of unsupported optional "
			       "features (%llx)\n",
			       sb->s_id, (unsigned long long)features);
			err = -EROFS;
			goto restore_opts;
		}

		sb->s_flags &= ~MS_RDONLY;

		root = NILFS_I(sb->s_root->d_inode)->i_root;
		err = nilfs_attach_log_writer(sb, root);
		if (err)
			goto restore_opts;

		down_write(&nilfs->ns_sem);
		nilfs_setup_super(sb, true);
		up_write(&nilfs->ns_sem);
	}
 out:
	unlock_kernel();
	return 0;

 restore_opts:
	sb->s_flags = old_sb_flags;
	nilfs->ns_mount_opt = old_mount_opt;
	unlock_kernel();
	return err;
}
Exemple #7
0
static int nilfs_remount(struct super_block *sb, int *flags, char *data)
{
    struct nilfs_sb_info *sbi = NILFS_SB(sb);
    struct the_nilfs *nilfs = sbi->s_nilfs;
    unsigned long old_sb_flags;
    struct nilfs_mount_options old_opts;
    int was_snapshot, err;

    lock_kernel();

    down_write(&nilfs->ns_super_sem);
    old_sb_flags = sb->s_flags;
    old_opts.mount_opt = sbi->s_mount_opt;
    old_opts.snapshot_cno = sbi->s_snapshot_cno;
    was_snapshot = nilfs_test_opt(sbi, SNAPSHOT);

    if (!parse_options(data, sb, 1)) {
        err = -EINVAL;
        goto restore_opts;
    }
    sb->s_flags = (sb->s_flags & ~MS_POSIXACL);

    err = -EINVAL;
    if (was_snapshot && !(*flags & MS_RDONLY)) {
        printk(KERN_ERR "NILFS (device %s): cannot remount snapshot "
               "read/write.\n", sb->s_id);
        goto restore_opts;
    }

    if (!nilfs_valid_fs(nilfs)) {
        printk(KERN_WARNING "NILFS (device %s): couldn't "
               "remount because the filesystem is in an "
               "incomplete recovery state.\n", sb->s_id);
        goto restore_opts;
    }

    if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
        goto out;
    if (*flags & MS_RDONLY) {
        /* Shutting down the segment constructor */
        nilfs_detach_segment_constructor(sbi);
        sb->s_flags |= MS_RDONLY;

        /*
         * Remounting a valid RW partition RDONLY, so set
         * the RDONLY flag and then mark the partition as valid again.
         */
        down_write(&nilfs->ns_sem);
        nilfs_cleanup_super(sbi);
        up_write(&nilfs->ns_sem);
    } else {
        __u64 features;

        /*
         * Mounting a RDONLY partition read-write, so reread and
         * store the current valid flag.  (It may have been changed
         * by fsck since we originally mounted the partition.)
         */
        down_read(&nilfs->ns_sem);
        features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
                   ~NILFS_FEATURE_COMPAT_RO_SUPP;
        up_read(&nilfs->ns_sem);
        if (features) {
            printk(KERN_WARNING "NILFS (device %s): couldn't "
                   "remount RDWR because of unsupported optional "
                   "features (%llx)\n",
                   sb->s_id, (unsigned long long)features);
            err = -EROFS;
            goto restore_opts;
        }

        sb->s_flags &= ~MS_RDONLY;

        err = nilfs_attach_segment_constructor(sbi);
        if (err)
            goto restore_opts;

        down_write(&nilfs->ns_sem);
        nilfs_setup_super(sbi);
        up_write(&nilfs->ns_sem);
    }
out:
    up_write(&nilfs->ns_super_sem);
    unlock_kernel();
    return 0;

restore_opts:
    sb->s_flags = old_sb_flags;
    sbi->s_mount_opt = old_opts.mount_opt;
    sbi->s_snapshot_cno = old_opts.snapshot_cno;
    up_write(&nilfs->ns_super_sem);
    unlock_kernel();
    return err;
}
Exemple #8
0
static int parse_options(char *options, struct super_block *sb, int is_remount)
{
    struct nilfs_sb_info *sbi = NILFS_SB(sb);
    char *p;
    substring_t args[MAX_OPT_ARGS];
    int option;

    if (!options)
        return 1;

    while ((p = strsep(&options, ",")) != NULL) {
        int token;
        if (!*p)
            continue;

        token = match_token(p, tokens, args);
        switch (token) {
        case Opt_barrier:
            nilfs_set_opt(sbi, BARRIER);
            break;
        case Opt_nobarrier:
            nilfs_clear_opt(sbi, BARRIER);
            break;
        case Opt_order:
            if (strcmp(args[0].from, "relaxed") == 0)
                /* Ordered data semantics */
                nilfs_clear_opt(sbi, STRICT_ORDER);
            else if (strcmp(args[0].from, "strict") == 0)
                /* Strict in-order semantics */
                nilfs_set_opt(sbi, STRICT_ORDER);
            else
                return 0;
            break;
        case Opt_err_panic:
            nilfs_write_opt(sbi, ERROR_MODE, ERRORS_PANIC);
            break;
        case Opt_err_ro:
            nilfs_write_opt(sbi, ERROR_MODE, ERRORS_RO);
            break;
        case Opt_err_cont:
            nilfs_write_opt(sbi, ERROR_MODE, ERRORS_CONT);
            break;
        case Opt_snapshot:
            if (match_int(&args[0], &option) || option <= 0)
                return 0;
            if (is_remount) {
                if (!nilfs_test_opt(sbi, SNAPSHOT)) {
                    printk(KERN_ERR
                           "NILFS: cannot change regular "
                           "mount to snapshot.\n");
                    return 0;
                } else if (option != sbi->s_snapshot_cno) {
                    printk(KERN_ERR
                           "NILFS: cannot remount to a "
                           "different snapshot.\n");
                    return 0;
                }
                break;
            }
            if (!(sb->s_flags & MS_RDONLY)) {
                printk(KERN_ERR "NILFS: cannot mount snapshot "
                       "read/write.  A read-only option is "
                       "required.\n");
                return 0;
            }
            sbi->s_snapshot_cno = option;
            nilfs_set_opt(sbi, SNAPSHOT);
            break;
        case Opt_norecovery:
            nilfs_set_opt(sbi, NORECOVERY);
            break;
        case Opt_discard:
            nilfs_set_opt(sbi, DISCARD);
            break;
        case Opt_nodiscard:
            nilfs_clear_opt(sbi, DISCARD);
            break;
        default:
            printk(KERN_ERR
                   "NILFS: Unrecognized mount option \"%s\"\n", p);
            return 0;
        }
    }
    return 1;
}
Exemple #9
0
static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag)
{
    struct the_nilfs *nilfs = sbi->s_nilfs;
    int err;

retry:
    set_buffer_dirty(nilfs->ns_sbh[0]);

    if (nilfs_test_opt(sbi, BARRIER)) {
        err = __sync_dirty_buffer(nilfs->ns_sbh[0],
                                  WRITE_SYNC | WRITE_BARRIER);
        if (err == -EOPNOTSUPP) {
            nilfs_warning(sbi->s_super, __func__,
                          "barrier-based sync failed. "
                          "disabling barriers\n");
            nilfs_clear_opt(sbi, BARRIER);
            goto retry;
        }
    } else {
        err = sync_dirty_buffer(nilfs->ns_sbh[0]);
    }

    if (unlikely(err)) {
        printk(KERN_ERR
               "NILFS: unable to write superblock (err=%d)\n", err);
        if (err == -EIO && nilfs->ns_sbh[1]) {
            /*
             * sbp[0] points to newer log than sbp[1],
             * so copy sbp[0] to sbp[1] to take over sbp[0].
             */
            memcpy(nilfs->ns_sbp[1], nilfs->ns_sbp[0],
                   nilfs->ns_sbsize);
            nilfs_fall_back_super_block(nilfs);
            goto retry;
        }
    } else {
        struct nilfs_super_block *sbp = nilfs->ns_sbp[0];

        nilfs->ns_sbwcount++;

        /*
         * The latest segment becomes trailable from the position
         * written in superblock.
         */
        clear_nilfs_discontinued(nilfs);

        /* update GC protection for recent segments */
        if (nilfs->ns_sbh[1]) {
            if (flag == NILFS_SB_COMMIT_ALL) {
                set_buffer_dirty(nilfs->ns_sbh[1]);
                if (sync_dirty_buffer(nilfs->ns_sbh[1]) < 0)
                    goto out;
            }
            if (le64_to_cpu(nilfs->ns_sbp[1]->s_last_cno) <
                    le64_to_cpu(nilfs->ns_sbp[0]->s_last_cno))
                sbp = nilfs->ns_sbp[1];
        }

        spin_lock(&nilfs->ns_last_segment_lock);
        nilfs->ns_prot_seq = le64_to_cpu(sbp->s_last_seq);
        spin_unlock(&nilfs->ns_last_segment_lock);
    }
out:
    return err;
}