Blame view

fs/ufs/util.c 6.07 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   *  linux/fs/ufs/util.c
   *
   * Copyright (C) 1998
   * Daniel Pirkl <daniel.pirkl@email.cz>
   * Charles University, Faculty of Mathematics and Physics
   */
   
  #include <linux/string.h>
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/buffer_head.h>
e54205988   Mike Frysinger   drop linux/ufs_fs...
12
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
13
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  #include "swab.h"
  #include "util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
23
24
25
26
27
  struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
  	struct super_block *sb, u64 fragment, u64 size)
  {
  	struct ufs_buffer_head * ubh;
  	unsigned i, j ;
  	u64  count = 0;
  	if (size & ~uspi->s_fmask)
  		return NULL;
  	count = size >> uspi->s_fshift;
  	if (count > UFS_MAXFRAG)
  		return NULL;
  	ubh = (struct ufs_buffer_head *)
788257d61   Arnd Bergmann   ufs: remove the BKL
28
  		kmalloc (sizeof (struct ufs_buffer_head), GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  	if (!ubh)
  		return NULL;
  	ubh->fragment = fragment;
  	ubh->count = count;
  	for (i = 0; i < count; i++)
  		if (!(ubh->bh[i] = sb_bread(sb, fragment + i)))
  			goto failed;
  	for (; i < UFS_MAXFRAG; i++)
  		ubh->bh[i] = NULL;
  	return ubh;
  failed:
  	for (j = 0; j < i; j++)
  		brelse (ubh->bh[j]);
  	kfree(ubh);
  	return NULL;
  }
  
  struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
  	struct super_block *sb, u64 fragment, u64 size)
  {
  	unsigned i, j;
  	u64 count = 0;
  	if (size & ~uspi->s_fmask)
  		return NULL;
  	count = size >> uspi->s_fshift;
  	if (count <= 0 || count > UFS_MAXFRAG)
  		return NULL;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
56
57
  	USPI_UBH(uspi)->fragment = fragment;
  	USPI_UBH(uspi)->count = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	for (i = 0; i < count; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
59
  		if (!(USPI_UBH(uspi)->bh[i] = sb_bread(sb, fragment + i)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
  			goto failed;
  	for (; i < UFS_MAXFRAG; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
62
63
  		USPI_UBH(uspi)->bh[i] = NULL;
  	return USPI_UBH(uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
  failed:
  	for (j = 0; j < i; j++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
66
  		brelse (USPI_UBH(uspi)->bh[j]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  	return NULL;
  }
  
  void ubh_brelse (struct ufs_buffer_head * ubh)
  {
  	unsigned i;
  	if (!ubh)
  		return;
  	for (i = 0; i < ubh->count; i++)
  		brelse (ubh->bh[i]);
  	kfree (ubh);
  }
  
  void ubh_brelse_uspi (struct ufs_sb_private_info * uspi)
  {
  	unsigned i;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
83
  	if (!USPI_UBH(uspi))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  		return;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
85
86
87
  	for ( i = 0; i < USPI_UBH(uspi)->count; i++ ) {
  		brelse (USPI_UBH(uspi)->bh[i]);
  		USPI_UBH(uspi)->bh[i] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  	}
  }
  
  void ubh_mark_buffer_dirty (struct ufs_buffer_head * ubh)
  {
  	unsigned i;
  	if (!ubh)
  		return;
  	for ( i = 0; i < ubh->count; i++ )
  		mark_buffer_dirty (ubh->bh[i]);
  }
  
  void ubh_mark_buffer_uptodate (struct ufs_buffer_head * ubh, int flag)
  {
  	unsigned i;
  	if (!ubh)
  		return;
  	if (flag) {
  		for ( i = 0; i < ubh->count; i++ )
  			set_buffer_uptodate (ubh->bh[i]);
  	} else {
  		for ( i = 0; i < ubh->count; i++ )
  			clear_buffer_uptodate (ubh->bh[i]);
  	}
  }
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
113
  void ubh_sync_block(struct ufs_buffer_head *ubh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  {
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
115
116
  	if (ubh) {
  		unsigned i;
098d5af7b   Evgeniy Dushistov   [PATCH] ufs: ubh_...
117

9cb569d60   Christoph Hellwig   remove SWRITE* I/...
118
119
  		for (i = 0; i < ubh->count; i++)
  			write_dirty_buffer(ubh->bh[i], WRITE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120

9cb569d60   Christoph Hellwig   remove SWRITE* I/...
121
122
123
  		for (i = 0; i < ubh->count; i++)
  			wait_on_buffer(ubh->bh[i]);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  void ubh_bforget (struct ufs_buffer_head * ubh)
  {
  	unsigned i;
  	if (!ubh) 
  		return;
  	for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] ) 
  		bforget (ubh->bh[i]);
  }
   
  int ubh_buffer_dirty (struct ufs_buffer_head * ubh)
  {
  	unsigned i;
  	unsigned result = 0;
  	if (!ubh)
  		return 0;
  	for ( i = 0; i < ubh->count; i++ )
  		result |= buffer_dirty(ubh->bh[i]);
  	return result;
  }
  
  void _ubh_ubhcpymem_(struct ufs_sb_private_info * uspi, 
  	unsigned char * mem, struct ufs_buffer_head * ubh, unsigned size)
  {
  	unsigned len, bhno;
  	if (size > (ubh->count << uspi->s_fshift))
  		size = ubh->count << uspi->s_fshift;
  	bhno = 0;
  	while (size) {
  		len = min_t(unsigned int, size, uspi->s_fsize);
  		memcpy (mem, ubh->bh[bhno]->b_data, len);
  		mem += uspi->s_fsize;
  		size -= len;
  		bhno++;
  	}
  }
  
  void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi, 
  	struct ufs_buffer_head * ubh, unsigned char * mem, unsigned size)
  {
  	unsigned len, bhno;
  	if (size > (ubh->count << uspi->s_fshift))
  		size = ubh->count << uspi->s_fshift;
  	bhno = 0;
  	while (size) {
  		len = min_t(unsigned int, size, uspi->s_fsize);
  		memcpy (ubh->bh[bhno]->b_data, mem, len);
  		mem += uspi->s_fsize;
  		size -= len;
  		bhno++;
  	}
  }
  
  dev_t
  ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
  {
44aa5359b   Al Viro   [PATCH] ufs endia...
180
  	__u32 fs32;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
  	dev_t dev;
  
  	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
44aa5359b   Al Viro   [PATCH] ufs endia...
184
  		fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	else
44aa5359b   Al Viro   [PATCH] ufs endia...
186
  		fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[0]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
  	case UFS_ST_SUNx86:
  	case UFS_ST_SUN:
  		if ((fs32 & 0xffff0000) == 0 ||
  		    (fs32 & 0xffff0000) == 0xffff0000)
  			dev = old_decode_dev(fs32 & 0x7fff);
  		else
  			dev = MKDEV(sysv_major(fs32), sysv_minor(fs32));
  		break;
  
  	default:
  		dev = old_decode_dev(fs32);
  		break;
  	}
  	return dev;
  }
  
  void
  ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev)
  {
44aa5359b   Al Viro   [PATCH] ufs endia...
207
  	__u32 fs32;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  
  	switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
  	case UFS_ST_SUNx86:
  	case UFS_ST_SUN:
  		fs32 = sysv_encode_dev(dev);
  		if ((fs32 & 0xffff8000) == 0) {
  			fs32 = old_encode_dev(dev);
  		}
  		break;
  
  	default:
  		fs32 = old_encode_dev(dev);
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  	if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
44aa5359b   Al Viro   [PATCH] ufs endia...
223
  		ufsi->i_u1.i_data[1] = cpu_to_fs32(sb, fs32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  	else
44aa5359b   Al Viro   [PATCH] ufs endia...
225
  		ufsi->i_u1.i_data[0] = cpu_to_fs32(sb, fs32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  }
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  
  /**
   * ufs_get_locked_page() - locate, pin and lock a pagecache page, if not exist
   * read it from disk.
   * @mapping: the address_space to search
   * @index: the page index
   *
   * Locates the desired pagecache page, if not exist we'll read it,
   * locks it, increments its reference
   * count and returns its address.
   *
   */
  
  struct page *ufs_get_locked_page(struct address_space *mapping,
  				 pgoff_t index)
  {
  	struct page *page;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
244
245
  	page = find_lock_page(mapping, index);
  	if (!page) {
6fe6900e1   Nick Piggin   mm: make read_cac...
246
  		page = read_mapping_page(mapping, index, NULL);
1fb32b7bd   Evgeniy Dushistov   [PATCH] ufs: ufs_...
247

10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
248
249
  		if (IS_ERR(page)) {
  			printk(KERN_ERR "ufs_change_blocknr: "
6fe6900e1   Nick Piggin   mm: make read_cac...
250
251
  			       "read_mapping_page error: ino %lu, index: %lu
  ",
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
252
253
254
255
256
  			       mapping->host->i_ino, index);
  			goto out;
  		}
  
  		lock_page(page);
1fb32b7bd   Evgeniy Dushistov   [PATCH] ufs: ufs_...
257
258
259
260
  		if (unlikely(page->mapping == NULL)) {
  			/* Truncate got there first */
  			unlock_page(page);
  			page_cache_release(page);
06fa45d3a   Evgeniy Dushistov   [PATCH] ufs: hand...
261
262
  			page = NULL;
  			goto out;
1fb32b7bd   Evgeniy Dushistov   [PATCH] ufs: ufs_...
263
  		}
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
264
265
266
267
268
269
270
271
272
273
  		if (!PageUptodate(page) || PageError(page)) {
  			unlock_page(page);
  			page_cache_release(page);
  
  			printk(KERN_ERR "ufs_change_blocknr: "
  			       "can not read page: ino %lu, index: %lu
  ",
  			       mapping->host->i_ino, index);
  
  			page = ERR_PTR(-EIO);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
274
275
  		}
  	}
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
276
277
278
  out:
  	return page;
  }