xref: /openbmc/linux/fs/bfs/file.c (revision 3f165e4c)
1 /*
2  *	fs/bfs/file.c
3  *	BFS file operations.
4  *	Copyright (C) 1999,2000 Tigran Aivazian <tigran@veritas.com>
5  *
6  *	Make the file block allocation algorithm understand the size
7  *	of the underlying block device.
8  *	Copyright (C) 2007 Dmitri Vorobiev <dmitri.vorobiev@gmail.com>
9  *
10  */
11 
12 #include <linux/fs.h>
13 #include <linux/buffer_head.h>
14 #include <linux/smp_lock.h>
15 #include "bfs.h"
16 
17 #undef DEBUG
18 
19 #ifdef DEBUG
20 #define dprintf(x...)	printf(x)
21 #else
22 #define dprintf(x...)
23 #endif
24 
25 const struct file_operations bfs_file_operations = {
26 	.llseek 	= generic_file_llseek,
27 	.read		= do_sync_read,
28 	.aio_read	= generic_file_aio_read,
29 	.write		= do_sync_write,
30 	.aio_write	= generic_file_aio_write,
31 	.mmap		= generic_file_mmap,
32 	.splice_read	= generic_file_splice_read,
33 };
34 
35 static int bfs_move_block(unsigned long from, unsigned long to,
36 					struct super_block *sb)
37 {
38 	struct buffer_head *bh, *new;
39 
40 	bh = sb_bread(sb, from);
41 	if (!bh)
42 		return -EIO;
43 	new = sb_getblk(sb, to);
44 	memcpy(new->b_data, bh->b_data, bh->b_size);
45 	mark_buffer_dirty(new);
46 	bforget(bh);
47 	brelse(new);
48 	return 0;
49 }
50 
51 static int bfs_move_blocks(struct super_block *sb, unsigned long start,
52 				unsigned long end, unsigned long where)
53 {
54 	unsigned long i;
55 
56 	dprintf("%08lx-%08lx->%08lx\n", start, end, where);
57 	for (i = start; i <= end; i++)
58 		if(bfs_move_block(i, where + i, sb)) {
59 			dprintf("failed to move block %08lx -> %08lx\n", i,
60 								where + i);
61 			return -EIO;
62 		}
63 	return 0;
64 }
65 
66 static int bfs_get_block(struct inode *inode, sector_t block,
67 			struct buffer_head *bh_result, int create)
68 {
69 	unsigned long phys;
70 	int err;
71 	struct super_block *sb = inode->i_sb;
72 	struct bfs_sb_info *info = BFS_SB(sb);
73 	struct bfs_inode_info *bi = BFS_I(inode);
74 	struct buffer_head *sbh = info->si_sbh;
75 
76 	phys = bi->i_sblock + block;
77 	if (!create) {
78 		if (phys <= bi->i_eblock) {
79 			dprintf("c=%d, b=%08lx, phys=%09lx (granted)\n",
80                                 create, (unsigned long)block, phys);
81 			map_bh(bh_result, sb, phys);
82 		}
83 		return 0;
84 	}
85 
86 	/*
87 	 * If the file is not empty and the requested block is within the
88 	 * range of blocks allocated for this file, we can grant it.
89 	 */
90 	if (bi->i_sblock && (phys <= bi->i_eblock)) {
91 		dprintf("c=%d, b=%08lx, phys=%08lx (interim block granted)\n",
92 				create, (unsigned long)block, phys);
93 		map_bh(bh_result, sb, phys);
94 		return 0;
95 	}
96 
97 	/* The file will be extended, so let's see if there is enough space. */
98 	if (phys >= info->si_blocks)
99 		return -ENOSPC;
100 
101 	/* The rest has to be protected against itself. */
102 	mutex_lock(&info->bfs_lock);
103 
104 	/*
105 	 * If the last data block for this file is the last allocated
106 	 * block, we can extend the file trivially, without moving it
107 	 * anywhere.
108 	 */
109 	if (bi->i_eblock == info->si_lf_eblk) {
110 		dprintf("c=%d, b=%08lx, phys=%08lx (simple extension)\n",
111 				create, (unsigned long)block, phys);
112 		map_bh(bh_result, sb, phys);
113 		info->si_freeb -= phys - bi->i_eblock;
114 		info->si_lf_eblk = bi->i_eblock = phys;
115 		mark_inode_dirty(inode);
116 		mark_buffer_dirty(sbh);
117 		err = 0;
118 		goto out;
119 	}
120 
121 	/* Ok, we have to move this entire file to the next free block. */
122 	phys = info->si_lf_eblk + 1;
123 	if (phys + block >= info->si_blocks) {
124 		err = -ENOSPC;
125 		goto out;
126 	}
127 
128 	if (bi->i_sblock) {
129 		err = bfs_move_blocks(inode->i_sb, bi->i_sblock,
130 						bi->i_eblock, phys);
131 		if (err) {
132 			dprintf("failed to move ino=%08lx -> fs corruption\n",
133 								inode->i_ino);
134 			goto out;
135 		}
136 	} else
137 		err = 0;
138 
139 	dprintf("c=%d, b=%08lx, phys=%08lx (moved)\n",
140                 create, (unsigned long)block, phys);
141 	bi->i_sblock = phys;
142 	phys += block;
143 	info->si_lf_eblk = bi->i_eblock = phys;
144 
145 	/*
146 	 * This assumes nothing can write the inode back while we are here
147 	 * and thus update inode->i_blocks! (XXX)
148 	 */
149 	info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks;
150 	mark_inode_dirty(inode);
151 	mark_buffer_dirty(sbh);
152 	map_bh(bh_result, sb, phys);
153 out:
154 	mutex_unlock(&info->bfs_lock);
155 	return err;
156 }
157 
158 static int bfs_writepage(struct page *page, struct writeback_control *wbc)
159 {
160 	return block_write_full_page(page, bfs_get_block, wbc);
161 }
162 
163 static int bfs_readpage(struct file *file, struct page *page)
164 {
165 	return block_read_full_page(page, bfs_get_block);
166 }
167 
168 static int bfs_write_begin(struct file *file, struct address_space *mapping,
169 			loff_t pos, unsigned len, unsigned flags,
170 			struct page **pagep, void **fsdata)
171 {
172 	*pagep = NULL;
173 	return block_write_begin(file, mapping, pos, len, flags,
174 					pagep, fsdata, bfs_get_block);
175 }
176 
177 static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
178 {
179 	return generic_block_bmap(mapping, block, bfs_get_block);
180 }
181 
182 const struct address_space_operations bfs_aops = {
183 	.readpage	= bfs_readpage,
184 	.writepage	= bfs_writepage,
185 	.sync_page	= block_sync_page,
186 	.write_begin	= bfs_write_begin,
187 	.write_end	= generic_write_end,
188 	.bmap		= bfs_bmap,
189 };
190 
191 const struct inode_operations bfs_file_inops;
192