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