brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · 0bef662 Raw
538 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS disk address translation.4 *5 * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Written by Koji Sato.8 */9 10#include <linux/types.h>11#include <linux/buffer_head.h>12#include <linux/string.h>13#include <linux/errno.h>14#include "nilfs.h"15#include "mdt.h"16#include "alloc.h"17#include "dat.h"18 19 20#define NILFS_CNO_MIN	((__u64)1)21#define NILFS_CNO_MAX	(~(__u64)0)22 23/**24 * struct nilfs_dat_info - on-memory private data of DAT file25 * @mi: on-memory private data of metadata file26 * @palloc_cache: persistent object allocator cache of DAT file27 * @shadow: shadow map of DAT file28 */29struct nilfs_dat_info {30	struct nilfs_mdt_info mi;31	struct nilfs_palloc_cache palloc_cache;32	struct nilfs_shadow_map shadow;33};34 35static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat)36{37	return (struct nilfs_dat_info *)NILFS_MDT(dat);38}39 40static int nilfs_dat_prepare_entry(struct inode *dat,41				   struct nilfs_palloc_req *req, int create)42{43	int ret;44 45	ret = nilfs_palloc_get_entry_block(dat, req->pr_entry_nr,46					   create, &req->pr_entry_bh);47	if (unlikely(ret == -ENOENT)) {48		nilfs_err(dat->i_sb,49			  "DAT doesn't have a block to manage vblocknr = %llu",50			  (unsigned long long)req->pr_entry_nr);51		/*52		 * Return internal code -EINVAL to notify bmap layer of53		 * metadata corruption.54		 */55		ret = -EINVAL;56	}57	return ret;58}59 60static void nilfs_dat_commit_entry(struct inode *dat,61				   struct nilfs_palloc_req *req)62{63	mark_buffer_dirty(req->pr_entry_bh);64	nilfs_mdt_mark_dirty(dat);65	brelse(req->pr_entry_bh);66}67 68static void nilfs_dat_abort_entry(struct inode *dat,69				  struct nilfs_palloc_req *req)70{71	brelse(req->pr_entry_bh);72}73 74int nilfs_dat_prepare_alloc(struct inode *dat, struct nilfs_palloc_req *req)75{76	int ret;77 78	ret = nilfs_palloc_prepare_alloc_entry(dat, req, true);79	if (ret < 0)80		return ret;81 82	ret = nilfs_dat_prepare_entry(dat, req, 1);83	if (ret < 0)84		nilfs_palloc_abort_alloc_entry(dat, req);85 86	return ret;87}88 89void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req)90{91	struct nilfs_dat_entry *entry;92	void *kaddr;93 94	kaddr = kmap_local_page(req->pr_entry_bh->b_page);95	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,96					     req->pr_entry_bh, kaddr);97	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);98	entry->de_end = cpu_to_le64(NILFS_CNO_MAX);99	entry->de_blocknr = cpu_to_le64(0);100	kunmap_local(kaddr);101 102	nilfs_palloc_commit_alloc_entry(dat, req);103	nilfs_dat_commit_entry(dat, req);104}105 106void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req)107{108	nilfs_dat_abort_entry(dat, req);109	nilfs_palloc_abort_alloc_entry(dat, req);110}111 112static void nilfs_dat_commit_free(struct inode *dat,113				  struct nilfs_palloc_req *req)114{115	struct nilfs_dat_entry *entry;116	void *kaddr;117 118	kaddr = kmap_local_page(req->pr_entry_bh->b_page);119	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,120					     req->pr_entry_bh, kaddr);121	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);122	entry->de_end = cpu_to_le64(NILFS_CNO_MIN);123	entry->de_blocknr = cpu_to_le64(0);124	kunmap_local(kaddr);125 126	nilfs_dat_commit_entry(dat, req);127 128	if (unlikely(req->pr_desc_bh == NULL || req->pr_bitmap_bh == NULL)) {129		nilfs_error(dat->i_sb,130			    "state inconsistency probably due to duplicate use of vblocknr = %llu",131			    (unsigned long long)req->pr_entry_nr);132		return;133	}134	nilfs_palloc_commit_free_entry(dat, req);135}136 137int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req)138{139	return nilfs_dat_prepare_entry(dat, req, 0);140}141 142void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,143			    sector_t blocknr)144{145	struct nilfs_dat_entry *entry;146	void *kaddr;147 148	kaddr = kmap_local_page(req->pr_entry_bh->b_page);149	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,150					     req->pr_entry_bh, kaddr);151	entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat));152	entry->de_blocknr = cpu_to_le64(blocknr);153	kunmap_local(kaddr);154 155	nilfs_dat_commit_entry(dat, req);156}157 158int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)159{160	struct nilfs_dat_entry *entry;161	__u64 start;162	sector_t blocknr;163	void *kaddr;164	int ret;165 166	ret = nilfs_dat_prepare_entry(dat, req, 0);167	if (ret < 0)168		return ret;169 170	kaddr = kmap_local_page(req->pr_entry_bh->b_page);171	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,172					     req->pr_entry_bh, kaddr);173	start = le64_to_cpu(entry->de_start);174	blocknr = le64_to_cpu(entry->de_blocknr);175	kunmap_local(kaddr);176 177	if (blocknr == 0) {178		ret = nilfs_palloc_prepare_free_entry(dat, req);179		if (ret < 0) {180			nilfs_dat_abort_entry(dat, req);181			return ret;182		}183	}184	if (unlikely(start > nilfs_mdt_cno(dat))) {185		nilfs_err(dat->i_sb,186			  "vblocknr = %llu has abnormal lifetime: start cno (= %llu) > current cno (= %llu)",187			  (unsigned long long)req->pr_entry_nr,188			  (unsigned long long)start,189			  (unsigned long long)nilfs_mdt_cno(dat));190		nilfs_dat_abort_entry(dat, req);191		return -EINVAL;192	}193 194	return 0;195}196 197void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,198			  int dead)199{200	struct nilfs_dat_entry *entry;201	__u64 start, end;202	sector_t blocknr;203	void *kaddr;204 205	kaddr = kmap_local_page(req->pr_entry_bh->b_page);206	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,207					     req->pr_entry_bh, kaddr);208	end = start = le64_to_cpu(entry->de_start);209	if (!dead) {210		end = nilfs_mdt_cno(dat);211		WARN_ON(start > end);212	}213	entry->de_end = cpu_to_le64(end);214	blocknr = le64_to_cpu(entry->de_blocknr);215	kunmap_local(kaddr);216 217	if (blocknr == 0)218		nilfs_dat_commit_free(dat, req);219	else220		nilfs_dat_commit_entry(dat, req);221}222 223void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req)224{225	struct nilfs_dat_entry *entry;226	__u64 start;227	sector_t blocknr;228	void *kaddr;229 230	kaddr = kmap_local_page(req->pr_entry_bh->b_page);231	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,232					     req->pr_entry_bh, kaddr);233	start = le64_to_cpu(entry->de_start);234	blocknr = le64_to_cpu(entry->de_blocknr);235	kunmap_local(kaddr);236 237	if (start == nilfs_mdt_cno(dat) && blocknr == 0)238		nilfs_palloc_abort_free_entry(dat, req);239	nilfs_dat_abort_entry(dat, req);240}241 242int nilfs_dat_prepare_update(struct inode *dat,243			     struct nilfs_palloc_req *oldreq,244			     struct nilfs_palloc_req *newreq)245{246	int ret;247 248	ret = nilfs_dat_prepare_end(dat, oldreq);249	if (!ret) {250		ret = nilfs_dat_prepare_alloc(dat, newreq);251		if (ret < 0)252			nilfs_dat_abort_end(dat, oldreq);253	}254	return ret;255}256 257void nilfs_dat_commit_update(struct inode *dat,258			     struct nilfs_palloc_req *oldreq,259			     struct nilfs_palloc_req *newreq, int dead)260{261	nilfs_dat_commit_end(dat, oldreq, dead);262	nilfs_dat_commit_alloc(dat, newreq);263}264 265void nilfs_dat_abort_update(struct inode *dat,266			    struct nilfs_palloc_req *oldreq,267			    struct nilfs_palloc_req *newreq)268{269	nilfs_dat_abort_end(dat, oldreq);270	nilfs_dat_abort_alloc(dat, newreq);271}272 273/**274 * nilfs_dat_mark_dirty - mark the DAT block buffer containing the specified275 *                        virtual block address entry as dirty276 * @dat:      DAT file inode277 * @vblocknr: virtual block number278 *279 * Return: 0 on success, or the following negative error code on failure.280 * * %-EINVAL	- Invalid DAT entry (internal code).281 * * %-EIO	- I/O error (including metadata corruption).282 * * %-ENOMEM	- Insufficient memory available.283 */284int nilfs_dat_mark_dirty(struct inode *dat, __u64 vblocknr)285{286	struct nilfs_palloc_req req;287	int ret;288 289	req.pr_entry_nr = vblocknr;290	ret = nilfs_dat_prepare_entry(dat, &req, 0);291	if (ret == 0)292		nilfs_dat_commit_entry(dat, &req);293	return ret;294}295 296/**297 * nilfs_dat_freev - free virtual block numbers298 * @dat: DAT file inode299 * @vblocknrs: array of virtual block numbers300 * @nitems: number of virtual block numbers301 *302 * Description: nilfs_dat_freev() frees the virtual block numbers specified by303 * @vblocknrs and @nitems.304 *305 * Return Value: On success, 0 is returned. On error, one of the following306 * negative error codes is returned.307 *308 * %-EIO - I/O error.309 *310 * %-ENOMEM - Insufficient amount of memory available.311 *312 * %-ENOENT - The virtual block number have not been allocated.313 */314int nilfs_dat_freev(struct inode *dat, __u64 *vblocknrs, size_t nitems)315{316	return nilfs_palloc_freev(dat, vblocknrs, nitems);317}318 319/**320 * nilfs_dat_move - change a block number321 * @dat: DAT file inode322 * @vblocknr: virtual block number323 * @blocknr: block number324 *325 * Description: nilfs_dat_move() changes the block number associated with326 * @vblocknr to @blocknr.327 *328 * Return Value: On success, 0 is returned. On error, one of the following329 * negative error codes is returned.330 *331 * %-EIO - I/O error.332 *333 * %-ENOMEM - Insufficient amount of memory available.334 */335int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)336{337	struct buffer_head *entry_bh;338	struct nilfs_dat_entry *entry;339	void *kaddr;340	int ret;341 342	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);343	if (ret < 0)344		return ret;345 346	/*347	 * The given disk block number (blocknr) is not yet written to348	 * the device at this point.349	 *350	 * To prevent nilfs_dat_translate() from returning the351	 * uncommitted block number, this makes a copy of the entry352	 * buffer and redirects nilfs_dat_translate() to the copy.353	 */354	if (!buffer_nilfs_redirected(entry_bh)) {355		ret = nilfs_mdt_freeze_buffer(dat, entry_bh);356		if (ret) {357			brelse(entry_bh);358			return ret;359		}360	}361 362	kaddr = kmap_local_page(entry_bh->b_page);363	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);364	if (unlikely(entry->de_blocknr == cpu_to_le64(0))) {365		nilfs_crit(dat->i_sb,366			   "%s: invalid vblocknr = %llu, [%llu, %llu)",367			   __func__, (unsigned long long)vblocknr,368			   (unsigned long long)le64_to_cpu(entry->de_start),369			   (unsigned long long)le64_to_cpu(entry->de_end));370		kunmap_local(kaddr);371		brelse(entry_bh);372		return -EINVAL;373	}374	WARN_ON(blocknr == 0);375	entry->de_blocknr = cpu_to_le64(blocknr);376	kunmap_local(kaddr);377 378	mark_buffer_dirty(entry_bh);379	nilfs_mdt_mark_dirty(dat);380 381	brelse(entry_bh);382 383	return 0;384}385 386/**387 * nilfs_dat_translate - translate a virtual block number to a block number388 * @dat: DAT file inode389 * @vblocknr: virtual block number390 * @blocknrp: pointer to a block number391 *392 * Description: nilfs_dat_translate() maps the virtual block number @vblocknr393 * to the corresponding block number.394 *395 * Return Value: On success, 0 is returned and the block number associated396 * with @vblocknr is stored in the place pointed by @blocknrp. On error, one397 * of the following negative error codes is returned.398 *399 * %-EIO - I/O error.400 *401 * %-ENOMEM - Insufficient amount of memory available.402 *403 * %-ENOENT - A block number associated with @vblocknr does not exist.404 */405int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)406{407	struct buffer_head *entry_bh, *bh;408	struct nilfs_dat_entry *entry;409	sector_t blocknr;410	void *kaddr;411	int ret;412 413	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);414	if (ret < 0)415		return ret;416 417	if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) {418		bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh);419		if (bh) {420			WARN_ON(!buffer_uptodate(bh));421			brelse(entry_bh);422			entry_bh = bh;423		}424	}425 426	kaddr = kmap_local_page(entry_bh->b_page);427	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);428	blocknr = le64_to_cpu(entry->de_blocknr);429	if (blocknr == 0) {430		ret = -ENOENT;431		goto out;432	}433	*blocknrp = blocknr;434 435 out:436	kunmap_local(kaddr);437	brelse(entry_bh);438	return ret;439}440 441ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned int visz,442			    size_t nvi)443{444	struct buffer_head *entry_bh;445	struct nilfs_dat_entry *entry;446	struct nilfs_vinfo *vinfo = buf;447	__u64 first, last;448	void *kaddr;449	unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block;450	int i, j, n, ret;451 452	for (i = 0; i < nvi; i += n) {453		ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr,454						   0, &entry_bh);455		if (ret < 0)456			return ret;457		kaddr = kmap_local_page(entry_bh->b_page);458		/* last virtual block number in this block */459		first = vinfo->vi_vblocknr;460		first = div64_ul(first, entries_per_block);461		first *= entries_per_block;462		last = first + entries_per_block - 1;463		for (j = i, n = 0;464		     j < nvi && vinfo->vi_vblocknr >= first &&465			     vinfo->vi_vblocknr <= last;466		     j++, n++, vinfo = (void *)vinfo + visz) {467			entry = nilfs_palloc_block_get_entry(468				dat, vinfo->vi_vblocknr, entry_bh, kaddr);469			vinfo->vi_start = le64_to_cpu(entry->de_start);470			vinfo->vi_end = le64_to_cpu(entry->de_end);471			vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr);472		}473		kunmap_local(kaddr);474		brelse(entry_bh);475	}476 477	return nvi;478}479 480/**481 * nilfs_dat_read - read or get dat inode482 * @sb: super block instance483 * @entry_size: size of a dat entry484 * @raw_inode: on-disk dat inode485 * @inodep: buffer to store the inode486 */487int nilfs_dat_read(struct super_block *sb, size_t entry_size,488		   struct nilfs_inode *raw_inode, struct inode **inodep)489{490	static struct lock_class_key dat_lock_key;491	struct inode *dat;492	struct nilfs_dat_info *di;493	int err;494 495	if (entry_size > sb->s_blocksize) {496		nilfs_err(sb, "too large DAT entry size: %zu bytes",497			  entry_size);498		return -EINVAL;499	} else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) {500		nilfs_err(sb, "too small DAT entry size: %zu bytes",501			  entry_size);502		return -EINVAL;503	}504 505	dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);506	if (unlikely(!dat))507		return -ENOMEM;508	if (!(dat->i_state & I_NEW))509		goto out;510 511	err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));512	if (err)513		goto failed;514 515	err = nilfs_palloc_init_blockgroup(dat, entry_size);516	if (err)517		goto failed;518 519	di = NILFS_DAT_I(dat);520	lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);521	nilfs_palloc_setup_cache(dat, &di->palloc_cache);522	err = nilfs_mdt_setup_shadow_map(dat, &di->shadow);523	if (err)524		goto failed;525 526	err = nilfs_read_inode_common(dat, raw_inode);527	if (err)528		goto failed;529 530	unlock_new_inode(dat);531 out:532	*inodep = dat;533	return 0;534 failed:535	iget_failed(dat);536	return err;537}538