xref: /openbmc/linux/fs/nilfs2/alloc.c (revision 95b13625)
1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+
25442680fSRyusuke Konishi /*
394ee1d91SRyusuke Konishi  * NILFS dat/inode allocator
45442680fSRyusuke Konishi  *
55442680fSRyusuke Konishi  * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.
65442680fSRyusuke Konishi  *
74b420ab4SRyusuke Konishi  * Originally written by Koji Sato.
84b420ab4SRyusuke Konishi  * Two allocators were unified by Ryusuke Konishi and Amagai Yoshiji.
95442680fSRyusuke Konishi  */
105442680fSRyusuke Konishi 
115442680fSRyusuke Konishi #include <linux/types.h>
125442680fSRyusuke Konishi #include <linux/buffer_head.h>
135442680fSRyusuke Konishi #include <linux/fs.h>
145442680fSRyusuke Konishi #include <linux/bitops.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
165442680fSRyusuke Konishi #include "mdt.h"
175442680fSRyusuke Konishi #include "alloc.h"
185442680fSRyusuke Konishi 
195442680fSRyusuke Konishi 
20db55d922SRyusuke Konishi /**
21db55d922SRyusuke Konishi  * nilfs_palloc_groups_per_desc_block - get the number of groups that a group
22db55d922SRyusuke Konishi  *					descriptor block can maintain
23db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
24db55d922SRyusuke Konishi  */
255442680fSRyusuke Konishi static inline unsigned long
nilfs_palloc_groups_per_desc_block(const struct inode * inode)265442680fSRyusuke Konishi nilfs_palloc_groups_per_desc_block(const struct inode *inode)
275442680fSRyusuke Konishi {
28f3048d17SGeliang Tang 	return i_blocksize(inode) /
295442680fSRyusuke Konishi 		sizeof(struct nilfs_palloc_group_desc);
305442680fSRyusuke Konishi }
315442680fSRyusuke Konishi 
32db55d922SRyusuke Konishi /**
33db55d922SRyusuke Konishi  * nilfs_palloc_groups_count - get maximum number of groups
34db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
35db55d922SRyusuke Konishi  */
365442680fSRyusuke Konishi static inline unsigned long
nilfs_palloc_groups_count(const struct inode * inode)375442680fSRyusuke Konishi nilfs_palloc_groups_count(const struct inode *inode)
385442680fSRyusuke Konishi {
395442680fSRyusuke Konishi 	return 1UL << (BITS_PER_LONG - (inode->i_blkbits + 3 /* log2(8) */));
405442680fSRyusuke Konishi }
415442680fSRyusuke Konishi 
42db55d922SRyusuke Konishi /**
43db55d922SRyusuke Konishi  * nilfs_palloc_init_blockgroup - initialize private variables for allocator
44db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
45db55d922SRyusuke Konishi  * @entry_size: size of the persistent object
46db55d922SRyusuke Konishi  */
nilfs_palloc_init_blockgroup(struct inode * inode,unsigned int entry_size)470c6c44cbSRyusuke Konishi int nilfs_palloc_init_blockgroup(struct inode *inode, unsigned int entry_size)
485442680fSRyusuke Konishi {
495442680fSRyusuke Konishi 	struct nilfs_mdt_info *mi = NILFS_MDT(inode);
505442680fSRyusuke Konishi 
515442680fSRyusuke Konishi 	mi->mi_bgl = kmalloc(sizeof(*mi->mi_bgl), GFP_NOFS);
525442680fSRyusuke Konishi 	if (!mi->mi_bgl)
535442680fSRyusuke Konishi 		return -ENOMEM;
545442680fSRyusuke Konishi 
555442680fSRyusuke Konishi 	bgl_lock_init(mi->mi_bgl);
565442680fSRyusuke Konishi 
575442680fSRyusuke Konishi 	nilfs_mdt_set_entry_size(inode, entry_size, 0);
585442680fSRyusuke Konishi 
595442680fSRyusuke Konishi 	mi->mi_blocks_per_group =
605442680fSRyusuke Konishi 		DIV_ROUND_UP(nilfs_palloc_entries_per_group(inode),
615442680fSRyusuke Konishi 			     mi->mi_entries_per_block) + 1;
62076a378bSRyusuke Konishi 		/*
63076a378bSRyusuke Konishi 		 * Number of blocks in a group including entry blocks
64076a378bSRyusuke Konishi 		 * and a bitmap block
65076a378bSRyusuke Konishi 		 */
665442680fSRyusuke Konishi 	mi->mi_blocks_per_desc_block =
675442680fSRyusuke Konishi 		nilfs_palloc_groups_per_desc_block(inode) *
685442680fSRyusuke Konishi 		mi->mi_blocks_per_group + 1;
69076a378bSRyusuke Konishi 		/*
70076a378bSRyusuke Konishi 		 * Number of blocks per descriptor including the
71076a378bSRyusuke Konishi 		 * descriptor block
72076a378bSRyusuke Konishi 		 */
735442680fSRyusuke Konishi 	return 0;
745442680fSRyusuke Konishi }
755442680fSRyusuke Konishi 
76db55d922SRyusuke Konishi /**
77db55d922SRyusuke Konishi  * nilfs_palloc_group - get group number and offset from an entry number
78db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
79db55d922SRyusuke Konishi  * @nr: serial number of the entry (e.g. inode number)
80db55d922SRyusuke Konishi  * @offset: pointer to store offset number in the group
81db55d922SRyusuke Konishi  */
nilfs_palloc_group(const struct inode * inode,__u64 nr,unsigned long * offset)825442680fSRyusuke Konishi static unsigned long nilfs_palloc_group(const struct inode *inode, __u64 nr,
835442680fSRyusuke Konishi 					unsigned long *offset)
845442680fSRyusuke Konishi {
855442680fSRyusuke Konishi 	__u64 group = nr;
865442680fSRyusuke Konishi 
875442680fSRyusuke Konishi 	*offset = do_div(group, nilfs_palloc_entries_per_group(inode));
885442680fSRyusuke Konishi 	return group;
895442680fSRyusuke Konishi }
905442680fSRyusuke Konishi 
91db55d922SRyusuke Konishi /**
92db55d922SRyusuke Konishi  * nilfs_palloc_desc_blkoff - get block offset of a group descriptor block
93db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
94db55d922SRyusuke Konishi  * @group: group number
95db55d922SRyusuke Konishi  *
96db55d922SRyusuke Konishi  * nilfs_palloc_desc_blkoff() returns block offset of the descriptor
97db55d922SRyusuke Konishi  * block which contains a descriptor of the specified group.
98db55d922SRyusuke Konishi  */
995442680fSRyusuke Konishi static unsigned long
nilfs_palloc_desc_blkoff(const struct inode * inode,unsigned long group)1005442680fSRyusuke Konishi nilfs_palloc_desc_blkoff(const struct inode *inode, unsigned long group)
1015442680fSRyusuke Konishi {
1025442680fSRyusuke Konishi 	unsigned long desc_block =
1035442680fSRyusuke Konishi 		group / nilfs_palloc_groups_per_desc_block(inode);
1045442680fSRyusuke Konishi 	return desc_block * NILFS_MDT(inode)->mi_blocks_per_desc_block;
1055442680fSRyusuke Konishi }
1065442680fSRyusuke Konishi 
107db55d922SRyusuke Konishi /**
108db55d922SRyusuke Konishi  * nilfs_palloc_bitmap_blkoff - get block offset of a bitmap block
109db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
110db55d922SRyusuke Konishi  * @group: group number
111db55d922SRyusuke Konishi  *
112db55d922SRyusuke Konishi  * nilfs_palloc_bitmap_blkoff() returns block offset of the bitmap
113db55d922SRyusuke Konishi  * block used to allocate/deallocate entries in the specified group.
114db55d922SRyusuke Konishi  */
1155442680fSRyusuke Konishi static unsigned long
nilfs_palloc_bitmap_blkoff(const struct inode * inode,unsigned long group)1165442680fSRyusuke Konishi nilfs_palloc_bitmap_blkoff(const struct inode *inode, unsigned long group)
1175442680fSRyusuke Konishi {
1185442680fSRyusuke Konishi 	unsigned long desc_offset =
1195442680fSRyusuke Konishi 		group % nilfs_palloc_groups_per_desc_block(inode);
1205442680fSRyusuke Konishi 	return nilfs_palloc_desc_blkoff(inode, group) + 1 +
1215442680fSRyusuke Konishi 		desc_offset * NILFS_MDT(inode)->mi_blocks_per_group;
1225442680fSRyusuke Konishi }
1235442680fSRyusuke Konishi 
124db55d922SRyusuke Konishi /**
125db55d922SRyusuke Konishi  * nilfs_palloc_group_desc_nfrees - get the number of free entries in a group
126db55d922SRyusuke Konishi  * @desc: pointer to descriptor structure for the group
1274e9e63a6SRyusuke Konishi  * @lock: spin lock protecting @desc
128db55d922SRyusuke Konishi  */
1295442680fSRyusuke Konishi static unsigned long
nilfs_palloc_group_desc_nfrees(const struct nilfs_palloc_group_desc * desc,spinlock_t * lock)1304e9e63a6SRyusuke Konishi nilfs_palloc_group_desc_nfrees(const struct nilfs_palloc_group_desc *desc,
1314e9e63a6SRyusuke Konishi 			       spinlock_t *lock)
1325442680fSRyusuke Konishi {
1335442680fSRyusuke Konishi 	unsigned long nfree;
1345442680fSRyusuke Konishi 
1354e9e63a6SRyusuke Konishi 	spin_lock(lock);
1365442680fSRyusuke Konishi 	nfree = le32_to_cpu(desc->pg_nfrees);
1374e9e63a6SRyusuke Konishi 	spin_unlock(lock);
1385442680fSRyusuke Konishi 	return nfree;
1395442680fSRyusuke Konishi }
1405442680fSRyusuke Konishi 
141db55d922SRyusuke Konishi /**
142db55d922SRyusuke Konishi  * nilfs_palloc_group_desc_add_entries - adjust count of free entries
143db55d922SRyusuke Konishi  * @desc: pointer to descriptor structure for the group
1444e9e63a6SRyusuke Konishi  * @lock: spin lock protecting @desc
145db55d922SRyusuke Konishi  * @n: delta to be added
146db55d922SRyusuke Konishi  */
147d0c14a9eSRyusuke Konishi static u32
nilfs_palloc_group_desc_add_entries(struct nilfs_palloc_group_desc * desc,spinlock_t * lock,u32 n)1484e9e63a6SRyusuke Konishi nilfs_palloc_group_desc_add_entries(struct nilfs_palloc_group_desc *desc,
1494e9e63a6SRyusuke Konishi 				    spinlock_t *lock, u32 n)
1505442680fSRyusuke Konishi {
151d0c14a9eSRyusuke Konishi 	u32 nfree;
152d0c14a9eSRyusuke Konishi 
1534e9e63a6SRyusuke Konishi 	spin_lock(lock);
1545442680fSRyusuke Konishi 	le32_add_cpu(&desc->pg_nfrees, n);
155d0c14a9eSRyusuke Konishi 	nfree = le32_to_cpu(desc->pg_nfrees);
1564e9e63a6SRyusuke Konishi 	spin_unlock(lock);
157d0c14a9eSRyusuke Konishi 	return nfree;
1585442680fSRyusuke Konishi }
1595442680fSRyusuke Konishi 
160db55d922SRyusuke Konishi /**
161db55d922SRyusuke Konishi  * nilfs_palloc_entry_blkoff - get block offset of an entry block
162db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
163db55d922SRyusuke Konishi  * @nr: serial number of the entry (e.g. inode number)
164db55d922SRyusuke Konishi  */
1655442680fSRyusuke Konishi static unsigned long
nilfs_palloc_entry_blkoff(const struct inode * inode,__u64 nr)1665442680fSRyusuke Konishi nilfs_palloc_entry_blkoff(const struct inode *inode, __u64 nr)
1675442680fSRyusuke Konishi {
1685442680fSRyusuke Konishi 	unsigned long group, group_offset;
1695442680fSRyusuke Konishi 
1705442680fSRyusuke Konishi 	group = nilfs_palloc_group(inode, nr, &group_offset);
1715442680fSRyusuke Konishi 
1725442680fSRyusuke Konishi 	return nilfs_palloc_bitmap_blkoff(inode, group) + 1 +
1735442680fSRyusuke Konishi 		group_offset / NILFS_MDT(inode)->mi_entries_per_block;
1745442680fSRyusuke Konishi }
1755442680fSRyusuke Konishi 
176db55d922SRyusuke Konishi /**
177db55d922SRyusuke Konishi  * nilfs_palloc_desc_block_init - initialize buffer of a group descriptor block
178db55d922SRyusuke Konishi  * @inode: inode of metadata file
179db55d922SRyusuke Konishi  * @bh: buffer head of the buffer to be initialized
180db55d922SRyusuke Konishi  * @kaddr: kernel address mapped for the page including the buffer
181db55d922SRyusuke Konishi  */
nilfs_palloc_desc_block_init(struct inode * inode,struct buffer_head * bh,void * kaddr)1825442680fSRyusuke Konishi static void nilfs_palloc_desc_block_init(struct inode *inode,
1835442680fSRyusuke Konishi 					 struct buffer_head *bh, void *kaddr)
1845442680fSRyusuke Konishi {
1855442680fSRyusuke Konishi 	struct nilfs_palloc_group_desc *desc = kaddr + bh_offset(bh);
1865442680fSRyusuke Konishi 	unsigned long n = nilfs_palloc_groups_per_desc_block(inode);
1875442680fSRyusuke Konishi 	__le32 nfrees;
1885442680fSRyusuke Konishi 
1895442680fSRyusuke Konishi 	nfrees = cpu_to_le32(nilfs_palloc_entries_per_group(inode));
1905442680fSRyusuke Konishi 	while (n-- > 0) {
1915442680fSRyusuke Konishi 		desc->pg_nfrees = nfrees;
1925442680fSRyusuke Konishi 		desc++;
1935442680fSRyusuke Konishi 	}
1945442680fSRyusuke Konishi }
1955442680fSRyusuke Konishi 
nilfs_palloc_get_block(struct inode * inode,unsigned long blkoff,int create,void (* init_block)(struct inode *,struct buffer_head *,void *),struct buffer_head ** bhp,struct nilfs_bh_assoc * prev,spinlock_t * lock)19670622a20SRyusuke Konishi static int nilfs_palloc_get_block(struct inode *inode, unsigned long blkoff,
19770622a20SRyusuke Konishi 				  int create,
19870622a20SRyusuke Konishi 				  void (*init_block)(struct inode *,
19970622a20SRyusuke Konishi 						     struct buffer_head *,
20070622a20SRyusuke Konishi 						     void *),
20170622a20SRyusuke Konishi 				  struct buffer_head **bhp,
20270622a20SRyusuke Konishi 				  struct nilfs_bh_assoc *prev,
20370622a20SRyusuke Konishi 				  spinlock_t *lock)
20470622a20SRyusuke Konishi {
20570622a20SRyusuke Konishi 	int ret;
20670622a20SRyusuke Konishi 
20770622a20SRyusuke Konishi 	spin_lock(lock);
208cdaac8e7SRyusuke Konishi 	if (prev->bh && blkoff == prev->blkoff &&
209cdaac8e7SRyusuke Konishi 	    likely(buffer_uptodate(prev->bh))) {
21070622a20SRyusuke Konishi 		get_bh(prev->bh);
21170622a20SRyusuke Konishi 		*bhp = prev->bh;
21270622a20SRyusuke Konishi 		spin_unlock(lock);
21370622a20SRyusuke Konishi 		return 0;
21470622a20SRyusuke Konishi 	}
21570622a20SRyusuke Konishi 	spin_unlock(lock);
21670622a20SRyusuke Konishi 
21770622a20SRyusuke Konishi 	ret = nilfs_mdt_get_block(inode, blkoff, create, init_block, bhp);
21870622a20SRyusuke Konishi 	if (!ret) {
21970622a20SRyusuke Konishi 		spin_lock(lock);
22070622a20SRyusuke Konishi 		/*
22170622a20SRyusuke Konishi 		 * The following code must be safe for change of the
22270622a20SRyusuke Konishi 		 * cache contents during the get block call.
22370622a20SRyusuke Konishi 		 */
22470622a20SRyusuke Konishi 		brelse(prev->bh);
22570622a20SRyusuke Konishi 		get_bh(*bhp);
22670622a20SRyusuke Konishi 		prev->bh = *bhp;
22770622a20SRyusuke Konishi 		prev->blkoff = blkoff;
22870622a20SRyusuke Konishi 		spin_unlock(lock);
22970622a20SRyusuke Konishi 	}
23070622a20SRyusuke Konishi 	return ret;
23170622a20SRyusuke Konishi }
23270622a20SRyusuke Konishi 
233db55d922SRyusuke Konishi /**
234da019954SRyusuke Konishi  * nilfs_palloc_delete_block - delete a block on the persistent allocator file
235da019954SRyusuke Konishi  * @inode: inode of metadata file using this allocator
236da019954SRyusuke Konishi  * @blkoff: block offset
237da019954SRyusuke Konishi  * @prev: nilfs_bh_assoc struct of the last used buffer
238da019954SRyusuke Konishi  * @lock: spin lock protecting @prev
239da019954SRyusuke Konishi  */
nilfs_palloc_delete_block(struct inode * inode,unsigned long blkoff,struct nilfs_bh_assoc * prev,spinlock_t * lock)240da019954SRyusuke Konishi static int nilfs_palloc_delete_block(struct inode *inode, unsigned long blkoff,
241da019954SRyusuke Konishi 				     struct nilfs_bh_assoc *prev,
242da019954SRyusuke Konishi 				     spinlock_t *lock)
243da019954SRyusuke Konishi {
244da019954SRyusuke Konishi 	spin_lock(lock);
245da019954SRyusuke Konishi 	if (prev->bh && blkoff == prev->blkoff) {
246da019954SRyusuke Konishi 		brelse(prev->bh);
247da019954SRyusuke Konishi 		prev->bh = NULL;
248da019954SRyusuke Konishi 	}
249da019954SRyusuke Konishi 	spin_unlock(lock);
250da019954SRyusuke Konishi 	return nilfs_mdt_delete_block(inode, blkoff);
251da019954SRyusuke Konishi }
252da019954SRyusuke Konishi 
253da019954SRyusuke Konishi /**
254db55d922SRyusuke Konishi  * nilfs_palloc_get_desc_block - get buffer head of a group descriptor block
255db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
256db55d922SRyusuke Konishi  * @group: group number
257db55d922SRyusuke Konishi  * @create: create flag
258db55d922SRyusuke Konishi  * @bhp: pointer to store the resultant buffer head
259db55d922SRyusuke Konishi  */
nilfs_palloc_get_desc_block(struct inode * inode,unsigned long group,int create,struct buffer_head ** bhp)2605442680fSRyusuke Konishi static int nilfs_palloc_get_desc_block(struct inode *inode,
2615442680fSRyusuke Konishi 				       unsigned long group,
2625442680fSRyusuke Konishi 				       int create, struct buffer_head **bhp)
2635442680fSRyusuke Konishi {
26470622a20SRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
26570622a20SRyusuke Konishi 
26670622a20SRyusuke Konishi 	return nilfs_palloc_get_block(inode,
2675442680fSRyusuke Konishi 				      nilfs_palloc_desc_blkoff(inode, group),
26870622a20SRyusuke Konishi 				      create, nilfs_palloc_desc_block_init,
26970622a20SRyusuke Konishi 				      bhp, &cache->prev_desc, &cache->lock);
2705442680fSRyusuke Konishi }
2715442680fSRyusuke Konishi 
272db55d922SRyusuke Konishi /**
273db55d922SRyusuke Konishi  * nilfs_palloc_get_bitmap_block - get buffer head of a bitmap block
274db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
275db55d922SRyusuke Konishi  * @group: group number
276db55d922SRyusuke Konishi  * @create: create flag
277db55d922SRyusuke Konishi  * @bhp: pointer to store the resultant buffer head
278db55d922SRyusuke Konishi  */
nilfs_palloc_get_bitmap_block(struct inode * inode,unsigned long group,int create,struct buffer_head ** bhp)2795442680fSRyusuke Konishi static int nilfs_palloc_get_bitmap_block(struct inode *inode,
2805442680fSRyusuke Konishi 					 unsigned long group,
2815442680fSRyusuke Konishi 					 int create, struct buffer_head **bhp)
2825442680fSRyusuke Konishi {
28370622a20SRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
28470622a20SRyusuke Konishi 
28570622a20SRyusuke Konishi 	return nilfs_palloc_get_block(inode,
2865442680fSRyusuke Konishi 				      nilfs_palloc_bitmap_blkoff(inode, group),
28770622a20SRyusuke Konishi 				      create, NULL, bhp,
28870622a20SRyusuke Konishi 				      &cache->prev_bitmap, &cache->lock);
2895442680fSRyusuke Konishi }
2905442680fSRyusuke Konishi 
291db55d922SRyusuke Konishi /**
292da019954SRyusuke Konishi  * nilfs_palloc_delete_bitmap_block - delete a bitmap block
293da019954SRyusuke Konishi  * @inode: inode of metadata file using this allocator
294da019954SRyusuke Konishi  * @group: group number
295da019954SRyusuke Konishi  */
nilfs_palloc_delete_bitmap_block(struct inode * inode,unsigned long group)296da019954SRyusuke Konishi static int nilfs_palloc_delete_bitmap_block(struct inode *inode,
297da019954SRyusuke Konishi 					    unsigned long group)
298da019954SRyusuke Konishi {
299da019954SRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
300da019954SRyusuke Konishi 
301da019954SRyusuke Konishi 	return nilfs_palloc_delete_block(inode,
302da019954SRyusuke Konishi 					 nilfs_palloc_bitmap_blkoff(inode,
303da019954SRyusuke Konishi 								    group),
304da019954SRyusuke Konishi 					 &cache->prev_bitmap, &cache->lock);
305da019954SRyusuke Konishi }
306da019954SRyusuke Konishi 
307da019954SRyusuke Konishi /**
308db55d922SRyusuke Konishi  * nilfs_palloc_get_entry_block - get buffer head of an entry block
309db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
310db55d922SRyusuke Konishi  * @nr: serial number of the entry (e.g. inode number)
311db55d922SRyusuke Konishi  * @create: create flag
312db55d922SRyusuke Konishi  * @bhp: pointer to store the resultant buffer head
313db55d922SRyusuke Konishi  */
nilfs_palloc_get_entry_block(struct inode * inode,__u64 nr,int create,struct buffer_head ** bhp)3145442680fSRyusuke Konishi int nilfs_palloc_get_entry_block(struct inode *inode, __u64 nr,
3155442680fSRyusuke Konishi 				 int create, struct buffer_head **bhp)
3165442680fSRyusuke Konishi {
31770622a20SRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
31870622a20SRyusuke Konishi 
31970622a20SRyusuke Konishi 	return nilfs_palloc_get_block(inode,
32070622a20SRyusuke Konishi 				      nilfs_palloc_entry_blkoff(inode, nr),
32170622a20SRyusuke Konishi 				      create, NULL, bhp,
32270622a20SRyusuke Konishi 				      &cache->prev_entry, &cache->lock);
3235442680fSRyusuke Konishi }
3245442680fSRyusuke Konishi 
325db55d922SRyusuke Konishi /**
326da019954SRyusuke Konishi  * nilfs_palloc_delete_entry_block - delete an entry block
327da019954SRyusuke Konishi  * @inode: inode of metadata file using this allocator
328da019954SRyusuke Konishi  * @nr: serial number of the entry
329da019954SRyusuke Konishi  */
nilfs_palloc_delete_entry_block(struct inode * inode,__u64 nr)330da019954SRyusuke Konishi static int nilfs_palloc_delete_entry_block(struct inode *inode, __u64 nr)
331da019954SRyusuke Konishi {
332da019954SRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
333da019954SRyusuke Konishi 
334da019954SRyusuke Konishi 	return nilfs_palloc_delete_block(inode,
335da019954SRyusuke Konishi 					 nilfs_palloc_entry_blkoff(inode, nr),
336da019954SRyusuke Konishi 					 &cache->prev_entry, &cache->lock);
337da019954SRyusuke Konishi }
338da019954SRyusuke Konishi 
339da019954SRyusuke Konishi /**
340db55d922SRyusuke Konishi  * nilfs_palloc_block_get_group_desc - get kernel address of a group descriptor
341db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
342db55d922SRyusuke Konishi  * @group: group number
343db55d922SRyusuke Konishi  * @bh: buffer head of the buffer storing the group descriptor block
344db55d922SRyusuke Konishi  * @kaddr: kernel address mapped for the page including the buffer
345db55d922SRyusuke Konishi  */
3465442680fSRyusuke Konishi static struct nilfs_palloc_group_desc *
nilfs_palloc_block_get_group_desc(const struct inode * inode,unsigned long group,const struct buffer_head * bh,void * kaddr)3475442680fSRyusuke Konishi nilfs_palloc_block_get_group_desc(const struct inode *inode,
3485442680fSRyusuke Konishi 				  unsigned long group,
3495442680fSRyusuke Konishi 				  const struct buffer_head *bh, void *kaddr)
3505442680fSRyusuke Konishi {
3515442680fSRyusuke Konishi 	return (struct nilfs_palloc_group_desc *)(kaddr + bh_offset(bh)) +
3525442680fSRyusuke Konishi 		group % nilfs_palloc_groups_per_desc_block(inode);
3535442680fSRyusuke Konishi }
3545442680fSRyusuke Konishi 
355db55d922SRyusuke Konishi /**
356db55d922SRyusuke Konishi  * nilfs_palloc_block_get_entry - get kernel address of an entry
357db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
358db55d922SRyusuke Konishi  * @nr: serial number of the entry (e.g. inode number)
359db55d922SRyusuke Konishi  * @bh: buffer head of the buffer storing the entry block
360db55d922SRyusuke Konishi  * @kaddr: kernel address mapped for the page including the buffer
361db55d922SRyusuke Konishi  */
nilfs_palloc_block_get_entry(const struct inode * inode,__u64 nr,const struct buffer_head * bh,void * kaddr)3625442680fSRyusuke Konishi void *nilfs_palloc_block_get_entry(const struct inode *inode, __u64 nr,
3635442680fSRyusuke Konishi 				   const struct buffer_head *bh, void *kaddr)
3645442680fSRyusuke Konishi {
3655442680fSRyusuke Konishi 	unsigned long entry_offset, group_offset;
3665442680fSRyusuke Konishi 
3675442680fSRyusuke Konishi 	nilfs_palloc_group(inode, nr, &group_offset);
3685442680fSRyusuke Konishi 	entry_offset = group_offset % NILFS_MDT(inode)->mi_entries_per_block;
3695442680fSRyusuke Konishi 
3705442680fSRyusuke Konishi 	return kaddr + bh_offset(bh) +
3715442680fSRyusuke Konishi 		entry_offset * NILFS_MDT(inode)->mi_entry_size;
3725442680fSRyusuke Konishi }
3735442680fSRyusuke Konishi 
374db55d922SRyusuke Konishi /**
375db55d922SRyusuke Konishi  * nilfs_palloc_find_available_slot - find available slot in a group
376db55d922SRyusuke Konishi  * @bitmap: bitmap of the group
3774e9e63a6SRyusuke Konishi  * @target: offset number of an entry in the group (start point)
378db55d922SRyusuke Konishi  * @bsize: size in bits
3794e9e63a6SRyusuke Konishi  * @lock: spin lock protecting @bitmap
380*95b13625SRyusuke Konishi  * @wrap: whether to wrap around
381db55d922SRyusuke Konishi  */
nilfs_palloc_find_available_slot(unsigned char * bitmap,unsigned long target,unsigned int bsize,spinlock_t * lock,bool wrap)3824e9e63a6SRyusuke Konishi static int nilfs_palloc_find_available_slot(unsigned char *bitmap,
3835442680fSRyusuke Konishi 					    unsigned long target,
3840c6c44cbSRyusuke Konishi 					    unsigned int bsize,
385*95b13625SRyusuke Konishi 					    spinlock_t *lock, bool wrap)
3865442680fSRyusuke Konishi {
38718c41b37SRyusuke Konishi 	int pos, end = bsize;
3885442680fSRyusuke Konishi 
38918c41b37SRyusuke Konishi 	if (likely(target < bsize)) {
39018c41b37SRyusuke Konishi 		pos = target;
39118c41b37SRyusuke Konishi 		do {
39218c41b37SRyusuke Konishi 			pos = nilfs_find_next_zero_bit(bitmap, end, pos);
39318c41b37SRyusuke Konishi 			if (pos >= end)
39418c41b37SRyusuke Konishi 				break;
39518c41b37SRyusuke Konishi 			if (!nilfs_set_bit_atomic(lock, pos, bitmap))
3965442680fSRyusuke Konishi 				return pos;
39718c41b37SRyusuke Konishi 		} while (++pos < end);
39818c41b37SRyusuke Konishi 
39918c41b37SRyusuke Konishi 		end = target;
4004e9e63a6SRyusuke Konishi 	}
401*95b13625SRyusuke Konishi 	if (!wrap)
402*95b13625SRyusuke Konishi 		return -ENOSPC;
4035442680fSRyusuke Konishi 
4045442680fSRyusuke Konishi 	/* wrap around */
40518c41b37SRyusuke Konishi 	for (pos = 0; pos < end; pos++) {
40618c41b37SRyusuke Konishi 		pos = nilfs_find_next_zero_bit(bitmap, end, pos);
40718c41b37SRyusuke Konishi 		if (pos >= end)
40818c41b37SRyusuke Konishi 			break;
40918c41b37SRyusuke Konishi 		if (!nilfs_set_bit_atomic(lock, pos, bitmap))
4105442680fSRyusuke Konishi 			return pos;
4115442680fSRyusuke Konishi 	}
41218c41b37SRyusuke Konishi 
4135442680fSRyusuke Konishi 	return -ENOSPC;
4145442680fSRyusuke Konishi }
4155442680fSRyusuke Konishi 
416db55d922SRyusuke Konishi /**
417db55d922SRyusuke Konishi  * nilfs_palloc_rest_groups_in_desc_block - get the remaining number of groups
418db55d922SRyusuke Konishi  *					    in a group descriptor block
419db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
420db55d922SRyusuke Konishi  * @curr: current group number
421db55d922SRyusuke Konishi  * @max: maximum number of groups
422db55d922SRyusuke Konishi  */
4235442680fSRyusuke Konishi static unsigned long
nilfs_palloc_rest_groups_in_desc_block(const struct inode * inode,unsigned long curr,unsigned long max)4245442680fSRyusuke Konishi nilfs_palloc_rest_groups_in_desc_block(const struct inode *inode,
4255442680fSRyusuke Konishi 				       unsigned long curr, unsigned long max)
4265442680fSRyusuke Konishi {
4275442680fSRyusuke Konishi 	return min_t(unsigned long,
4285442680fSRyusuke Konishi 		     nilfs_palloc_groups_per_desc_block(inode) -
4295442680fSRyusuke Konishi 		     curr % nilfs_palloc_groups_per_desc_block(inode),
4305442680fSRyusuke Konishi 		     max - curr + 1);
4315442680fSRyusuke Konishi }
4325442680fSRyusuke Konishi 
433db55d922SRyusuke Konishi /**
434c7ef972cSVyacheslav Dubeyko  * nilfs_palloc_count_desc_blocks - count descriptor blocks number
435c7ef972cSVyacheslav Dubeyko  * @inode: inode of metadata file using this allocator
436c7ef972cSVyacheslav Dubeyko  * @desc_blocks: descriptor blocks number [out]
437c7ef972cSVyacheslav Dubeyko  */
nilfs_palloc_count_desc_blocks(struct inode * inode,unsigned long * desc_blocks)438c7ef972cSVyacheslav Dubeyko static int nilfs_palloc_count_desc_blocks(struct inode *inode,
439c7ef972cSVyacheslav Dubeyko 					    unsigned long *desc_blocks)
440c7ef972cSVyacheslav Dubeyko {
4413568a13fSRyusuke Konishi 	__u64 blknum;
442c7ef972cSVyacheslav Dubeyko 	int ret;
443c7ef972cSVyacheslav Dubeyko 
444c7ef972cSVyacheslav Dubeyko 	ret = nilfs_bmap_last_key(NILFS_I(inode)->i_bmap, &blknum);
445c7ef972cSVyacheslav Dubeyko 	if (likely(!ret))
446c7ef972cSVyacheslav Dubeyko 		*desc_blocks = DIV_ROUND_UP(
4473568a13fSRyusuke Konishi 			(unsigned long)blknum,
4483568a13fSRyusuke Konishi 			NILFS_MDT(inode)->mi_blocks_per_desc_block);
449c7ef972cSVyacheslav Dubeyko 	return ret;
450c7ef972cSVyacheslav Dubeyko }
451c7ef972cSVyacheslav Dubeyko 
452c7ef972cSVyacheslav Dubeyko /**
453c7ef972cSVyacheslav Dubeyko  * nilfs_palloc_mdt_file_can_grow - check potential opportunity for
454c7ef972cSVyacheslav Dubeyko  *					MDT file growing
455c7ef972cSVyacheslav Dubeyko  * @inode: inode of metadata file using this allocator
456c7ef972cSVyacheslav Dubeyko  * @desc_blocks: known current descriptor blocks count
457c7ef972cSVyacheslav Dubeyko  */
nilfs_palloc_mdt_file_can_grow(struct inode * inode,unsigned long desc_blocks)458c7ef972cSVyacheslav Dubeyko static inline bool nilfs_palloc_mdt_file_can_grow(struct inode *inode,
459c7ef972cSVyacheslav Dubeyko 						    unsigned long desc_blocks)
460c7ef972cSVyacheslav Dubeyko {
461c7ef972cSVyacheslav Dubeyko 	return (nilfs_palloc_groups_per_desc_block(inode) * desc_blocks) <
462c7ef972cSVyacheslav Dubeyko 			nilfs_palloc_groups_count(inode);
463c7ef972cSVyacheslav Dubeyko }
464c7ef972cSVyacheslav Dubeyko 
465c7ef972cSVyacheslav Dubeyko /**
466c7ef972cSVyacheslav Dubeyko  * nilfs_palloc_count_max_entries - count max number of entries that can be
467c7ef972cSVyacheslav Dubeyko  *					described by descriptor blocks count
468c7ef972cSVyacheslav Dubeyko  * @inode: inode of metadata file using this allocator
469c7ef972cSVyacheslav Dubeyko  * @nused: current number of used entries
470c7ef972cSVyacheslav Dubeyko  * @nmaxp: max number of entries [out]
471c7ef972cSVyacheslav Dubeyko  */
nilfs_palloc_count_max_entries(struct inode * inode,u64 nused,u64 * nmaxp)472c7ef972cSVyacheslav Dubeyko int nilfs_palloc_count_max_entries(struct inode *inode, u64 nused, u64 *nmaxp)
473c7ef972cSVyacheslav Dubeyko {
474c7ef972cSVyacheslav Dubeyko 	unsigned long desc_blocks = 0;
475c7ef972cSVyacheslav Dubeyko 	u64 entries_per_desc_block, nmax;
476c7ef972cSVyacheslav Dubeyko 	int err;
477c7ef972cSVyacheslav Dubeyko 
478c7ef972cSVyacheslav Dubeyko 	err = nilfs_palloc_count_desc_blocks(inode, &desc_blocks);
479c7ef972cSVyacheslav Dubeyko 	if (unlikely(err))
480c7ef972cSVyacheslav Dubeyko 		return err;
481c7ef972cSVyacheslav Dubeyko 
482c7ef972cSVyacheslav Dubeyko 	entries_per_desc_block = (u64)nilfs_palloc_entries_per_group(inode) *
483c7ef972cSVyacheslav Dubeyko 				nilfs_palloc_groups_per_desc_block(inode);
484c7ef972cSVyacheslav Dubeyko 	nmax = entries_per_desc_block * desc_blocks;
485c7ef972cSVyacheslav Dubeyko 
486c7ef972cSVyacheslav Dubeyko 	if (nused == nmax &&
487c7ef972cSVyacheslav Dubeyko 			nilfs_palloc_mdt_file_can_grow(inode, desc_blocks))
488c7ef972cSVyacheslav Dubeyko 		nmax += entries_per_desc_block;
489c7ef972cSVyacheslav Dubeyko 
490c7ef972cSVyacheslav Dubeyko 	if (nused > nmax)
491c7ef972cSVyacheslav Dubeyko 		return -ERANGE;
492c7ef972cSVyacheslav Dubeyko 
493c7ef972cSVyacheslav Dubeyko 	*nmaxp = nmax;
494c7ef972cSVyacheslav Dubeyko 	return 0;
495c7ef972cSVyacheslav Dubeyko }
496c7ef972cSVyacheslav Dubeyko 
497c7ef972cSVyacheslav Dubeyko /**
498db55d922SRyusuke Konishi  * nilfs_palloc_prepare_alloc_entry - prepare to allocate a persistent object
499db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
500db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the allocation
501*95b13625SRyusuke Konishi  * @wrap: whether to wrap around
502db55d922SRyusuke Konishi  */
nilfs_palloc_prepare_alloc_entry(struct inode * inode,struct nilfs_palloc_req * req,bool wrap)5035442680fSRyusuke Konishi int nilfs_palloc_prepare_alloc_entry(struct inode *inode,
504*95b13625SRyusuke Konishi 				     struct nilfs_palloc_req *req, bool wrap)
5055442680fSRyusuke Konishi {
5065442680fSRyusuke Konishi 	struct buffer_head *desc_bh, *bitmap_bh;
5075442680fSRyusuke Konishi 	struct nilfs_palloc_group_desc *desc;
5085442680fSRyusuke Konishi 	unsigned char *bitmap;
5095442680fSRyusuke Konishi 	void *desc_kaddr, *bitmap_kaddr;
5105442680fSRyusuke Konishi 	unsigned long group, maxgroup, ngroups;
5115442680fSRyusuke Konishi 	unsigned long group_offset, maxgroup_offset;
51209ef29e0SRyusuke Konishi 	unsigned long n, entries_per_group;
5135442680fSRyusuke Konishi 	unsigned long i, j;
5144e9e63a6SRyusuke Konishi 	spinlock_t *lock;
5155442680fSRyusuke Konishi 	int pos, ret;
5165442680fSRyusuke Konishi 
5175442680fSRyusuke Konishi 	ngroups = nilfs_palloc_groups_count(inode);
5185442680fSRyusuke Konishi 	maxgroup = ngroups - 1;
5195442680fSRyusuke Konishi 	group = nilfs_palloc_group(inode, req->pr_entry_nr, &group_offset);
5205442680fSRyusuke Konishi 	entries_per_group = nilfs_palloc_entries_per_group(inode);
5215442680fSRyusuke Konishi 
5225442680fSRyusuke Konishi 	for (i = 0; i < ngroups; i += n) {
523*95b13625SRyusuke Konishi 		if (group >= ngroups && wrap) {
5245442680fSRyusuke Konishi 			/* wrap around */
5255442680fSRyusuke Konishi 			group = 0;
5265442680fSRyusuke Konishi 			maxgroup = nilfs_palloc_group(inode, req->pr_entry_nr,
5275442680fSRyusuke Konishi 						      &maxgroup_offset) - 1;
5285442680fSRyusuke Konishi 		}
5295442680fSRyusuke Konishi 		ret = nilfs_palloc_get_desc_block(inode, group, 1, &desc_bh);
5305442680fSRyusuke Konishi 		if (ret < 0)
5315442680fSRyusuke Konishi 			return ret;
5325442680fSRyusuke Konishi 		desc_kaddr = kmap(desc_bh->b_page);
5335442680fSRyusuke Konishi 		desc = nilfs_palloc_block_get_group_desc(
5345442680fSRyusuke Konishi 			inode, group, desc_bh, desc_kaddr);
5355442680fSRyusuke Konishi 		n = nilfs_palloc_rest_groups_in_desc_block(inode, group,
5365442680fSRyusuke Konishi 							   maxgroup);
5375442680fSRyusuke Konishi 		for (j = 0; j < n; j++, desc++, group++) {
5384e9e63a6SRyusuke Konishi 			lock = nilfs_mdt_bgl_lock(inode, group);
5394e9e63a6SRyusuke Konishi 			if (nilfs_palloc_group_desc_nfrees(desc, lock) > 0) {
5405442680fSRyusuke Konishi 				ret = nilfs_palloc_get_bitmap_block(
5415442680fSRyusuke Konishi 					inode, group, 1, &bitmap_bh);
5425442680fSRyusuke Konishi 				if (ret < 0)
5435442680fSRyusuke Konishi 					goto out_desc;
5445442680fSRyusuke Konishi 				bitmap_kaddr = kmap(bitmap_bh->b_page);
545141bbdbaSRyusuke Konishi 				bitmap = bitmap_kaddr + bh_offset(bitmap_bh);
5465442680fSRyusuke Konishi 				pos = nilfs_palloc_find_available_slot(
5474e9e63a6SRyusuke Konishi 					bitmap, group_offset,
548*95b13625SRyusuke Konishi 					entries_per_group, lock, wrap);
549*95b13625SRyusuke Konishi 				/*
550*95b13625SRyusuke Konishi 				 * Since the search for a free slot in the
551*95b13625SRyusuke Konishi 				 * second and subsequent bitmap blocks always
552*95b13625SRyusuke Konishi 				 * starts from the beginning, the wrap flag
553*95b13625SRyusuke Konishi 				 * only has an effect on the first search.
554*95b13625SRyusuke Konishi 				 */
5555442680fSRyusuke Konishi 				if (pos >= 0) {
5565442680fSRyusuke Konishi 					/* found a free entry */
5575442680fSRyusuke Konishi 					nilfs_palloc_group_desc_add_entries(
5584e9e63a6SRyusuke Konishi 						desc, lock, -1);
5595442680fSRyusuke Konishi 					req->pr_entry_nr =
5605442680fSRyusuke Konishi 						entries_per_group * group + pos;
5615442680fSRyusuke Konishi 					kunmap(desc_bh->b_page);
5625442680fSRyusuke Konishi 					kunmap(bitmap_bh->b_page);
5635442680fSRyusuke Konishi 
5645442680fSRyusuke Konishi 					req->pr_desc_bh = desc_bh;
5655442680fSRyusuke Konishi 					req->pr_bitmap_bh = bitmap_bh;
5665442680fSRyusuke Konishi 					return 0;
5675442680fSRyusuke Konishi 				}
5685442680fSRyusuke Konishi 				kunmap(bitmap_bh->b_page);
5695442680fSRyusuke Konishi 				brelse(bitmap_bh);
5705442680fSRyusuke Konishi 			}
5715442680fSRyusuke Konishi 
5725442680fSRyusuke Konishi 			group_offset = 0;
5735442680fSRyusuke Konishi 		}
5745442680fSRyusuke Konishi 
5755442680fSRyusuke Konishi 		kunmap(desc_bh->b_page);
5765442680fSRyusuke Konishi 		brelse(desc_bh);
5775442680fSRyusuke Konishi 	}
5785442680fSRyusuke Konishi 
5795442680fSRyusuke Konishi 	/* no entries left */
5805442680fSRyusuke Konishi 	return -ENOSPC;
5815442680fSRyusuke Konishi 
5825442680fSRyusuke Konishi  out_desc:
5835442680fSRyusuke Konishi 	kunmap(desc_bh->b_page);
5845442680fSRyusuke Konishi 	brelse(desc_bh);
5855442680fSRyusuke Konishi 	return ret;
5865442680fSRyusuke Konishi }
5875442680fSRyusuke Konishi 
588db55d922SRyusuke Konishi /**
589db55d922SRyusuke Konishi  * nilfs_palloc_commit_alloc_entry - finish allocation of a persistent object
590db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
591db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the allocation
592db55d922SRyusuke Konishi  */
nilfs_palloc_commit_alloc_entry(struct inode * inode,struct nilfs_palloc_req * req)5935442680fSRyusuke Konishi void nilfs_palloc_commit_alloc_entry(struct inode *inode,
5945442680fSRyusuke Konishi 				     struct nilfs_palloc_req *req)
5955442680fSRyusuke Konishi {
5965fc7b141SRyusuke Konishi 	mark_buffer_dirty(req->pr_bitmap_bh);
5975fc7b141SRyusuke Konishi 	mark_buffer_dirty(req->pr_desc_bh);
5985442680fSRyusuke Konishi 	nilfs_mdt_mark_dirty(inode);
5995442680fSRyusuke Konishi 
6005442680fSRyusuke Konishi 	brelse(req->pr_bitmap_bh);
6015442680fSRyusuke Konishi 	brelse(req->pr_desc_bh);
6025442680fSRyusuke Konishi }
6035442680fSRyusuke Konishi 
604db55d922SRyusuke Konishi /**
605db55d922SRyusuke Konishi  * nilfs_palloc_commit_free_entry - finish deallocating a persistent object
606db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
607db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the removal
608db55d922SRyusuke Konishi  */
nilfs_palloc_commit_free_entry(struct inode * inode,struct nilfs_palloc_req * req)6095442680fSRyusuke Konishi void nilfs_palloc_commit_free_entry(struct inode *inode,
6105442680fSRyusuke Konishi 				    struct nilfs_palloc_req *req)
6115442680fSRyusuke Konishi {
6125442680fSRyusuke Konishi 	struct nilfs_palloc_group_desc *desc;
6135442680fSRyusuke Konishi 	unsigned long group, group_offset;
6145442680fSRyusuke Konishi 	unsigned char *bitmap;
6155442680fSRyusuke Konishi 	void *desc_kaddr, *bitmap_kaddr;
6164e9e63a6SRyusuke Konishi 	spinlock_t *lock;
6175442680fSRyusuke Konishi 
6185442680fSRyusuke Konishi 	group = nilfs_palloc_group(inode, req->pr_entry_nr, &group_offset);
6195442680fSRyusuke Konishi 	desc_kaddr = kmap(req->pr_desc_bh->b_page);
6205442680fSRyusuke Konishi 	desc = nilfs_palloc_block_get_group_desc(inode, group,
6215442680fSRyusuke Konishi 						 req->pr_desc_bh, desc_kaddr);
6225442680fSRyusuke Konishi 	bitmap_kaddr = kmap(req->pr_bitmap_bh->b_page);
623141bbdbaSRyusuke Konishi 	bitmap = bitmap_kaddr + bh_offset(req->pr_bitmap_bh);
6244e9e63a6SRyusuke Konishi 	lock = nilfs_mdt_bgl_lock(inode, group);
6255442680fSRyusuke Konishi 
6264e9e63a6SRyusuke Konishi 	if (!nilfs_clear_bit_atomic(lock, group_offset, bitmap))
627a1d0747aSJoe Perches 		nilfs_warn(inode->i_sb,
628d6517debSRyusuke Konishi 			   "%s (ino=%lu): entry number %llu already freed",
629d6517debSRyusuke Konishi 			   __func__, inode->i_ino,
630d6517debSRyusuke Konishi 			   (unsigned long long)req->pr_entry_nr);
6319954e7afSRyusuke Konishi 	else
6324e9e63a6SRyusuke Konishi 		nilfs_palloc_group_desc_add_entries(desc, lock, 1);
6335442680fSRyusuke Konishi 
6345442680fSRyusuke Konishi 	kunmap(req->pr_bitmap_bh->b_page);
6355442680fSRyusuke Konishi 	kunmap(req->pr_desc_bh->b_page);
6365442680fSRyusuke Konishi 
6375fc7b141SRyusuke Konishi 	mark_buffer_dirty(req->pr_desc_bh);
6385fc7b141SRyusuke Konishi 	mark_buffer_dirty(req->pr_bitmap_bh);
6395442680fSRyusuke Konishi 	nilfs_mdt_mark_dirty(inode);
6405442680fSRyusuke Konishi 
6415442680fSRyusuke Konishi 	brelse(req->pr_bitmap_bh);
6425442680fSRyusuke Konishi 	brelse(req->pr_desc_bh);
6435442680fSRyusuke Konishi }
6445442680fSRyusuke Konishi 
645db55d922SRyusuke Konishi /**
646db55d922SRyusuke Konishi  * nilfs_palloc_abort_alloc_entry - cancel allocation of a persistent object
647db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
648db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the allocation
649db55d922SRyusuke Konishi  */
nilfs_palloc_abort_alloc_entry(struct inode * inode,struct nilfs_palloc_req * req)6505442680fSRyusuke Konishi void nilfs_palloc_abort_alloc_entry(struct inode *inode,
6515442680fSRyusuke Konishi 				    struct nilfs_palloc_req *req)
6525442680fSRyusuke Konishi {
6535442680fSRyusuke Konishi 	struct nilfs_palloc_group_desc *desc;
6545442680fSRyusuke Konishi 	void *desc_kaddr, *bitmap_kaddr;
6555442680fSRyusuke Konishi 	unsigned char *bitmap;
6565442680fSRyusuke Konishi 	unsigned long group, group_offset;
6574e9e63a6SRyusuke Konishi 	spinlock_t *lock;
6585442680fSRyusuke Konishi 
6595442680fSRyusuke Konishi 	group = nilfs_palloc_group(inode, req->pr_entry_nr, &group_offset);
6605442680fSRyusuke Konishi 	desc_kaddr = kmap(req->pr_desc_bh->b_page);
6615442680fSRyusuke Konishi 	desc = nilfs_palloc_block_get_group_desc(inode, group,
6625442680fSRyusuke Konishi 						 req->pr_desc_bh, desc_kaddr);
6635442680fSRyusuke Konishi 	bitmap_kaddr = kmap(req->pr_bitmap_bh->b_page);
664141bbdbaSRyusuke Konishi 	bitmap = bitmap_kaddr + bh_offset(req->pr_bitmap_bh);
6654e9e63a6SRyusuke Konishi 	lock = nilfs_mdt_bgl_lock(inode, group);
6664e9e63a6SRyusuke Konishi 
6674e9e63a6SRyusuke Konishi 	if (!nilfs_clear_bit_atomic(lock, group_offset, bitmap))
668a1d0747aSJoe Perches 		nilfs_warn(inode->i_sb,
669d6517debSRyusuke Konishi 			   "%s (ino=%lu): entry number %llu already freed",
670d6517debSRyusuke Konishi 			   __func__, inode->i_ino,
671d6517debSRyusuke Konishi 			   (unsigned long long)req->pr_entry_nr);
6729954e7afSRyusuke Konishi 	else
6734e9e63a6SRyusuke Konishi 		nilfs_palloc_group_desc_add_entries(desc, lock, 1);
6745442680fSRyusuke Konishi 
6755442680fSRyusuke Konishi 	kunmap(req->pr_bitmap_bh->b_page);
6765442680fSRyusuke Konishi 	kunmap(req->pr_desc_bh->b_page);
6775442680fSRyusuke Konishi 
6785442680fSRyusuke Konishi 	brelse(req->pr_bitmap_bh);
6795442680fSRyusuke Konishi 	brelse(req->pr_desc_bh);
6805442680fSRyusuke Konishi 
6815442680fSRyusuke Konishi 	req->pr_entry_nr = 0;
6825442680fSRyusuke Konishi 	req->pr_bitmap_bh = NULL;
6835442680fSRyusuke Konishi 	req->pr_desc_bh = NULL;
6845442680fSRyusuke Konishi }
6855442680fSRyusuke Konishi 
686db55d922SRyusuke Konishi /**
687db55d922SRyusuke Konishi  * nilfs_palloc_prepare_free_entry - prepare to deallocate a persistent object
688db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
689db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the removal
690db55d922SRyusuke Konishi  */
nilfs_palloc_prepare_free_entry(struct inode * inode,struct nilfs_palloc_req * req)6915442680fSRyusuke Konishi int nilfs_palloc_prepare_free_entry(struct inode *inode,
6925442680fSRyusuke Konishi 				    struct nilfs_palloc_req *req)
6935442680fSRyusuke Konishi {
6945442680fSRyusuke Konishi 	struct buffer_head *desc_bh, *bitmap_bh;
6955442680fSRyusuke Konishi 	unsigned long group, group_offset;
6965442680fSRyusuke Konishi 	int ret;
6975442680fSRyusuke Konishi 
6985442680fSRyusuke Konishi 	group = nilfs_palloc_group(inode, req->pr_entry_nr, &group_offset);
6995442680fSRyusuke Konishi 	ret = nilfs_palloc_get_desc_block(inode, group, 1, &desc_bh);
7005442680fSRyusuke Konishi 	if (ret < 0)
7015442680fSRyusuke Konishi 		return ret;
7025442680fSRyusuke Konishi 	ret = nilfs_palloc_get_bitmap_block(inode, group, 1, &bitmap_bh);
7035442680fSRyusuke Konishi 	if (ret < 0) {
7045442680fSRyusuke Konishi 		brelse(desc_bh);
7055442680fSRyusuke Konishi 		return ret;
7065442680fSRyusuke Konishi 	}
7075442680fSRyusuke Konishi 
7085442680fSRyusuke Konishi 	req->pr_desc_bh = desc_bh;
7095442680fSRyusuke Konishi 	req->pr_bitmap_bh = bitmap_bh;
7105442680fSRyusuke Konishi 	return 0;
7115442680fSRyusuke Konishi }
7125442680fSRyusuke Konishi 
713db55d922SRyusuke Konishi /**
714db55d922SRyusuke Konishi  * nilfs_palloc_abort_free_entry - cancel deallocating a persistent object
715db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
716db55d922SRyusuke Konishi  * @req: nilfs_palloc_req structure exchanged for the removal
717db55d922SRyusuke Konishi  */
nilfs_palloc_abort_free_entry(struct inode * inode,struct nilfs_palloc_req * req)7185442680fSRyusuke Konishi void nilfs_palloc_abort_free_entry(struct inode *inode,
7195442680fSRyusuke Konishi 				   struct nilfs_palloc_req *req)
7205442680fSRyusuke Konishi {
7215442680fSRyusuke Konishi 	brelse(req->pr_bitmap_bh);
7225442680fSRyusuke Konishi 	brelse(req->pr_desc_bh);
7235442680fSRyusuke Konishi 
7245442680fSRyusuke Konishi 	req->pr_entry_nr = 0;
7255442680fSRyusuke Konishi 	req->pr_bitmap_bh = NULL;
7265442680fSRyusuke Konishi 	req->pr_desc_bh = NULL;
7275442680fSRyusuke Konishi }
7285442680fSRyusuke Konishi 
729db55d922SRyusuke Konishi /**
730db55d922SRyusuke Konishi  * nilfs_palloc_freev - deallocate a set of persistent objects
731db55d922SRyusuke Konishi  * @inode: inode of metadata file using this allocator
732db55d922SRyusuke Konishi  * @entry_nrs: array of entry numbers to be deallocated
733db55d922SRyusuke Konishi  * @nitems: number of entries stored in @entry_nrs
734db55d922SRyusuke Konishi  */
nilfs_palloc_freev(struct inode * inode,__u64 * entry_nrs,size_t nitems)7355442680fSRyusuke Konishi int nilfs_palloc_freev(struct inode *inode, __u64 *entry_nrs, size_t nitems)
7365442680fSRyusuke Konishi {
7375442680fSRyusuke Konishi 	struct buffer_head *desc_bh, *bitmap_bh;
7385442680fSRyusuke Konishi 	struct nilfs_palloc_group_desc *desc;
7395442680fSRyusuke Konishi 	unsigned char *bitmap;
7405442680fSRyusuke Konishi 	void *desc_kaddr, *bitmap_kaddr;
7415442680fSRyusuke Konishi 	unsigned long group, group_offset;
742d0c14a9eSRyusuke Konishi 	__u64 group_min_nr, last_nrs[8];
743b2258094SRyusuke Konishi 	const unsigned long epg = nilfs_palloc_entries_per_group(inode);
7440c6c44cbSRyusuke Konishi 	const unsigned int epb = NILFS_MDT(inode)->mi_entries_per_block;
7450c6c44cbSRyusuke Konishi 	unsigned int entry_start, end, pos;
7464e9e63a6SRyusuke Konishi 	spinlock_t *lock;
747d0c14a9eSRyusuke Konishi 	int i, j, k, ret;
748d0c14a9eSRyusuke Konishi 	u32 nfree;
7495442680fSRyusuke Konishi 
750349dbc36SRyusuke Konishi 	for (i = 0; i < nitems; i = j) {
751d0c14a9eSRyusuke Konishi 		int change_group = false;
752d0c14a9eSRyusuke Konishi 		int nempties = 0, n = 0;
753d0c14a9eSRyusuke Konishi 
7545442680fSRyusuke Konishi 		group = nilfs_palloc_group(inode, entry_nrs[i], &group_offset);
7555442680fSRyusuke Konishi 		ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh);
7565442680fSRyusuke Konishi 		if (ret < 0)
7575442680fSRyusuke Konishi 			return ret;
7585442680fSRyusuke Konishi 		ret = nilfs_palloc_get_bitmap_block(inode, group, 0,
7595442680fSRyusuke Konishi 						    &bitmap_bh);
7605442680fSRyusuke Konishi 		if (ret < 0) {
7615442680fSRyusuke Konishi 			brelse(desc_bh);
7625442680fSRyusuke Konishi 			return ret;
7635442680fSRyusuke Konishi 		}
764b2258094SRyusuke Konishi 
765b2258094SRyusuke Konishi 		/* Get the first entry number of the group */
766b2258094SRyusuke Konishi 		group_min_nr = (__u64)group * epg;
767b2258094SRyusuke Konishi 
7685442680fSRyusuke Konishi 		bitmap_kaddr = kmap(bitmap_bh->b_page);
769141bbdbaSRyusuke Konishi 		bitmap = bitmap_kaddr + bh_offset(bitmap_bh);
7704e9e63a6SRyusuke Konishi 		lock = nilfs_mdt_bgl_lock(inode, group);
771d0c14a9eSRyusuke Konishi 
772d0c14a9eSRyusuke Konishi 		j = i;
773d0c14a9eSRyusuke Konishi 		entry_start = rounddown(group_offset, epb);
774d0c14a9eSRyusuke Konishi 		do {
7754e9e63a6SRyusuke Konishi 			if (!nilfs_clear_bit_atomic(lock, group_offset,
7764e9e63a6SRyusuke Konishi 						    bitmap)) {
777a1d0747aSJoe Perches 				nilfs_warn(inode->i_sb,
778d6517debSRyusuke Konishi 					   "%s (ino=%lu): entry number %llu already freed",
779d6517debSRyusuke Konishi 					   __func__, inode->i_ino,
780d6517debSRyusuke Konishi 					   (unsigned long long)entry_nrs[j]);
7819954e7afSRyusuke Konishi 			} else {
7829954e7afSRyusuke Konishi 				n++;
7835442680fSRyusuke Konishi 			}
784d0c14a9eSRyusuke Konishi 
785d0c14a9eSRyusuke Konishi 			j++;
786d0c14a9eSRyusuke Konishi 			if (j >= nitems || entry_nrs[j] < group_min_nr ||
787d0c14a9eSRyusuke Konishi 			    entry_nrs[j] >= group_min_nr + epg) {
788d0c14a9eSRyusuke Konishi 				change_group = true;
789d0c14a9eSRyusuke Konishi 			} else {
790d0c14a9eSRyusuke Konishi 				group_offset = entry_nrs[j] - group_min_nr;
791d0c14a9eSRyusuke Konishi 				if (group_offset >= entry_start &&
792d0c14a9eSRyusuke Konishi 				    group_offset < entry_start + epb) {
793d0c14a9eSRyusuke Konishi 					/* This entry is in the same block */
794d0c14a9eSRyusuke Konishi 					continue;
7955442680fSRyusuke Konishi 				}
796d0c14a9eSRyusuke Konishi 			}
797d0c14a9eSRyusuke Konishi 
798d0c14a9eSRyusuke Konishi 			/* Test if the entry block is empty or not */
799d0c14a9eSRyusuke Konishi 			end = entry_start + epb;
800d0c14a9eSRyusuke Konishi 			pos = nilfs_find_next_bit(bitmap, end, entry_start);
801d0c14a9eSRyusuke Konishi 			if (pos >= end) {
802d0c14a9eSRyusuke Konishi 				last_nrs[nempties++] = entry_nrs[j - 1];
803d0c14a9eSRyusuke Konishi 				if (nempties >= ARRAY_SIZE(last_nrs))
804d0c14a9eSRyusuke Konishi 					break;
805d0c14a9eSRyusuke Konishi 			}
806d0c14a9eSRyusuke Konishi 
807d0c14a9eSRyusuke Konishi 			if (change_group)
808d0c14a9eSRyusuke Konishi 				break;
809d0c14a9eSRyusuke Konishi 
810d0c14a9eSRyusuke Konishi 			/* Go on to the next entry block */
811d0c14a9eSRyusuke Konishi 			entry_start = rounddown(group_offset, epb);
812d0c14a9eSRyusuke Konishi 		} while (true);
8135442680fSRyusuke Konishi 
8145442680fSRyusuke Konishi 		kunmap(bitmap_bh->b_page);
8155fc7b141SRyusuke Konishi 		mark_buffer_dirty(bitmap_bh);
8165442680fSRyusuke Konishi 		brelse(bitmap_bh);
817d0c14a9eSRyusuke Konishi 
818d0c14a9eSRyusuke Konishi 		for (k = 0; k < nempties; k++) {
819d0c14a9eSRyusuke Konishi 			ret = nilfs_palloc_delete_entry_block(inode,
820d0c14a9eSRyusuke Konishi 							      last_nrs[k]);
821d6517debSRyusuke Konishi 			if (ret && ret != -ENOENT)
822a1d0747aSJoe Perches 				nilfs_warn(inode->i_sb,
823d6517debSRyusuke Konishi 					   "error %d deleting block that object (entry=%llu, ino=%lu) belongs to",
824d6517debSRyusuke Konishi 					   ret, (unsigned long long)last_nrs[k],
825d6517debSRyusuke Konishi 					   inode->i_ino);
826d0c14a9eSRyusuke Konishi 		}
827d0c14a9eSRyusuke Konishi 
828d0c14a9eSRyusuke Konishi 		desc_kaddr = kmap_atomic(desc_bh->b_page);
829d0c14a9eSRyusuke Konishi 		desc = nilfs_palloc_block_get_group_desc(
830d0c14a9eSRyusuke Konishi 			inode, group, desc_bh, desc_kaddr);
831d0c14a9eSRyusuke Konishi 		nfree = nilfs_palloc_group_desc_add_entries(desc, lock, n);
832d0c14a9eSRyusuke Konishi 		kunmap_atomic(desc_kaddr);
833d0c14a9eSRyusuke Konishi 		mark_buffer_dirty(desc_bh);
834d0c14a9eSRyusuke Konishi 		nilfs_mdt_mark_dirty(inode);
8355442680fSRyusuke Konishi 		brelse(desc_bh);
836d0c14a9eSRyusuke Konishi 
837d0c14a9eSRyusuke Konishi 		if (nfree == nilfs_palloc_entries_per_group(inode)) {
838d0c14a9eSRyusuke Konishi 			ret = nilfs_palloc_delete_bitmap_block(inode, group);
839d6517debSRyusuke Konishi 			if (ret && ret != -ENOENT)
840a1d0747aSJoe Perches 				nilfs_warn(inode->i_sb,
841d6517debSRyusuke Konishi 					   "error %d deleting bitmap block of group=%lu, ino=%lu",
842d6517debSRyusuke Konishi 					   ret, group, inode->i_ino);
843d0c14a9eSRyusuke Konishi 		}
8445442680fSRyusuke Konishi 	}
8455442680fSRyusuke Konishi 	return 0;
8465442680fSRyusuke Konishi }
847db38d5adSRyusuke Konishi 
nilfs_palloc_setup_cache(struct inode * inode,struct nilfs_palloc_cache * cache)848db38d5adSRyusuke Konishi void nilfs_palloc_setup_cache(struct inode *inode,
849db38d5adSRyusuke Konishi 			      struct nilfs_palloc_cache *cache)
850db38d5adSRyusuke Konishi {
851db38d5adSRyusuke Konishi 	NILFS_MDT(inode)->mi_palloc_cache = cache;
852db38d5adSRyusuke Konishi 	spin_lock_init(&cache->lock);
853db38d5adSRyusuke Konishi }
854db38d5adSRyusuke Konishi 
nilfs_palloc_clear_cache(struct inode * inode)855db38d5adSRyusuke Konishi void nilfs_palloc_clear_cache(struct inode *inode)
856db38d5adSRyusuke Konishi {
857db38d5adSRyusuke Konishi 	struct nilfs_palloc_cache *cache = NILFS_MDT(inode)->mi_palloc_cache;
858db38d5adSRyusuke Konishi 
859db38d5adSRyusuke Konishi 	spin_lock(&cache->lock);
860db38d5adSRyusuke Konishi 	brelse(cache->prev_desc.bh);
861db38d5adSRyusuke Konishi 	brelse(cache->prev_bitmap.bh);
862db38d5adSRyusuke Konishi 	brelse(cache->prev_entry.bh);
863db38d5adSRyusuke Konishi 	cache->prev_desc.bh = NULL;
864db38d5adSRyusuke Konishi 	cache->prev_bitmap.bh = NULL;
865db38d5adSRyusuke Konishi 	cache->prev_entry.bh = NULL;
866db38d5adSRyusuke Konishi 	spin_unlock(&cache->lock);
867db38d5adSRyusuke Konishi }
868db38d5adSRyusuke Konishi 
nilfs_palloc_destroy_cache(struct inode * inode)869db38d5adSRyusuke Konishi void nilfs_palloc_destroy_cache(struct inode *inode)
870db38d5adSRyusuke Konishi {
871db38d5adSRyusuke Konishi 	nilfs_palloc_clear_cache(inode);
872db38d5adSRyusuke Konishi 	NILFS_MDT(inode)->mi_palloc_cache = NULL;
873db38d5adSRyusuke Konishi }
874