]>
Commit | Line | Data |
---|---|---|
6a930a95 BS |
1 | From: Jeff Mahoney <jeffm@suse.com> |
2 | Subject: reiserfs: use generic readdir for operations across all xattrs | |
3 | ||
4 | The current reiserfs xattr implementation open codes reiserfs_readdir and | |
5 | frees the path before calling the filldir function. Typically, the filldir | |
6 | function is something that modifies the file system, such as a chown or | |
7 | an inode deletion that also require reading of an inode associated with each | |
8 | direntry. Since the file system is modified, the path retained becomes | |
9 | invalid for the next run. In addition, it runs backwards in attempt to | |
10 | minimize activity. | |
11 | ||
12 | This is clearly suboptimal from a code cleanliness perspective as well as | |
13 | performance-wise. | |
14 | ||
15 | This patch implements a generic reiserfs_for_each_xattr that uses the generic | |
16 | readdir and a specific filldir routine that simply populates an array of | |
17 | dentries and then performs a specific operation on them. When all files have | |
18 | been operated on, it then calls the operation on the directory itself. | |
19 | ||
20 | The result is a noticable code reduction and better performance. | |
21 | ||
22 | Signed-off-by: Jeff Mahoney <jeffm@suse.com> | |
23 | ||
24 | -- | |
25 | fs/reiserfs/dir.c | 28 +-- | |
26 | fs/reiserfs/xattr.c | 402 ++++++++++++-------------------------------- | |
27 | include/linux/reiserfs_fs.h | 1 | |
28 | 3 files changed, 131 insertions(+), 300 deletions(-) | |
29 | ||
30 | --- a/fs/reiserfs/dir.c | |
31 | +++ b/fs/reiserfs/dir.c | |
32 | @@ -41,10 +41,10 @@ static int reiserfs_dir_fsync(struct fil | |
33 | ||
34 | #define store_ih(where,what) copy_item_head (where, what) | |
35 | ||
36 | -// | |
37 | -static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |
38 | +int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, | |
39 | + filldir_t filldir, loff_t *pos) | |
40 | { | |
41 | - struct inode *inode = filp->f_path.dentry->d_inode; | |
42 | + struct inode *inode = dentry->d_inode; | |
43 | struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ | |
44 | INITIALIZE_PATH(path_to_entry); | |
45 | struct buffer_head *bh; | |
46 | @@ -64,13 +64,9 @@ static int reiserfs_readdir(struct file | |
47 | ||
48 | /* form key for search the next directory entry using f_pos field of | |
49 | file structure */ | |
50 | - make_cpu_key(&pos_key, inode, | |
51 | - (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY, | |
52 | - 3); | |
53 | + make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3); | |
54 | next_pos = cpu_key_k_offset(&pos_key); | |
55 | ||
56 | - /* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */ | |
57 | - | |
58 | path_to_entry.reada = PATH_READA; | |
59 | while (1) { | |
60 | research: | |
61 | @@ -144,7 +140,7 @@ static int reiserfs_readdir(struct file | |
62 | /* Ignore the .reiserfs_priv entry */ | |
63 | if (reiserfs_xattrs(inode->i_sb) && | |
64 | !old_format_only(inode->i_sb) && | |
65 | - filp->f_path.dentry == inode->i_sb->s_root && | |
66 | + dentry == inode->i_sb->s_root && | |
67 | REISERFS_SB(inode->i_sb)->priv_root && | |
68 | REISERFS_SB(inode->i_sb)->priv_root->d_inode | |
69 | && deh_objectid(deh) == | |
70 | @@ -156,7 +152,7 @@ static int reiserfs_readdir(struct file | |
71 | } | |
72 | ||
73 | d_off = deh_offset(deh); | |
74 | - filp->f_pos = d_off; | |
75 | + *pos = d_off; | |
76 | d_ino = deh_objectid(deh); | |
77 | if (d_reclen <= 32) { | |
78 | local_buf = small_buf; | |
79 | @@ -223,15 +219,21 @@ static int reiserfs_readdir(struct file | |
80 | ||
81 | } /* while */ | |
82 | ||
83 | - end: | |
84 | - filp->f_pos = next_pos; | |
85 | +end: | |
86 | + *pos = next_pos; | |
87 | pathrelse(&path_to_entry); | |
88 | reiserfs_check_path(&path_to_entry); | |
89 | - out: | |
90 | +out: | |
91 | reiserfs_write_unlock(inode->i_sb); | |
92 | return ret; | |
93 | } | |
94 | ||
95 | +static int reiserfs_readdir(struct file *file, void *dirent, filldir_t filldir) | |
96 | +{ | |
97 | + struct dentry *dentry = file->f_path.dentry; | |
98 | + return reiserfs_readdir_dentry(dentry, dirent, filldir, &file->f_pos); | |
99 | +} | |
100 | + | |
101 | /* compose directory item containing "." and ".." entries (entries are | |
102 | not aligned to 4 byte boundary) */ | |
103 | /* the last four params are LE */ | |
104 | --- a/fs/reiserfs/xattr.c | |
105 | +++ b/fs/reiserfs/xattr.c | |
106 | @@ -167,218 +167,65 @@ static struct dentry *open_xa_dir(const | |
107 | ||
108 | } | |
109 | ||
110 | -/* | |
111 | - * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but | |
112 | - * we need to drop the path before calling the filldir struct. That | |
113 | - * would be a big performance hit to the non-xattr case, so I've copied | |
114 | - * the whole thing for now. --clm | |
115 | - * | |
116 | - * the big difference is that I go backwards through the directory, | |
117 | - * and don't mess with f->f_pos, but the idea is the same. Do some | |
118 | - * action on each and every entry in the directory. | |
119 | - * | |
120 | - * we're called with i_mutex held, so there are no worries about the directory | |
121 | - * changing underneath us. | |
122 | - */ | |
123 | -static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir) | |
124 | -{ | |
125 | - struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ | |
126 | - INITIALIZE_PATH(path_to_entry); | |
127 | - struct buffer_head *bh; | |
128 | - int entry_num; | |
129 | - struct item_head *ih, tmp_ih; | |
130 | - int search_res; | |
131 | - char *local_buf; | |
132 | - loff_t next_pos; | |
133 | - char small_buf[32]; /* avoid kmalloc if we can */ | |
134 | - struct reiserfs_de_head *deh; | |
135 | - int d_reclen; | |
136 | - char *d_name; | |
137 | - off_t d_off; | |
138 | - ino_t d_ino; | |
139 | - struct reiserfs_dir_entry de; | |
140 | - | |
141 | - /* form key for search the next directory entry using f_pos field of | |
142 | - file structure */ | |
143 | - next_pos = max_reiserfs_offset(inode); | |
144 | - | |
145 | - while (1) { | |
146 | - research: | |
147 | - if (next_pos <= DOT_DOT_OFFSET) | |
148 | - break; | |
149 | - make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3); | |
150 | - | |
151 | - search_res = | |
152 | - search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, | |
153 | - &de); | |
154 | - if (search_res == IO_ERROR) { | |
155 | - // FIXME: we could just skip part of directory which could | |
156 | - // not be read | |
157 | - pathrelse(&path_to_entry); | |
158 | - return -EIO; | |
159 | - } | |
160 | - | |
161 | - if (search_res == NAME_NOT_FOUND) | |
162 | - de.de_entry_num--; | |
163 | - | |
164 | - set_de_name_and_namelen(&de); | |
165 | - entry_num = de.de_entry_num; | |
166 | - deh = &(de.de_deh[entry_num]); | |
167 | - | |
168 | - bh = de.de_bh; | |
169 | - ih = de.de_ih; | |
170 | - | |
171 | - if (!is_direntry_le_ih(ih)) { | |
172 | - reiserfs_error(inode->i_sb, "jdm-20000", | |
173 | - "not direntry %h", ih); | |
174 | - break; | |
175 | - } | |
176 | - copy_item_head(&tmp_ih, ih); | |
177 | - | |
178 | - /* we must have found item, that is item of this directory, */ | |
179 | - RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), | |
180 | - "vs-9000: found item %h does not match to dir we readdir %K", | |
181 | - ih, &pos_key); | |
182 | - | |
183 | - if (deh_offset(deh) <= DOT_DOT_OFFSET) { | |
184 | - break; | |
185 | - } | |
186 | - | |
187 | - /* look for the previous entry in the directory */ | |
188 | - next_pos = deh_offset(deh) - 1; | |
189 | - | |
190 | - if (!de_visible(deh)) | |
191 | - /* it is hidden entry */ | |
192 | - continue; | |
193 | - | |
194 | - d_reclen = entry_length(bh, ih, entry_num); | |
195 | - d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); | |
196 | - d_off = deh_offset(deh); | |
197 | - d_ino = deh_objectid(deh); | |
198 | - | |
199 | - if (!d_name[d_reclen - 1]) | |
200 | - d_reclen = strlen(d_name); | |
201 | - | |
202 | - if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) { | |
203 | - /* too big to send back to VFS */ | |
204 | - continue; | |
205 | - } | |
206 | - | |
207 | - /* Ignore the .reiserfs_priv entry */ | |
208 | - if (reiserfs_xattrs(inode->i_sb) && | |
209 | - !old_format_only(inode->i_sb) && | |
210 | - deh_objectid(deh) == | |
211 | - le32_to_cpu(INODE_PKEY | |
212 | - (REISERFS_SB(inode->i_sb)->priv_root->d_inode)-> | |
213 | - k_objectid)) | |
214 | - continue; | |
215 | - | |
216 | - if (d_reclen <= 32) { | |
217 | - local_buf = small_buf; | |
218 | - } else { | |
219 | - local_buf = kmalloc(d_reclen, GFP_NOFS); | |
220 | - if (!local_buf) { | |
221 | - pathrelse(&path_to_entry); | |
222 | - return -ENOMEM; | |
223 | - } | |
224 | - if (item_moved(&tmp_ih, &path_to_entry)) { | |
225 | - kfree(local_buf); | |
226 | - | |
227 | - /* sigh, must retry. Do this same offset again */ | |
228 | - next_pos = d_off; | |
229 | - goto research; | |
230 | - } | |
231 | - } | |
232 | - | |
233 | - // Note, that we copy name to user space via temporary | |
234 | - // buffer (local_buf) because filldir will block if | |
235 | - // user space buffer is swapped out. At that time | |
236 | - // entry can move to somewhere else | |
237 | - memcpy(local_buf, d_name, d_reclen); | |
238 | - | |
239 | - /* the filldir function might need to start transactions, | |
240 | - * or do who knows what. Release the path now that we've | |
241 | - * copied all the important stuff out of the deh | |
242 | - */ | |
243 | - pathrelse(&path_to_entry); | |
244 | - | |
245 | - if (filldir(dirent, local_buf, d_reclen, d_off, d_ino, | |
246 | - DT_UNKNOWN) < 0) { | |
247 | - if (local_buf != small_buf) { | |
248 | - kfree(local_buf); | |
249 | - } | |
250 | - goto end; | |
251 | - } | |
252 | - if (local_buf != small_buf) { | |
253 | - kfree(local_buf); | |
254 | - } | |
255 | - } /* while */ | |
256 | - | |
257 | - end: | |
258 | - pathrelse(&path_to_entry); | |
259 | - return 0; | |
260 | -} | |
261 | - | |
262 | -/* | |
263 | - * this could be done with dedicated readdir ops for the xattr files, | |
264 | - * but I want to get something working asap | |
265 | - * this is stolen from vfs_readdir | |
266 | - * | |
267 | - */ | |
268 | -static | |
269 | -int xattr_readdir(struct inode *inode, filldir_t filler, void *buf) | |
270 | -{ | |
271 | - int res = -ENOENT; | |
272 | - if (!IS_DEADDIR(inode)) { | |
273 | - lock_kernel(); | |
274 | - res = __xattr_readdir(inode, buf, filler); | |
275 | - unlock_kernel(); | |
276 | - } | |
277 | - return res; | |
278 | -} | |
279 | - | |
280 | /* The following are side effects of other operations that aren't explicitly | |
281 | * modifying extended attributes. This includes operations such as permissions | |
282 | * or ownership changes, object deletions, etc. */ | |
283 | +struct reiserfs_dentry_buf { | |
284 | + struct dentry *xadir; | |
285 | + int count; | |
286 | + struct dentry *dentries[8]; | |
287 | +}; | |
288 | ||
289 | static int | |
290 | -reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, | |
291 | - loff_t offset, u64 ino, unsigned int d_type) | |
292 | +fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset, | |
293 | + u64 ino, unsigned int d_type) | |
294 | { | |
295 | - struct dentry *xadir = (struct dentry *)buf; | |
296 | + struct reiserfs_dentry_buf *dbuf = buf; | |
297 | struct dentry *dentry; | |
298 | - int err = 0; | |
299 | ||
300 | - dentry = lookup_one_len(name, xadir, namelen); | |
301 | + if (dbuf->count == ARRAY_SIZE(dbuf->dentries)) | |
302 | + return -ENOSPC; | |
303 | + | |
304 | + if (name[0] == '.' && (name[1] == '\0' || | |
305 | + (name[1] == '.' && name[2] == '\0'))) | |
306 | + return 0; | |
307 | + | |
308 | + dentry = lookup_one_len(name, dbuf->xadir, namelen); | |
309 | if (IS_ERR(dentry)) { | |
310 | - err = PTR_ERR(dentry); | |
311 | - goto out; | |
312 | + return PTR_ERR(dentry); | |
313 | } else if (!dentry->d_inode) { | |
314 | - err = -ENODATA; | |
315 | - goto out_file; | |
316 | + /* A directory entry exists, but no file? */ | |
317 | + reiserfs_error(dentry->d_sb, "xattr-20003", | |
318 | + "Corrupted directory: xattr %s listed but " | |
319 | + "not found for file %s.\n", | |
320 | + dentry->d_name.name, dbuf->xadir->d_name.name); | |
321 | + dput(dentry); | |
322 | + return -EIO; | |
323 | } | |
324 | ||
325 | - /* Skip directories.. */ | |
326 | - if (S_ISDIR(dentry->d_inode->i_mode)) | |
327 | - goto out_file; | |
328 | - | |
329 | - err = xattr_unlink(xadir->d_inode, dentry); | |
330 | - | |
331 | -out_file: | |
332 | - dput(dentry); | |
333 | + dbuf->dentries[dbuf->count++] = dentry; | |
334 | + return 0; | |
335 | +} | |
336 | ||
337 | -out: | |
338 | - return err; | |
339 | +static void | |
340 | +cleanup_dentry_buf(struct reiserfs_dentry_buf *buf) | |
341 | +{ | |
342 | + int i; | |
343 | + for (i = 0; i < buf->count; i++) | |
344 | + if (buf->dentries[i]) | |
345 | + dput(buf->dentries[i]); | |
346 | } | |
347 | ||
348 | -/* This is called w/ inode->i_mutex downed */ | |
349 | -int reiserfs_delete_xattrs(struct inode *inode) | |
350 | +static int reiserfs_for_each_xattr(struct inode *inode, | |
351 | + int (*action)(struct dentry *, void *), | |
352 | + void *data) | |
353 | { | |
354 | - int err = -ENODATA; | |
355 | - struct dentry *dir, *root; | |
356 | - struct reiserfs_transaction_handle th; | |
357 | - int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + | |
358 | - 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); | |
359 | + struct dentry *dir; | |
360 | + int i, err = 0; | |
361 | + loff_t pos = 0; | |
362 | + struct reiserfs_dentry_buf buf = { | |
363 | + .count = 0, | |
364 | + }; | |
365 | ||
366 | /* Skip out, an xattr has no xattrs associated with it */ | |
367 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | |
368 | @@ -389,117 +236,97 @@ int reiserfs_delete_xattrs(struct inode | |
369 | err = PTR_ERR(dir); | |
370 | goto out; | |
371 | } else if (!dir->d_inode) { | |
372 | - dput(dir); | |
373 | - goto out; | |
374 | + err = 0; | |
375 | + goto out_dir; | |
376 | } | |
377 | ||
378 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | |
379 | - err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); | |
380 | - mutex_unlock(&dir->d_inode->i_mutex); | |
381 | - if (err) { | |
382 | - dput(dir); | |
383 | - goto out; | |
384 | + buf.xadir = dir; | |
385 | + err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); | |
386 | + while ((err == 0 || err == -ENOSPC) && buf.count) { | |
387 | + err = 0; | |
388 | + | |
389 | + for (i = 0; i < buf.count && buf.dentries[i]; i++) { | |
390 | + int lerr = 0; | |
391 | + struct dentry *dentry = buf.dentries[i]; | |
392 | + | |
393 | + if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode)) | |
394 | + lerr = action(dentry, data); | |
395 | + | |
396 | + dput(dentry); | |
397 | + buf.dentries[i] = NULL; | |
398 | + err = lerr ?: err; | |
399 | + } | |
400 | + buf.count = 0; | |
401 | + if (!err) | |
402 | + err = reiserfs_readdir_dentry(dir, &buf, | |
403 | + fill_with_dentries, &pos); | |
404 | } | |
405 | + mutex_unlock(&dir->d_inode->i_mutex); | |
406 | ||
407 | - root = dget(dir->d_parent); | |
408 | - dput(dir); | |
409 | + /* Clean up after a failed readdir */ | |
410 | + cleanup_dentry_buf(&buf); | |
411 | ||
412 | - /* We start a transaction here to avoid a ABBA situation | |
413 | - * between the xattr root's i_mutex and the journal lock. | |
414 | - * Inode creation will inherit an ACL, which requires a | |
415 | - * lookup. The lookup locks the xattr root i_mutex with a | |
416 | - * transaction open. Inode deletion takes teh xattr root | |
417 | - * i_mutex to delete the directory and then starts a | |
418 | - * transaction inside it. Boom. This doesn't incur much | |
419 | - * additional overhead since the reiserfs_rmdir transaction | |
420 | - * will just nest inside the outer transaction. */ | |
421 | - err = journal_begin(&th, inode->i_sb, blocks); | |
422 | if (!err) { | |
423 | - int jerror; | |
424 | - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); | |
425 | - err = xattr_rmdir(root->d_inode, dir); | |
426 | - jerror = journal_end(&th, inode->i_sb, blocks); | |
427 | - mutex_unlock(&root->d_inode->i_mutex); | |
428 | - err = jerror ?: err; | |
429 | + /* We start a transaction here to avoid a ABBA situation | |
430 | + * between the xattr root's i_mutex and the journal lock. | |
431 | + * This doesn't incur much additional overhead since the | |
432 | + * new transaction will just nest inside the | |
433 | + * outer transaction. */ | |
434 | + int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + | |
435 | + 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); | |
436 | + struct reiserfs_transaction_handle th; | |
437 | + err = journal_begin(&th, inode->i_sb, blocks); | |
438 | + if (!err) { | |
439 | + int jerror; | |
440 | + mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, | |
441 | + I_MUTEX_XATTR); | |
442 | + err = action(dir, data); | |
443 | + jerror = journal_end(&th, inode->i_sb, blocks); | |
444 | + mutex_unlock(&dir->d_parent->d_inode->i_mutex); | |
445 | + err = jerror ?: err; | |
446 | + } | |
447 | } | |
448 | - | |
449 | - dput(root); | |
450 | +out_dir: | |
451 | + dput(dir); | |
452 | out: | |
453 | - if (err) | |
454 | - reiserfs_warning(inode->i_sb, "jdm-20004", | |
455 | - "Couldn't remove all xattrs (%d)\n", err); | |
456 | + /* -ENODATA isn't an error */ | |
457 | + if (err == -ENODATA) | |
458 | + err = 0; | |
459 | return err; | |
460 | } | |
461 | ||
462 | -struct reiserfs_chown_buf { | |
463 | - struct inode *inode; | |
464 | - struct dentry *xadir; | |
465 | - struct iattr *attrs; | |
466 | -}; | |
467 | - | |
468 | -/* XXX: If there is a better way to do this, I'd love to hear about it */ | |
469 | -static int | |
470 | -reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen, | |
471 | - loff_t offset, u64 ino, unsigned int d_type) | |
472 | +static int delete_one_xattr(struct dentry *dentry, void *data) | |
473 | { | |
474 | - struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; | |
475 | - struct dentry *xafile, *xadir = chown_buf->xadir; | |
476 | - struct iattr *attrs = chown_buf->attrs; | |
477 | - int err = 0; | |
478 | + struct inode *dir = dentry->d_parent->d_inode; | |
479 | ||
480 | - xafile = lookup_one_len(name, xadir, namelen); | |
481 | - if (IS_ERR(xafile)) | |
482 | - return PTR_ERR(xafile); | |
483 | - else if (!xafile->d_inode) { | |
484 | - dput(xafile); | |
485 | - return -ENODATA; | |
486 | - } | |
487 | + /* This is the xattr dir, handle specially. */ | |
488 | + if (S_ISDIR(dentry->d_inode->i_mode)) | |
489 | + return xattr_rmdir(dir, dentry); | |
490 | ||
491 | - if (!S_ISDIR(xafile->d_inode->i_mode)) { | |
492 | - mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); | |
493 | - err = reiserfs_setattr(xafile, attrs); | |
494 | - mutex_unlock(&xafile->d_inode->i_mutex); | |
495 | - } | |
496 | - dput(xafile); | |
497 | + return xattr_unlink(dir, dentry); | |
498 | +} | |
499 | + | |
500 | +static int chown_one_xattr(struct dentry *dentry, void *data) | |
501 | +{ | |
502 | + struct iattr *attrs = data; | |
503 | + return reiserfs_setattr(dentry, attrs); | |
504 | +} | |
505 | ||
506 | +/* No i_mutex, but the inode is unconnected. */ | |
507 | +int reiserfs_delete_xattrs(struct inode *inode) | |
508 | +{ | |
509 | + int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL); | |
510 | + if (err) | |
511 | + reiserfs_warning(inode->i_sb, "jdm-20004", | |
512 | + "Couldn't delete all xattrs (%d)\n", err); | |
513 | return err; | |
514 | } | |
515 | ||
516 | +/* inode->i_mutex: down */ | |
517 | int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) | |
518 | { | |
519 | - struct dentry *dir; | |
520 | - int err = 0; | |
521 | - struct reiserfs_chown_buf buf; | |
522 | - unsigned int ia_valid = attrs->ia_valid; | |
523 | - | |
524 | - /* Skip out, an xattr has no xattrs associated with it */ | |
525 | - if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) | |
526 | - return 0; | |
527 | - | |
528 | - dir = open_xa_dir(inode, XATTR_REPLACE); | |
529 | - if (IS_ERR(dir)) { | |
530 | - if (PTR_ERR(dir) != -ENODATA) | |
531 | - err = PTR_ERR(dir); | |
532 | - goto out; | |
533 | - } else if (!dir->d_inode) | |
534 | - goto out_dir; | |
535 | - | |
536 | - attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME); | |
537 | - buf.xadir = dir; | |
538 | - buf.attrs = attrs; | |
539 | - buf.inode = inode; | |
540 | - | |
541 | - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | |
542 | - err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf); | |
543 | - | |
544 | - if (!err) | |
545 | - err = reiserfs_setattr(dir, attrs); | |
546 | - mutex_unlock(&dir->d_inode->i_mutex); | |
547 | - | |
548 | - attrs->ia_valid = ia_valid; | |
549 | -out_dir: | |
550 | - dput(dir); | |
551 | -out: | |
552 | + int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs); | |
553 | if (err) | |
554 | reiserfs_warning(inode->i_sb, "jdm-20007", | |
555 | "Couldn't chown all xattrs (%d)\n", err); | |
556 | @@ -1004,6 +831,7 @@ ssize_t reiserfs_listxattr(struct dentry | |
557 | { | |
558 | struct dentry *dir; | |
559 | int err = 0; | |
560 | + loff_t pos = 0; | |
561 | struct listxattr_buf buf = { | |
562 | .inode = dentry->d_inode, | |
563 | .buf = buffer, | |
564 | @@ -1026,7 +854,7 @@ ssize_t reiserfs_listxattr(struct dentry | |
565 | } | |
566 | ||
567 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); | |
568 | - err = xattr_readdir(dir->d_inode, listxattr_filler, &buf); | |
569 | + err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos); | |
570 | mutex_unlock(&dir->d_inode->i_mutex); | |
571 | ||
572 | if (!err) | |
573 | --- a/include/linux/reiserfs_fs.h | |
574 | +++ b/include/linux/reiserfs_fs.h | |
575 | @@ -1984,6 +1984,7 @@ extern const struct inode_operations rei | |
576 | extern const struct inode_operations reiserfs_symlink_inode_operations; | |
577 | extern const struct inode_operations reiserfs_special_inode_operations; | |
578 | extern const struct file_operations reiserfs_dir_operations; | |
579 | +int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *); | |
580 | ||
581 | /* tail_conversion.c */ | |
582 | int direct2indirect(struct reiserfs_transaction_handle *, struct inode *, |