xref: /openbmc/linux/fs/nilfs2/dat.c (revision ee1cd5048959de496cd005c50b137212a5b62062)
1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+
2a17564f5SKoji Sato /*
394ee1d91SRyusuke Konishi  * NILFS disk address translation.
4a17564f5SKoji Sato  *
5a17564f5SKoji Sato  * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
6a17564f5SKoji Sato  *
74b420ab4SRyusuke Konishi  * Written by Koji Sato.
8a17564f5SKoji Sato  */
9a17564f5SKoji Sato 
10a17564f5SKoji Sato #include <linux/types.h>
11a17564f5SKoji Sato #include <linux/buffer_head.h>
12a17564f5SKoji Sato #include <linux/string.h>
13a17564f5SKoji Sato #include <linux/errno.h>
14a17564f5SKoji Sato #include "nilfs.h"
15a17564f5SKoji Sato #include "mdt.h"
16a17564f5SKoji Sato #include "alloc.h"
17a17564f5SKoji Sato #include "dat.h"
18a17564f5SKoji Sato 
19a17564f5SKoji Sato 
20a17564f5SKoji Sato #define NILFS_CNO_MIN	((__u64)1)
21a17564f5SKoji Sato #define NILFS_CNO_MAX	(~(__u64)0)
22a17564f5SKoji Sato 
23f5974c8fSVyacheslav Dubeyko /**
24f5974c8fSVyacheslav Dubeyko  * struct nilfs_dat_info - on-memory private data of DAT file
25f5974c8fSVyacheslav Dubeyko  * @mi: on-memory private data of metadata file
26f5974c8fSVyacheslav Dubeyko  * @palloc_cache: persistent object allocator cache of DAT file
27f5974c8fSVyacheslav Dubeyko  * @shadow: shadow map of DAT file
28f5974c8fSVyacheslav Dubeyko  */
298908b2f7SRyusuke Konishi struct nilfs_dat_info {
308908b2f7SRyusuke Konishi 	struct nilfs_mdt_info mi;
318908b2f7SRyusuke Konishi 	struct nilfs_palloc_cache palloc_cache;
32c1c1d709SRyusuke Konishi 	struct nilfs_shadow_map shadow;
338908b2f7SRyusuke Konishi };
348908b2f7SRyusuke Konishi 
NILFS_DAT_I(struct inode * dat)358908b2f7SRyusuke Konishi static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat)
368908b2f7SRyusuke Konishi {
378908b2f7SRyusuke Konishi 	return (struct nilfs_dat_info *)NILFS_MDT(dat);
388908b2f7SRyusuke Konishi }
398908b2f7SRyusuke Konishi 
nilfs_dat_prepare_entry(struct inode * dat,struct nilfs_palloc_req * req,int create)40a17564f5SKoji Sato static int nilfs_dat_prepare_entry(struct inode *dat,
41a17564f5SKoji Sato 				   struct nilfs_palloc_req *req, int create)
42a17564f5SKoji Sato {
435124a0a5SRyusuke Konishi 	int ret;
445124a0a5SRyusuke Konishi 
455124a0a5SRyusuke Konishi 	ret = nilfs_palloc_get_entry_block(dat, req->pr_entry_nr,
46a17564f5SKoji Sato 					   create, &req->pr_entry_bh);
475124a0a5SRyusuke Konishi 	if (unlikely(ret == -ENOENT)) {
485124a0a5SRyusuke Konishi 		nilfs_err(dat->i_sb,
495124a0a5SRyusuke Konishi 			  "DAT doesn't have a block to manage vblocknr = %llu",
505124a0a5SRyusuke Konishi 			  (unsigned long long)req->pr_entry_nr);
515124a0a5SRyusuke Konishi 		/*
525124a0a5SRyusuke Konishi 		 * Return internal code -EINVAL to notify bmap layer of
535124a0a5SRyusuke Konishi 		 * metadata corruption.
545124a0a5SRyusuke Konishi 		 */
555124a0a5SRyusuke Konishi 		ret = -EINVAL;
565124a0a5SRyusuke Konishi 	}
575124a0a5SRyusuke Konishi 	return ret;
58a17564f5SKoji Sato }
59a17564f5SKoji Sato 
nilfs_dat_commit_entry(struct inode * dat,struct nilfs_palloc_req * req)60a17564f5SKoji Sato static void nilfs_dat_commit_entry(struct inode *dat,
61a17564f5SKoji Sato 				   struct nilfs_palloc_req *req)
62a17564f5SKoji Sato {
635fc7b141SRyusuke Konishi 	mark_buffer_dirty(req->pr_entry_bh);
64a17564f5SKoji Sato 	nilfs_mdt_mark_dirty(dat);
65a17564f5SKoji Sato 	brelse(req->pr_entry_bh);
66a17564f5SKoji Sato }
67a17564f5SKoji Sato 
nilfs_dat_abort_entry(struct inode * dat,struct nilfs_palloc_req * req)68a17564f5SKoji Sato static void nilfs_dat_abort_entry(struct inode *dat,
69a17564f5SKoji Sato 				  struct nilfs_palloc_req *req)
70a17564f5SKoji Sato {
71a17564f5SKoji Sato 	brelse(req->pr_entry_bh);
72a17564f5SKoji Sato }
73a17564f5SKoji Sato 
nilfs_dat_prepare_alloc(struct inode * dat,struct nilfs_palloc_req * req)74a17564f5SKoji Sato int nilfs_dat_prepare_alloc(struct inode *dat, struct nilfs_palloc_req *req)
75a17564f5SKoji Sato {
76a17564f5SKoji Sato 	int ret;
77a17564f5SKoji Sato 
78*95b13625SRyusuke Konishi 	ret = nilfs_palloc_prepare_alloc_entry(dat, req, true);
79a17564f5SKoji Sato 	if (ret < 0)
80a17564f5SKoji Sato 		return ret;
81a17564f5SKoji Sato 
82a17564f5SKoji Sato 	ret = nilfs_dat_prepare_entry(dat, req, 1);
83a17564f5SKoji Sato 	if (ret < 0)
84a17564f5SKoji Sato 		nilfs_palloc_abort_alloc_entry(dat, req);
85a17564f5SKoji Sato 
86a17564f5SKoji Sato 	return ret;
87a17564f5SKoji Sato }
88a17564f5SKoji Sato 
nilfs_dat_commit_alloc(struct inode * dat,struct nilfs_palloc_req * req)89a17564f5SKoji Sato void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req)
90a17564f5SKoji Sato {
91a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
92a17564f5SKoji Sato 	void *kaddr;
93a17564f5SKoji Sato 
947b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
95a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
96a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
97a17564f5SKoji Sato 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
98a17564f5SKoji Sato 	entry->de_end = cpu_to_le64(NILFS_CNO_MAX);
99a17564f5SKoji Sato 	entry->de_blocknr = cpu_to_le64(0);
1007b9c0976SCong Wang 	kunmap_atomic(kaddr);
101a17564f5SKoji Sato 
102a17564f5SKoji Sato 	nilfs_palloc_commit_alloc_entry(dat, req);
103a17564f5SKoji Sato 	nilfs_dat_commit_entry(dat, req);
104a17564f5SKoji Sato }
105a17564f5SKoji Sato 
nilfs_dat_abort_alloc(struct inode * dat,struct nilfs_palloc_req * req)106a17564f5SKoji Sato void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req)
107a17564f5SKoji Sato {
108a17564f5SKoji Sato 	nilfs_dat_abort_entry(dat, req);
109a17564f5SKoji Sato 	nilfs_palloc_abort_alloc_entry(dat, req);
110a17564f5SKoji Sato }
111a17564f5SKoji Sato 
nilfs_dat_commit_free(struct inode * dat,struct nilfs_palloc_req * req)112abc0b50bSJiro SEKIBA static void nilfs_dat_commit_free(struct inode *dat,
113abc0b50bSJiro SEKIBA 				  struct nilfs_palloc_req *req)
114a17564f5SKoji Sato {
115a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
116a17564f5SKoji Sato 	void *kaddr;
117a17564f5SKoji Sato 
1187b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
119a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
120a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
121a17564f5SKoji Sato 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
122a17564f5SKoji Sato 	entry->de_end = cpu_to_le64(NILFS_CNO_MIN);
123a17564f5SKoji Sato 	entry->de_blocknr = cpu_to_le64(0);
1247b9c0976SCong Wang 	kunmap_atomic(kaddr);
125a17564f5SKoji Sato 
126a17564f5SKoji Sato 	nilfs_dat_commit_entry(dat, req);
127f0a0ccdaSZhangPeng 
128f0a0ccdaSZhangPeng 	if (unlikely(req->pr_desc_bh == NULL || req->pr_bitmap_bh == NULL)) {
129f0a0ccdaSZhangPeng 		nilfs_error(dat->i_sb,
130f0a0ccdaSZhangPeng 			    "state inconsistency probably due to duplicate use of vblocknr = %llu",
131f0a0ccdaSZhangPeng 			    (unsigned long long)req->pr_entry_nr);
132f0a0ccdaSZhangPeng 		return;
133f0a0ccdaSZhangPeng 	}
134a17564f5SKoji Sato 	nilfs_palloc_commit_free_entry(dat, req);
135a17564f5SKoji Sato }
136a17564f5SKoji Sato 
nilfs_dat_prepare_start(struct inode * dat,struct nilfs_palloc_req * req)137a17564f5SKoji Sato int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req)
138a17564f5SKoji Sato {
1395124a0a5SRyusuke Konishi 	return nilfs_dat_prepare_entry(dat, req, 0);
140a17564f5SKoji Sato }
141a17564f5SKoji Sato 
nilfs_dat_commit_start(struct inode * dat,struct nilfs_palloc_req * req,sector_t blocknr)142a17564f5SKoji Sato void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
143a17564f5SKoji Sato 			    sector_t blocknr)
144a17564f5SKoji Sato {
145a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
146a17564f5SKoji Sato 	void *kaddr;
147a17564f5SKoji Sato 
1487b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
149a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
150a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
151a17564f5SKoji Sato 	entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat));
152a17564f5SKoji Sato 	entry->de_blocknr = cpu_to_le64(blocknr);
1537b9c0976SCong Wang 	kunmap_atomic(kaddr);
154a17564f5SKoji Sato 
155a17564f5SKoji Sato 	nilfs_dat_commit_entry(dat, req);
156a17564f5SKoji Sato }
157a17564f5SKoji Sato 
nilfs_dat_prepare_end(struct inode * dat,struct nilfs_palloc_req * req)158a17564f5SKoji Sato int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
159a17564f5SKoji Sato {
160a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
161602ce7b8SRyusuke Konishi 	__u64 start;
162a17564f5SKoji Sato 	sector_t blocknr;
163a17564f5SKoji Sato 	void *kaddr;
164a17564f5SKoji Sato 	int ret;
165a17564f5SKoji Sato 
166a17564f5SKoji Sato 	ret = nilfs_dat_prepare_entry(dat, req, 0);
1675124a0a5SRyusuke Konishi 	if (ret < 0)
168a17564f5SKoji Sato 		return ret;
169a17564f5SKoji Sato 
1707b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
171a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
172a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
173602ce7b8SRyusuke Konishi 	start = le64_to_cpu(entry->de_start);
174a17564f5SKoji Sato 	blocknr = le64_to_cpu(entry->de_blocknr);
1757b9c0976SCong Wang 	kunmap_atomic(kaddr);
176a17564f5SKoji Sato 
177a17564f5SKoji Sato 	if (blocknr == 0) {
178a17564f5SKoji Sato 		ret = nilfs_palloc_prepare_free_entry(dat, req);
179a17564f5SKoji Sato 		if (ret < 0) {
180a17564f5SKoji Sato 			nilfs_dat_abort_entry(dat, req);
181a17564f5SKoji Sato 			return ret;
182a17564f5SKoji Sato 		}
183a17564f5SKoji Sato 	}
184602ce7b8SRyusuke Konishi 	if (unlikely(start > nilfs_mdt_cno(dat))) {
185602ce7b8SRyusuke Konishi 		nilfs_err(dat->i_sb,
186602ce7b8SRyusuke Konishi 			  "vblocknr = %llu has abnormal lifetime: start cno (= %llu) > current cno (= %llu)",
187602ce7b8SRyusuke Konishi 			  (unsigned long long)req->pr_entry_nr,
188602ce7b8SRyusuke Konishi 			  (unsigned long long)start,
189602ce7b8SRyusuke Konishi 			  (unsigned long long)nilfs_mdt_cno(dat));
190602ce7b8SRyusuke Konishi 		nilfs_dat_abort_entry(dat, req);
191602ce7b8SRyusuke Konishi 		return -EINVAL;
192602ce7b8SRyusuke Konishi 	}
193a17564f5SKoji Sato 
194a17564f5SKoji Sato 	return 0;
195a17564f5SKoji Sato }
196a17564f5SKoji Sato 
nilfs_dat_commit_end(struct inode * dat,struct nilfs_palloc_req * req,int dead)197a17564f5SKoji Sato void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
198a17564f5SKoji Sato 			  int dead)
199a17564f5SKoji Sato {
200a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
201a17564f5SKoji Sato 	__u64 start, end;
202a17564f5SKoji Sato 	sector_t blocknr;
203a17564f5SKoji Sato 	void *kaddr;
204a17564f5SKoji Sato 
2057b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
206a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
207a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
208a17564f5SKoji Sato 	end = start = le64_to_cpu(entry->de_start);
209a17564f5SKoji Sato 	if (!dead) {
210a17564f5SKoji Sato 		end = nilfs_mdt_cno(dat);
2111f5abe7eSRyusuke Konishi 		WARN_ON(start > end);
212a17564f5SKoji Sato 	}
213a17564f5SKoji Sato 	entry->de_end = cpu_to_le64(end);
214a17564f5SKoji Sato 	blocknr = le64_to_cpu(entry->de_blocknr);
2157b9c0976SCong Wang 	kunmap_atomic(kaddr);
216a17564f5SKoji Sato 
217a17564f5SKoji Sato 	if (blocknr == 0)
218a17564f5SKoji Sato 		nilfs_dat_commit_free(dat, req);
219a17564f5SKoji Sato 	else
220a17564f5SKoji Sato 		nilfs_dat_commit_entry(dat, req);
221a17564f5SKoji Sato }
222a17564f5SKoji Sato 
nilfs_dat_abort_end(struct inode * dat,struct nilfs_palloc_req * req)223a17564f5SKoji Sato void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req)
224a17564f5SKoji Sato {
225a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
226a17564f5SKoji Sato 	__u64 start;
227a17564f5SKoji Sato 	sector_t blocknr;
228a17564f5SKoji Sato 	void *kaddr;
229a17564f5SKoji Sato 
2307b9c0976SCong Wang 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
231a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
232a17564f5SKoji Sato 					     req->pr_entry_bh, kaddr);
233a17564f5SKoji Sato 	start = le64_to_cpu(entry->de_start);
234a17564f5SKoji Sato 	blocknr = le64_to_cpu(entry->de_blocknr);
2357b9c0976SCong Wang 	kunmap_atomic(kaddr);
236a17564f5SKoji Sato 
237a17564f5SKoji Sato 	if (start == nilfs_mdt_cno(dat) && blocknr == 0)
238a17564f5SKoji Sato 		nilfs_palloc_abort_free_entry(dat, req);
239a17564f5SKoji Sato 	nilfs_dat_abort_entry(dat, req);
240a17564f5SKoji Sato }
241a17564f5SKoji Sato 
nilfs_dat_prepare_update(struct inode * dat,struct nilfs_palloc_req * oldreq,struct nilfs_palloc_req * newreq)242bd8169efSRyusuke Konishi int nilfs_dat_prepare_update(struct inode *dat,
243bd8169efSRyusuke Konishi 			     struct nilfs_palloc_req *oldreq,
244bd8169efSRyusuke Konishi 			     struct nilfs_palloc_req *newreq)
245bd8169efSRyusuke Konishi {
246bd8169efSRyusuke Konishi 	int ret;
247bd8169efSRyusuke Konishi 
248bd8169efSRyusuke Konishi 	ret = nilfs_dat_prepare_end(dat, oldreq);
249bd8169efSRyusuke Konishi 	if (!ret) {
250bd8169efSRyusuke Konishi 		ret = nilfs_dat_prepare_alloc(dat, newreq);
251bd8169efSRyusuke Konishi 		if (ret < 0)
252bd8169efSRyusuke Konishi 			nilfs_dat_abort_end(dat, oldreq);
253bd8169efSRyusuke Konishi 	}
254bd8169efSRyusuke Konishi 	return ret;
255bd8169efSRyusuke Konishi }
256bd8169efSRyusuke Konishi 
nilfs_dat_commit_update(struct inode * dat,struct nilfs_palloc_req * oldreq,struct nilfs_palloc_req * newreq,int dead)257bd8169efSRyusuke Konishi void nilfs_dat_commit_update(struct inode *dat,
258bd8169efSRyusuke Konishi 			     struct nilfs_palloc_req *oldreq,
259bd8169efSRyusuke Konishi 			     struct nilfs_palloc_req *newreq, int dead)
260bd8169efSRyusuke Konishi {
261bd8169efSRyusuke Konishi 	nilfs_dat_commit_end(dat, oldreq, dead);
262bd8169efSRyusuke Konishi 	nilfs_dat_commit_alloc(dat, newreq);
263bd8169efSRyusuke Konishi }
264bd8169efSRyusuke Konishi 
nilfs_dat_abort_update(struct inode * dat,struct nilfs_palloc_req * oldreq,struct nilfs_palloc_req * newreq)265bd8169efSRyusuke Konishi void nilfs_dat_abort_update(struct inode *dat,
266bd8169efSRyusuke Konishi 			    struct nilfs_palloc_req *oldreq,
267bd8169efSRyusuke Konishi 			    struct nilfs_palloc_req *newreq)
268bd8169efSRyusuke Konishi {
269bd8169efSRyusuke Konishi 	nilfs_dat_abort_end(dat, oldreq);
270bd8169efSRyusuke Konishi 	nilfs_dat_abort_alloc(dat, newreq);
271bd8169efSRyusuke Konishi }
272bd8169efSRyusuke Konishi 
273a17564f5SKoji Sato /**
274a17564f5SKoji Sato  * nilfs_dat_mark_dirty -
275a17564f5SKoji Sato  * @dat: DAT file inode
276a17564f5SKoji Sato  * @vblocknr: virtual block number
277a17564f5SKoji Sato  *
278a17564f5SKoji Sato  * Description:
279a17564f5SKoji Sato  *
280a17564f5SKoji Sato  * Return Value: On success, 0 is returned. On error, one of the following
281a17564f5SKoji Sato  * negative error codes is returned.
282a17564f5SKoji Sato  *
283a17564f5SKoji Sato  * %-EIO - I/O error.
284a17564f5SKoji Sato  *
285a17564f5SKoji Sato  * %-ENOMEM - Insufficient amount of memory available.
286a17564f5SKoji Sato  */
nilfs_dat_mark_dirty(struct inode * dat,__u64 vblocknr)287a17564f5SKoji Sato int nilfs_dat_mark_dirty(struct inode *dat, __u64 vblocknr)
288a17564f5SKoji Sato {
289a17564f5SKoji Sato 	struct nilfs_palloc_req req;
290a17564f5SKoji Sato 	int ret;
291a17564f5SKoji Sato 
292a17564f5SKoji Sato 	req.pr_entry_nr = vblocknr;
293a17564f5SKoji Sato 	ret = nilfs_dat_prepare_entry(dat, &req, 0);
294a17564f5SKoji Sato 	if (ret == 0)
295a17564f5SKoji Sato 		nilfs_dat_commit_entry(dat, &req);
296a17564f5SKoji Sato 	return ret;
297a17564f5SKoji Sato }
298a17564f5SKoji Sato 
299a17564f5SKoji Sato /**
300a17564f5SKoji Sato  * nilfs_dat_freev - free virtual block numbers
301a17564f5SKoji Sato  * @dat: DAT file inode
302a17564f5SKoji Sato  * @vblocknrs: array of virtual block numbers
303a17564f5SKoji Sato  * @nitems: number of virtual block numbers
304a17564f5SKoji Sato  *
305a17564f5SKoji Sato  * Description: nilfs_dat_freev() frees the virtual block numbers specified by
306a17564f5SKoji Sato  * @vblocknrs and @nitems.
307a17564f5SKoji Sato  *
308a17564f5SKoji Sato  * Return Value: On success, 0 is returned. On error, one of the following
3097a65004bSRyusuke Konishi  * negative error codes is returned.
310a17564f5SKoji Sato  *
311a17564f5SKoji Sato  * %-EIO - I/O error.
312a17564f5SKoji Sato  *
313a17564f5SKoji Sato  * %-ENOMEM - Insufficient amount of memory available.
314a17564f5SKoji Sato  *
315a17564f5SKoji Sato  * %-ENOENT - The virtual block number have not been allocated.
316a17564f5SKoji Sato  */
nilfs_dat_freev(struct inode * dat,__u64 * vblocknrs,size_t nitems)317a17564f5SKoji Sato int nilfs_dat_freev(struct inode *dat, __u64 *vblocknrs, size_t nitems)
318a17564f5SKoji Sato {
319a17564f5SKoji Sato 	return nilfs_palloc_freev(dat, vblocknrs, nitems);
320a17564f5SKoji Sato }
321a17564f5SKoji Sato 
322a17564f5SKoji Sato /**
323a17564f5SKoji Sato  * nilfs_dat_move - change a block number
324a17564f5SKoji Sato  * @dat: DAT file inode
325a17564f5SKoji Sato  * @vblocknr: virtual block number
326a17564f5SKoji Sato  * @blocknr: block number
327a17564f5SKoji Sato  *
328a17564f5SKoji Sato  * Description: nilfs_dat_move() changes the block number associated with
329a17564f5SKoji Sato  * @vblocknr to @blocknr.
330a17564f5SKoji Sato  *
331a17564f5SKoji Sato  * Return Value: On success, 0 is returned. On error, one of the following
332a17564f5SKoji Sato  * negative error codes is returned.
333a17564f5SKoji Sato  *
334a17564f5SKoji Sato  * %-EIO - I/O error.
335a17564f5SKoji Sato  *
336a17564f5SKoji Sato  * %-ENOMEM - Insufficient amount of memory available.
337a17564f5SKoji Sato  */
nilfs_dat_move(struct inode * dat,__u64 vblocknr,sector_t blocknr)338a17564f5SKoji Sato int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
339a17564f5SKoji Sato {
340a17564f5SKoji Sato 	struct buffer_head *entry_bh;
341a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
342a17564f5SKoji Sato 	void *kaddr;
343a17564f5SKoji Sato 	int ret;
344a17564f5SKoji Sato 
345a17564f5SKoji Sato 	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
346a17564f5SKoji Sato 	if (ret < 0)
347a17564f5SKoji Sato 		return ret;
348c1c1d709SRyusuke Konishi 
349c1c1d709SRyusuke Konishi 	/*
350c1c1d709SRyusuke Konishi 	 * The given disk block number (blocknr) is not yet written to
351c1c1d709SRyusuke Konishi 	 * the device at this point.
352c1c1d709SRyusuke Konishi 	 *
353c1c1d709SRyusuke Konishi 	 * To prevent nilfs_dat_translate() from returning the
354f6c26ec5SRyusuke Konishi 	 * uncommitted block number, this makes a copy of the entry
355c1c1d709SRyusuke Konishi 	 * buffer and redirects nilfs_dat_translate() to the copy.
356c1c1d709SRyusuke Konishi 	 */
357c1c1d709SRyusuke Konishi 	if (!buffer_nilfs_redirected(entry_bh)) {
358c1c1d709SRyusuke Konishi 		ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
359c1c1d709SRyusuke Konishi 		if (ret) {
360c1c1d709SRyusuke Konishi 			brelse(entry_bh);
361c1c1d709SRyusuke Konishi 			return ret;
362c1c1d709SRyusuke Konishi 		}
363c1c1d709SRyusuke Konishi 	}
364c1c1d709SRyusuke Konishi 
3657b9c0976SCong Wang 	kaddr = kmap_atomic(entry_bh->b_page);
366a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
3671f5abe7eSRyusuke Konishi 	if (unlikely(entry->de_blocknr == cpu_to_le64(0))) {
368a1d0747aSJoe Perches 		nilfs_crit(dat->i_sb,
369feee880fSRyusuke Konishi 			   "%s: invalid vblocknr = %llu, [%llu, %llu)",
370feee880fSRyusuke Konishi 			   __func__, (unsigned long long)vblocknr,
371a17564f5SKoji Sato 			   (unsigned long long)le64_to_cpu(entry->de_start),
372a17564f5SKoji Sato 			   (unsigned long long)le64_to_cpu(entry->de_end));
3737b9c0976SCong Wang 		kunmap_atomic(kaddr);
3741f5abe7eSRyusuke Konishi 		brelse(entry_bh);
3751f5abe7eSRyusuke Konishi 		return -EINVAL;
376a17564f5SKoji Sato 	}
3771f5abe7eSRyusuke Konishi 	WARN_ON(blocknr == 0);
378a17564f5SKoji Sato 	entry->de_blocknr = cpu_to_le64(blocknr);
3797b9c0976SCong Wang 	kunmap_atomic(kaddr);
380a17564f5SKoji Sato 
3815fc7b141SRyusuke Konishi 	mark_buffer_dirty(entry_bh);
382a17564f5SKoji Sato 	nilfs_mdt_mark_dirty(dat);
383a17564f5SKoji Sato 
384a17564f5SKoji Sato 	brelse(entry_bh);
385a17564f5SKoji Sato 
386a17564f5SKoji Sato 	return 0;
387a17564f5SKoji Sato }
388a17564f5SKoji Sato 
389a17564f5SKoji Sato /**
390a17564f5SKoji Sato  * nilfs_dat_translate - translate a virtual block number to a block number
391a17564f5SKoji Sato  * @dat: DAT file inode
392a17564f5SKoji Sato  * @vblocknr: virtual block number
393a17564f5SKoji Sato  * @blocknrp: pointer to a block number
394a17564f5SKoji Sato  *
395a17564f5SKoji Sato  * Description: nilfs_dat_translate() maps the virtual block number @vblocknr
396a17564f5SKoji Sato  * to the corresponding block number.
397a17564f5SKoji Sato  *
398a17564f5SKoji Sato  * Return Value: On success, 0 is returned and the block number associated
399a17564f5SKoji Sato  * with @vblocknr is stored in the place pointed by @blocknrp. On error, one
400a17564f5SKoji Sato  * of the following negative error codes is returned.
401a17564f5SKoji Sato  *
402a17564f5SKoji Sato  * %-EIO - I/O error.
403a17564f5SKoji Sato  *
404a17564f5SKoji Sato  * %-ENOMEM - Insufficient amount of memory available.
405a17564f5SKoji Sato  *
406a17564f5SKoji Sato  * %-ENOENT - A block number associated with @vblocknr does not exist.
407a17564f5SKoji Sato  */
nilfs_dat_translate(struct inode * dat,__u64 vblocknr,sector_t * blocknrp)408a17564f5SKoji Sato int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
409a17564f5SKoji Sato {
410c1c1d709SRyusuke Konishi 	struct buffer_head *entry_bh, *bh;
411a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
412a17564f5SKoji Sato 	sector_t blocknr;
413a17564f5SKoji Sato 	void *kaddr;
414a17564f5SKoji Sato 	int ret;
415a17564f5SKoji Sato 
416a17564f5SKoji Sato 	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
417a17564f5SKoji Sato 	if (ret < 0)
418a17564f5SKoji Sato 		return ret;
419a17564f5SKoji Sato 
420c1c1d709SRyusuke Konishi 	if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) {
421c1c1d709SRyusuke Konishi 		bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh);
422c1c1d709SRyusuke Konishi 		if (bh) {
423c1c1d709SRyusuke Konishi 			WARN_ON(!buffer_uptodate(bh));
424c1c1d709SRyusuke Konishi 			brelse(entry_bh);
425c1c1d709SRyusuke Konishi 			entry_bh = bh;
426c1c1d709SRyusuke Konishi 		}
427c1c1d709SRyusuke Konishi 	}
428c1c1d709SRyusuke Konishi 
4297b9c0976SCong Wang 	kaddr = kmap_atomic(entry_bh->b_page);
430a17564f5SKoji Sato 	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
431a17564f5SKoji Sato 	blocknr = le64_to_cpu(entry->de_blocknr);
432a17564f5SKoji Sato 	if (blocknr == 0) {
433a17564f5SKoji Sato 		ret = -ENOENT;
434a17564f5SKoji Sato 		goto out;
435a17564f5SKoji Sato 	}
436a17564f5SKoji Sato 	*blocknrp = blocknr;
437a17564f5SKoji Sato 
438a17564f5SKoji Sato  out:
4397b9c0976SCong Wang 	kunmap_atomic(kaddr);
440a17564f5SKoji Sato 	brelse(entry_bh);
441a17564f5SKoji Sato 	return ret;
442a17564f5SKoji Sato }
443a17564f5SKoji Sato 
nilfs_dat_get_vinfo(struct inode * dat,void * buf,unsigned int visz,size_t nvi)4440c6c44cbSRyusuke Konishi ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned int visz,
445a17564f5SKoji Sato 			    size_t nvi)
446a17564f5SKoji Sato {
447a17564f5SKoji Sato 	struct buffer_head *entry_bh;
448a17564f5SKoji Sato 	struct nilfs_dat_entry *entry;
449003ff182SRyusuke Konishi 	struct nilfs_vinfo *vinfo = buf;
450a17564f5SKoji Sato 	__u64 first, last;
451a17564f5SKoji Sato 	void *kaddr;
452a17564f5SKoji Sato 	unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block;
453a17564f5SKoji Sato 	int i, j, n, ret;
454a17564f5SKoji Sato 
455a17564f5SKoji Sato 	for (i = 0; i < nvi; i += n) {
456003ff182SRyusuke Konishi 		ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr,
457a17564f5SKoji Sato 						   0, &entry_bh);
458a17564f5SKoji Sato 		if (ret < 0)
459a17564f5SKoji Sato 			return ret;
4607b9c0976SCong Wang 		kaddr = kmap_atomic(entry_bh->b_page);
461a17564f5SKoji Sato 		/* last virtual block number in this block */
462003ff182SRyusuke Konishi 		first = vinfo->vi_vblocknr;
463a17564f5SKoji Sato 		do_div(first, entries_per_block);
464a17564f5SKoji Sato 		first *= entries_per_block;
465a17564f5SKoji Sato 		last = first + entries_per_block - 1;
466a17564f5SKoji Sato 		for (j = i, n = 0;
467003ff182SRyusuke Konishi 		     j < nvi && vinfo->vi_vblocknr >= first &&
468003ff182SRyusuke Konishi 			     vinfo->vi_vblocknr <= last;
469003ff182SRyusuke Konishi 		     j++, n++, vinfo = (void *)vinfo + visz) {
470a17564f5SKoji Sato 			entry = nilfs_palloc_block_get_entry(
471003ff182SRyusuke Konishi 				dat, vinfo->vi_vblocknr, entry_bh, kaddr);
472003ff182SRyusuke Konishi 			vinfo->vi_start = le64_to_cpu(entry->de_start);
473003ff182SRyusuke Konishi 			vinfo->vi_end = le64_to_cpu(entry->de_end);
474003ff182SRyusuke Konishi 			vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr);
475a17564f5SKoji Sato 		}
4767b9c0976SCong Wang 		kunmap_atomic(kaddr);
477a17564f5SKoji Sato 		brelse(entry_bh);
478a17564f5SKoji Sato 	}
479a17564f5SKoji Sato 
480a17564f5SKoji Sato 	return nvi;
481a17564f5SKoji Sato }
48279739565SRyusuke Konishi 
48379739565SRyusuke Konishi /**
484f1e89c86SRyusuke Konishi  * nilfs_dat_read - read or get dat inode
485f1e89c86SRyusuke Konishi  * @sb: super block instance
48679739565SRyusuke Konishi  * @entry_size: size of a dat entry
487f1e89c86SRyusuke Konishi  * @raw_inode: on-disk dat inode
488f1e89c86SRyusuke Konishi  * @inodep: buffer to store the inode
48979739565SRyusuke Konishi  */
nilfs_dat_read(struct super_block * sb,size_t entry_size,struct nilfs_inode * raw_inode,struct inode ** inodep)490f1e89c86SRyusuke Konishi int nilfs_dat_read(struct super_block *sb, size_t entry_size,
491f1e89c86SRyusuke Konishi 		   struct nilfs_inode *raw_inode, struct inode **inodep)
49279739565SRyusuke Konishi {
49379739565SRyusuke Konishi 	static struct lock_class_key dat_lock_key;
49479739565SRyusuke Konishi 	struct inode *dat;
4958908b2f7SRyusuke Konishi 	struct nilfs_dat_info *di;
49679739565SRyusuke Konishi 	int err;
49779739565SRyusuke Konishi 
4980ec060d1SRyusuke Konishi 	if (entry_size > sb->s_blocksize) {
499a1d0747aSJoe Perches 		nilfs_err(sb, "too large DAT entry size: %zu bytes",
5000ec060d1SRyusuke Konishi 			  entry_size);
5010ec060d1SRyusuke Konishi 		return -EINVAL;
5020ec060d1SRyusuke Konishi 	} else if (entry_size < NILFS_MIN_DAT_ENTRY_SIZE) {
503a1d0747aSJoe Perches 		nilfs_err(sb, "too small DAT entry size: %zu bytes",
5040ec060d1SRyusuke Konishi 			  entry_size);
5050ec060d1SRyusuke Konishi 		return -EINVAL;
5060ec060d1SRyusuke Konishi 	}
5070ec060d1SRyusuke Konishi 
508f1e89c86SRyusuke Konishi 	dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO);
509f1e89c86SRyusuke Konishi 	if (unlikely(!dat))
510f1e89c86SRyusuke Konishi 		return -ENOMEM;
511f1e89c86SRyusuke Konishi 	if (!(dat->i_state & I_NEW))
512f1e89c86SRyusuke Konishi 		goto out;
513f1e89c86SRyusuke Konishi 
514f1e89c86SRyusuke Konishi 	err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di));
515f1e89c86SRyusuke Konishi 	if (err)
516f1e89c86SRyusuke Konishi 		goto failed;
517f1e89c86SRyusuke Konishi 
51879739565SRyusuke Konishi 	err = nilfs_palloc_init_blockgroup(dat, entry_size);
519f1e89c86SRyusuke Konishi 	if (err)
520f1e89c86SRyusuke Konishi 		goto failed;
5218908b2f7SRyusuke Konishi 
5228908b2f7SRyusuke Konishi 	di = NILFS_DAT_I(dat);
5238908b2f7SRyusuke Konishi 	lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);
5248908b2f7SRyusuke Konishi 	nilfs_palloc_setup_cache(dat, &di->palloc_cache);
5256e211930SRyusuke Konishi 	err = nilfs_mdt_setup_shadow_map(dat, &di->shadow);
5266e211930SRyusuke Konishi 	if (err)
5276e211930SRyusuke Konishi 		goto failed;
528f1e89c86SRyusuke Konishi 
529f1e89c86SRyusuke Konishi 	err = nilfs_read_inode_common(dat, raw_inode);
530f1e89c86SRyusuke Konishi 	if (err)
531f1e89c86SRyusuke Konishi 		goto failed;
532f1e89c86SRyusuke Konishi 
533f1e89c86SRyusuke Konishi 	unlock_new_inode(dat);
534f1e89c86SRyusuke Konishi  out:
535f1e89c86SRyusuke Konishi 	*inodep = dat;
536f1e89c86SRyusuke Konishi 	return 0;
537f1e89c86SRyusuke Konishi  failed:
538f1e89c86SRyusuke Konishi 	iget_failed(dat);
539f1e89c86SRyusuke Konishi 	return err;
54079739565SRyusuke Konishi }
541