diff options
-rw-r--r-- | fs/gfs2/ops_file.c | 187 |
1 files changed, 9 insertions, 178 deletions
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index 80f3ff0bba7b..372dbcb3f7f3 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -43,27 +43,6 @@ | |||
43 | #include "util.h" | 43 | #include "util.h" |
44 | #include "eaops.h" | 44 | #include "eaops.h" |
45 | 45 | ||
46 | /* "bad" is for NFS support */ | ||
47 | struct filldir_bad_entry { | ||
48 | char *fbe_name; | ||
49 | unsigned int fbe_length; | ||
50 | u64 fbe_offset; | ||
51 | struct gfs2_inum fbe_inum; | ||
52 | unsigned int fbe_type; | ||
53 | }; | ||
54 | |||
55 | struct filldir_bad { | ||
56 | struct gfs2_sbd *fdb_sbd; | ||
57 | |||
58 | struct filldir_bad_entry *fdb_entry; | ||
59 | unsigned int fdb_entry_num; | ||
60 | unsigned int fdb_entry_off; | ||
61 | |||
62 | char *fdb_name; | ||
63 | unsigned int fdb_name_size; | ||
64 | unsigned int fdb_name_off; | ||
65 | }; | ||
66 | |||
67 | /* For regular, non-NFS */ | 46 | /* For regular, non-NFS */ |
68 | struct filldir_reg { | 47 | struct filldir_reg { |
69 | struct gfs2_sbd *fdr_sbd; | 48 | struct gfs2_sbd *fdr_sbd; |
@@ -149,7 +128,7 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) | |||
149 | } | 128 | } |
150 | 129 | ||
151 | /** | 130 | /** |
152 | * filldir_reg_func - Report a directory entry to the caller of gfs2_dir_read() | 131 | * filldir_func - Report a directory entry to the caller of gfs2_dir_read() |
153 | * @opaque: opaque data used by the function | 132 | * @opaque: opaque data used by the function |
154 | * @name: the name of the directory entry | 133 | * @name: the name of the directory entry |
155 | * @length: the length of the name | 134 | * @length: the length of the name |
@@ -160,9 +139,9 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) | |||
160 | * Returns: 0 on success, 1 if buffer full | 139 | * Returns: 0 on success, 1 if buffer full |
161 | */ | 140 | */ |
162 | 141 | ||
163 | static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | 142 | static int filldir_func(void *opaque, const char *name, unsigned int length, |
164 | u64 offset, struct gfs2_inum *inum, | 143 | u64 offset, struct gfs2_inum *inum, |
165 | unsigned int type) | 144 | unsigned int type) |
166 | { | 145 | { |
167 | struct filldir_reg *fdr = (struct filldir_reg *)opaque; | 146 | struct filldir_reg *fdr = (struct filldir_reg *)opaque; |
168 | struct gfs2_sbd *sdp = fdr->fdr_sbd; | 147 | struct gfs2_sbd *sdp = fdr->fdr_sbd; |
@@ -174,11 +153,9 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | |||
174 | return 1; | 153 | return 1; |
175 | 154 | ||
176 | if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { | 155 | if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) { |
177 | gfs2_glock_prefetch_num(sdp, | 156 | gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops, |
178 | inum->no_addr, &gfs2_inode_glops, | ||
179 | LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); | 157 | LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); |
180 | gfs2_glock_prefetch_num(sdp, | 158 | gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops, |
181 | inum->no_addr, &gfs2_iopen_glops, | ||
182 | LM_ST_SHARED, LM_FLAG_TRY); | 159 | LM_ST_SHARED, LM_FLAG_TRY); |
183 | } | 160 | } |
184 | 161 | ||
@@ -186,7 +163,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | |||
186 | } | 163 | } |
187 | 164 | ||
188 | /** | 165 | /** |
189 | * readdir_reg - Read directory entries from a directory | 166 | * gfs2_readdir - Read directory entries from a directory |
190 | * @file: The directory to read from | 167 | * @file: The directory to read from |
191 | * @dirent: Buffer for dirents | 168 | * @dirent: Buffer for dirents |
192 | * @filldir: Function used to do the copying | 169 | * @filldir: Function used to do the copying |
@@ -194,7 +171,7 @@ static int filldir_reg_func(void *opaque, const char *name, unsigned int length, | |||
194 | * Returns: errno | 171 | * Returns: errno |
195 | */ | 172 | */ |
196 | 173 | ||
197 | static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) | 174 | static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) |
198 | { | 175 | { |
199 | struct inode *dir = file->f_mapping->host; | 176 | struct inode *dir = file->f_mapping->host; |
200 | struct gfs2_inode *dip = GFS2_I(dir); | 177 | struct gfs2_inode *dip = GFS2_I(dir); |
@@ -215,7 +192,7 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) | |||
215 | return error; | 192 | return error; |
216 | } | 193 | } |
217 | 194 | ||
218 | error = gfs2_dir_read(dir, &offset, &fdr, filldir_reg_func); | 195 | error = gfs2_dir_read(dir, &offset, &fdr, filldir_func); |
219 | 196 | ||
220 | gfs2_glock_dq_uninit(&d_gh); | 197 | gfs2_glock_dq_uninit(&d_gh); |
221 | 198 | ||
@@ -224,152 +201,6 @@ static int readdir_reg(struct file *file, void *dirent, filldir_t filldir) | |||
224 | return error; | 201 | return error; |
225 | } | 202 | } |
226 | 203 | ||
227 | /** | ||
228 | * filldir_bad_func - Report a directory entry to the caller of gfs2_dir_read() | ||
229 | * @opaque: opaque data used by the function | ||
230 | * @name: the name of the directory entry | ||
231 | * @length: the length of the name | ||
232 | * @offset: the entry's offset in the directory | ||
233 | * @inum: the inode number the entry points to | ||
234 | * @type: the type of inode the entry points to | ||
235 | * | ||
236 | * For supporting NFS. | ||
237 | * | ||
238 | * Returns: 0 on success, 1 if buffer full | ||
239 | */ | ||
240 | |||
241 | static int filldir_bad_func(void *opaque, const char *name, unsigned int length, | ||
242 | u64 offset, struct gfs2_inum *inum, | ||
243 | unsigned int type) | ||
244 | { | ||
245 | struct filldir_bad *fdb = (struct filldir_bad *)opaque; | ||
246 | struct gfs2_sbd *sdp = fdb->fdb_sbd; | ||
247 | struct filldir_bad_entry *fbe; | ||
248 | |||
249 | if (fdb->fdb_entry_off == fdb->fdb_entry_num || | ||
250 | fdb->fdb_name_off + length > fdb->fdb_name_size) | ||
251 | return 1; | ||
252 | |||
253 | fbe = &fdb->fdb_entry[fdb->fdb_entry_off]; | ||
254 | fbe->fbe_name = fdb->fdb_name + fdb->fdb_name_off; | ||
255 | memcpy(fbe->fbe_name, name, length); | ||
256 | fbe->fbe_length = length; | ||
257 | fbe->fbe_offset = offset; | ||
258 | fbe->fbe_inum = *inum; | ||
259 | fbe->fbe_type = type; | ||
260 | |||
261 | fdb->fdb_entry_off++; | ||
262 | fdb->fdb_name_off += length; | ||
263 | |||
264 | if (!(length == 1 && *name == '.')) { | ||
265 | gfs2_glock_prefetch_num(sdp, | ||
266 | inum->no_addr, &gfs2_inode_glops, | ||
267 | LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY); | ||
268 | gfs2_glock_prefetch_num(sdp, | ||
269 | inum->no_addr, &gfs2_iopen_glops, | ||
270 | LM_ST_SHARED, LM_FLAG_TRY); | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * readdir_bad - Read directory entries from a directory | ||
278 | * @file: The directory to read from | ||
279 | * @dirent: Buffer for dirents | ||
280 | * @filldir: Function used to do the copying | ||
281 | * | ||
282 | * For supporting NFS. | ||
283 | * | ||
284 | * Returns: errno | ||
285 | */ | ||
286 | |||
287 | static int readdir_bad(struct file *file, void *dirent, filldir_t filldir) | ||
288 | { | ||
289 | struct inode *dir = file->f_mapping->host; | ||
290 | struct gfs2_inode *dip = GFS2_I(dir); | ||
291 | struct gfs2_sbd *sdp = GFS2_SB(dir); | ||
292 | struct filldir_reg fdr; | ||
293 | unsigned int entries, size; | ||
294 | struct filldir_bad *fdb; | ||
295 | struct gfs2_holder d_gh; | ||
296 | u64 offset = file->f_pos; | ||
297 | unsigned int x; | ||
298 | struct filldir_bad_entry *fbe; | ||
299 | int error; | ||
300 | |||
301 | entries = gfs2_tune_get(sdp, gt_entries_per_readdir); | ||
302 | size = sizeof(struct filldir_bad) + | ||
303 | entries * (sizeof(struct filldir_bad_entry) + GFS2_FAST_NAME_SIZE); | ||
304 | |||
305 | fdb = kzalloc(size, GFP_KERNEL); | ||
306 | if (!fdb) | ||
307 | return -ENOMEM; | ||
308 | |||
309 | fdb->fdb_sbd = sdp; | ||
310 | fdb->fdb_entry = (struct filldir_bad_entry *)(fdb + 1); | ||
311 | fdb->fdb_entry_num = entries; | ||
312 | fdb->fdb_name = ((char *)fdb) + sizeof(struct filldir_bad) + | ||
313 | entries * sizeof(struct filldir_bad_entry); | ||
314 | fdb->fdb_name_size = entries * GFS2_FAST_NAME_SIZE; | ||
315 | |||
316 | gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh); | ||
317 | error = gfs2_glock_nq_atime(&d_gh); | ||
318 | if (error) { | ||
319 | gfs2_holder_uninit(&d_gh); | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | error = gfs2_dir_read(dir, &offset, fdb, filldir_bad_func); | ||
324 | |||
325 | gfs2_glock_dq_uninit(&d_gh); | ||
326 | |||
327 | fdr.fdr_sbd = sdp; | ||
328 | fdr.fdr_prefetch = 0; | ||
329 | fdr.fdr_filldir = filldir; | ||
330 | fdr.fdr_opaque = dirent; | ||
331 | |||
332 | for (x = 0; x < fdb->fdb_entry_off; x++) { | ||
333 | fbe = &fdb->fdb_entry[x]; | ||
334 | |||
335 | error = filldir_reg_func(&fdr, | ||
336 | fbe->fbe_name, fbe->fbe_length, | ||
337 | fbe->fbe_offset, | ||
338 | &fbe->fbe_inum, fbe->fbe_type); | ||
339 | if (error) { | ||
340 | file->f_pos = fbe->fbe_offset; | ||
341 | error = 0; | ||
342 | goto out; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | file->f_pos = offset; | ||
347 | |||
348 | out: | ||
349 | kfree(fdb); | ||
350 | return error; | ||
351 | } | ||
352 | |||
353 | /** | ||
354 | * gfs2_readdir - Read directory entries from a directory | ||
355 | * @file: The directory to read from | ||
356 | * @dirent: Buffer for dirents | ||
357 | * @filldir: Function used to do the copying | ||
358 | * | ||
359 | * Returns: errno | ||
360 | */ | ||
361 | |||
362 | static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) | ||
363 | { | ||
364 | int error; | ||
365 | |||
366 | if (strcmp(current->comm, "nfsd") != 0) | ||
367 | error = readdir_reg(file, dirent, filldir); | ||
368 | else | ||
369 | error = readdir_bad(file, dirent, filldir); | ||
370 | |||
371 | return error; | ||
372 | } | ||
373 | 204 | ||
374 | static const u32 iflags_to_gfs2[32] = { | 205 | static const u32 iflags_to_gfs2[32] = { |
375 | [iflag_Sync] = GFS2_DIF_SYNC, | 206 | [iflag_Sync] = GFS2_DIF_SYNC, |