]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.suse/reiserfs-kill-xattr-readdir.diff
Add a patch to fix Intel E100 wake-on-lan problems.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / reiserfs-kill-xattr-readdir.diff
CommitLineData
6a930a95
BS
1From: Jeff Mahoney <jeffm@suse.com>
2Subject: 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
22Signed-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 *,