diff options
Diffstat (limited to 'fs/nilfs2/cpfile.c')
| -rw-r--r-- | fs/nilfs2/cpfile.c | 140 | 
1 files changed, 78 insertions, 62 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 5ff15a8a102..0d58075f34e 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -216,14 +216,14 @@ int nilfs_cpfile_get_checkpoint(struct inode *cpfile,  		if (!nilfs_cpfile_is_in_first(cpfile, cno))  			nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,  								 kaddr, 1); -		nilfs_mdt_mark_buffer_dirty(cp_bh); +		mark_buffer_dirty(cp_bh); -		kaddr = kmap_atomic(header_bh->b_page, KM_USER0); +		kaddr = kmap_atomic(header_bh->b_page);  		header = nilfs_cpfile_block_get_header(cpfile, header_bh,  						       kaddr);  		le64_add_cpu(&header->ch_ncheckpoints, 1); -		kunmap_atomic(kaddr, KM_USER0); -		nilfs_mdt_mark_buffer_dirty(header_bh); +		kunmap_atomic(kaddr); +		mark_buffer_dirty(header_bh);  		nilfs_mdt_mark_dirty(cpfile);  	} @@ -286,7 +286,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,  	__u64 cno;  	void *kaddr;  	unsigned long tnicps; -	int ret, ncps, nicps, count, i; +	int ret, ncps, nicps, nss, count, i;  	if (unlikely(start == 0 || start > end)) {  		printk(KERN_ERR "%s: invalid range of checkpoint numbers: " @@ -301,6 +301,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,  	if (ret < 0)  		goto out_sem;  	tnicps = 0; +	nss = 0;  	for (cno = start; cno < end; cno += ncps) {  		ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end); @@ -313,20 +314,21 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,  			continue;  		} -		kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); +		kaddr = kmap_atomic(cp_bh->b_page);  		cp = nilfs_cpfile_block_get_checkpoint(  			cpfile, cno, cp_bh, kaddr);  		nicps = 0;  		for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) { -			WARN_ON(nilfs_checkpoint_snapshot(cp)); -			if (!nilfs_checkpoint_invalid(cp)) { +			if (nilfs_checkpoint_snapshot(cp)) { +				nss++; +			} else if (!nilfs_checkpoint_invalid(cp)) {  				nilfs_checkpoint_set_invalid(cp);  				nicps++;  			}  		}  		if (nicps > 0) {  			tnicps += nicps; -			nilfs_mdt_mark_buffer_dirty(cp_bh); +			mark_buffer_dirty(cp_bh);  			nilfs_mdt_mark_dirty(cpfile);  			if (!nilfs_cpfile_is_in_first(cpfile, cno)) {  				count = @@ -334,7 +336,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,  						cpfile, cp_bh, kaddr, nicps);  				if (count == 0) {  					/* make hole */ -					kunmap_atomic(kaddr, KM_USER0); +					kunmap_atomic(kaddr);  					brelse(cp_bh);  					ret =  					  nilfs_cpfile_delete_checkpoint_block( @@ -349,21 +351,23 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,  			}  		} -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		brelse(cp_bh);  	}  	if (tnicps > 0) { -		kaddr = kmap_atomic(header_bh->b_page, KM_USER0); +		kaddr = kmap_atomic(header_bh->b_page);  		header = nilfs_cpfile_block_get_header(cpfile, header_bh,  						       kaddr);  		le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps); -		nilfs_mdt_mark_buffer_dirty(header_bh); +		mark_buffer_dirty(header_bh);  		nilfs_mdt_mark_dirty(cpfile); -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  	}  	brelse(header_bh); +	if (nss > 0) +		ret = -EBUSY;   out_sem:  	up_write(&NILFS_MDT(cpfile)->mi_sem); @@ -408,7 +412,7 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,  			continue; /* skip hole */  		} -		kaddr = kmap_atomic(bh->b_page, KM_USER0); +		kaddr = kmap_atomic(bh->b_page);  		cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);  		for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {  			if (!nilfs_checkpoint_invalid(cp)) { @@ -418,7 +422,7 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,  				n++;  			}  		} -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		brelse(bh);  	} @@ -451,10 +455,10 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,  		ret = nilfs_cpfile_get_header_block(cpfile, &bh);  		if (ret < 0)  			goto out; -		kaddr = kmap_atomic(bh->b_page, KM_USER0); +		kaddr = kmap_atomic(bh->b_page);  		header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);  		curr = le64_to_cpu(header->ch_snapshot_list.ssl_next); -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		brelse(bh);  		if (curr == 0) {  			ret = 0; @@ -472,7 +476,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,  			ret = 0; /* No snapshots (started from a hole block) */  		goto out;  	} -	kaddr = kmap_atomic(bh->b_page, KM_USER0); +	kaddr = kmap_atomic(bh->b_page);  	while (n < nci) {  		cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);  		curr = ~(__u64)0; /* Terminator */ @@ -488,7 +492,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,  		next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);  		if (curr_blkoff != next_blkoff) { -			kunmap_atomic(kaddr, KM_USER0); +			kunmap_atomic(kaddr);  			brelse(bh);  			ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,  								0, &bh); @@ -496,12 +500,12 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,  				WARN_ON(ret == -ENOENT);  				goto out;  			} -			kaddr = kmap_atomic(bh->b_page, KM_USER0); +			kaddr = kmap_atomic(bh->b_page);  		}  		curr = next;  		curr_blkoff = next_blkoff;  	} -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	brelse(bh);  	*cnop = curr;  	ret = n; @@ -592,24 +596,24 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)  	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);  	if (ret < 0)  		goto out_sem; -	kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(cp_bh->b_page);  	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);  	if (nilfs_checkpoint_invalid(cp)) {  		ret = -ENOENT; -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		goto out_cp;  	}  	if (nilfs_checkpoint_snapshot(cp)) {  		ret = 0; -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		goto out_cp;  	} -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);  	if (ret < 0)  		goto out_cp; -	kaddr = kmap_atomic(header_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(header_bh->b_page);  	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);  	list = &header->ch_snapshot_list;  	curr_bh = header_bh; @@ -621,13 +625,13 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)  		prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);  		curr = prev;  		if (curr_blkoff != prev_blkoff) { -			kunmap_atomic(kaddr, KM_USER0); +			kunmap_atomic(kaddr);  			brelse(curr_bh);  			ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,  								0, &curr_bh);  			if (ret < 0)  				goto out_header; -			kaddr = kmap_atomic(curr_bh->b_page, KM_USER0); +			kaddr = kmap_atomic(curr_bh->b_page);  		}  		curr_blkoff = prev_blkoff;  		cp = nilfs_cpfile_block_get_checkpoint( @@ -635,7 +639,7 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)  		list = &cp->cp_snapshot_list;  		prev = le64_to_cpu(list->ssl_prev);  	} -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	if (prev != 0) {  		ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, @@ -647,34 +651,34 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)  		get_bh(prev_bh);  	} -	kaddr = kmap_atomic(curr_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(curr_bh->b_page);  	list = nilfs_cpfile_block_get_snapshot_list(  		cpfile, curr, curr_bh, kaddr);  	list->ssl_prev = cpu_to_le64(cno); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(cp_bh->b_page);  	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);  	cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);  	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);  	nilfs_checkpoint_set_snapshot(cp); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(prev_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(prev_bh->b_page);  	list = nilfs_cpfile_block_get_snapshot_list(  		cpfile, prev, prev_bh, kaddr);  	list->ssl_next = cpu_to_le64(cno); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(header_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(header_bh->b_page);  	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);  	le64_add_cpu(&header->ch_nsnapshots, 1); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	nilfs_mdt_mark_buffer_dirty(prev_bh); -	nilfs_mdt_mark_buffer_dirty(curr_bh); -	nilfs_mdt_mark_buffer_dirty(cp_bh); -	nilfs_mdt_mark_buffer_dirty(header_bh); +	mark_buffer_dirty(prev_bh); +	mark_buffer_dirty(curr_bh); +	mark_buffer_dirty(cp_bh); +	mark_buffer_dirty(header_bh);  	nilfs_mdt_mark_dirty(cpfile);  	brelse(prev_bh); @@ -710,23 +714,23 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)  	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);  	if (ret < 0)  		goto out_sem; -	kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(cp_bh->b_page);  	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);  	if (nilfs_checkpoint_invalid(cp)) {  		ret = -ENOENT; -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		goto out_cp;  	}  	if (!nilfs_checkpoint_snapshot(cp)) {  		ret = 0; -		kunmap_atomic(kaddr, KM_USER0); +		kunmap_atomic(kaddr);  		goto out_cp;  	}  	list = &cp->cp_snapshot_list;  	next = le64_to_cpu(list->ssl_next);  	prev = le64_to_cpu(list->ssl_prev); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);  	if (ret < 0) @@ -750,34 +754,34 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)  		get_bh(prev_bh);  	} -	kaddr = kmap_atomic(next_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(next_bh->b_page);  	list = nilfs_cpfile_block_get_snapshot_list(  		cpfile, next, next_bh, kaddr);  	list->ssl_prev = cpu_to_le64(prev); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(prev_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(prev_bh->b_page);  	list = nilfs_cpfile_block_get_snapshot_list(  		cpfile, prev, prev_bh, kaddr);  	list->ssl_next = cpu_to_le64(next); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(cp_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(cp_bh->b_page);  	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);  	cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);  	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);  	nilfs_checkpoint_clear_snapshot(cp); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	kaddr = kmap_atomic(header_bh->b_page, KM_USER0); +	kaddr = kmap_atomic(header_bh->b_page);  	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);  	le64_add_cpu(&header->ch_nsnapshots, -1); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr); -	nilfs_mdt_mark_buffer_dirty(next_bh); -	nilfs_mdt_mark_buffer_dirty(prev_bh); -	nilfs_mdt_mark_buffer_dirty(cp_bh); -	nilfs_mdt_mark_buffer_dirty(header_bh); +	mark_buffer_dirty(next_bh); +	mark_buffer_dirty(prev_bh); +	mark_buffer_dirty(cp_bh); +	mark_buffer_dirty(header_bh);  	nilfs_mdt_mark_dirty(cpfile);  	brelse(prev_bh); @@ -829,13 +833,13 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)  	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);  	if (ret < 0)  		goto out; -	kaddr = kmap_atomic(bh->b_page, KM_USER0); +	kaddr = kmap_atomic(bh->b_page);  	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);  	if (nilfs_checkpoint_invalid(cp))  		ret = -ENOENT;  	else  		ret = nilfs_checkpoint_snapshot(cp); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	brelse(bh);   out: @@ -912,12 +916,12 @@ int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)  	ret = nilfs_cpfile_get_header_block(cpfile, &bh);  	if (ret < 0)  		goto out_sem; -	kaddr = kmap_atomic(bh->b_page, KM_USER0); +	kaddr = kmap_atomic(bh->b_page);  	header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);  	cpstat->cs_cno = nilfs_mdt_cno(cpfile);  	cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);  	cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots); -	kunmap_atomic(kaddr, KM_USER0); +	kunmap_atomic(kaddr);  	brelse(bh);   out_sem: @@ -938,6 +942,18 @@ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,  	struct inode *cpfile;  	int err; +	if (cpsize > sb->s_blocksize) { +		printk(KERN_ERR +		       "NILFS: too large checkpoint size: %zu bytes.\n", +		       cpsize); +		return -EINVAL; +	} else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) { +		printk(KERN_ERR +		       "NILFS: too small checkpoint size: %zu bytes.\n", +		       cpsize); +		return -EINVAL; +	} +  	cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);  	if (unlikely(!cpfile))  		return -ENOMEM;  | 
