Commit a41f1a4715f26f7bc4d047d0bc7710145c8e69c7

Authored by Jeff Mahoney
Committed by Linus Torvalds
1 parent 0ab2621ebd

reiserfs: use generic readdir for operations across all xattrs

The current reiserfs xattr implementation open codes reiserfs_readdir
and frees the path before calling the filldir function.  Typically, the
filldir function is something that modifies the file system, such as a
chown or an inode deletion that also require reading of an inode
associated with each direntry.  Since the file system is modified, the
path retained becomes invalid for the next run.  In addition, it runs
backwards in attempt to minimize activity.

This is clearly suboptimal from a code cleanliness perspective as well
as performance-wise.

This patch implements a generic reiserfs_for_each_xattr that uses the
generic readdir and a specific filldir routine that simply populates an
array of dentries and then performs a specific operation on them.  When
all files have been operated on, it then calls the operation on the
directory itself.

The result is a noticable code reduction and better performance.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 131 additions and 300 deletions Side-by-side Diff

... ... @@ -41,10 +41,10 @@
41 41  
42 42 #define store_ih(where,what) copy_item_head (where, what)
43 43  
44   -//
45   -static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  44 +int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent,
  45 + filldir_t filldir, loff_t *pos)
46 46 {
47   - struct inode *inode = filp->f_path.dentry->d_inode;
  47 + struct inode *inode = dentry->d_inode;
48 48 struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
49 49 INITIALIZE_PATH(path_to_entry);
50 50 struct buffer_head *bh;
51 51  
... ... @@ -64,13 +64,9 @@
64 64  
65 65 /* form key for search the next directory entry using f_pos field of
66 66 file structure */
67   - make_cpu_key(&pos_key, inode,
68   - (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY,
69   - 3);
  67 + make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3);
70 68 next_pos = cpu_key_k_offset(&pos_key);
71 69  
72   - /* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */
73   -
74 70 path_to_entry.reada = PATH_READA;
75 71 while (1) {
76 72 research:
... ... @@ -144,7 +140,7 @@
144 140 /* Ignore the .reiserfs_priv entry */
145 141 if (reiserfs_xattrs(inode->i_sb) &&
146 142 !old_format_only(inode->i_sb) &&
147   - filp->f_path.dentry == inode->i_sb->s_root &&
  143 + dentry == inode->i_sb->s_root &&
148 144 REISERFS_SB(inode->i_sb)->priv_root &&
149 145 REISERFS_SB(inode->i_sb)->priv_root->d_inode
150 146 && deh_objectid(deh) ==
... ... @@ -156,7 +152,7 @@
156 152 }
157 153  
158 154 d_off = deh_offset(deh);
159   - filp->f_pos = d_off;
  155 + *pos = d_off;
160 156 d_ino = deh_objectid(deh);
161 157 if (d_reclen <= 32) {
162 158 local_buf = small_buf;
163 159  
164 160  
... ... @@ -223,13 +219,19 @@
223 219  
224 220 } /* while */
225 221  
226   - end:
227   - filp->f_pos = next_pos;
  222 +end:
  223 + *pos = next_pos;
228 224 pathrelse(&path_to_entry);
229 225 reiserfs_check_path(&path_to_entry);
230   - out:
  226 +out:
231 227 reiserfs_write_unlock(inode->i_sb);
232 228 return ret;
  229 +}
  230 +
  231 +static int reiserfs_readdir(struct file *file, void *dirent, filldir_t filldir)
  232 +{
  233 + struct dentry *dentry = file->f_path.dentry;
  234 + return reiserfs_readdir_dentry(dentry, dirent, filldir, &file->f_pos);
233 235 }
234 236  
235 237 /* compose directory item containing "." and ".." entries (entries are
... ... @@ -167,218 +167,65 @@
167 167  
168 168 }
169 169  
170   -/*
171   - * this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
172   - * we need to drop the path before calling the filldir struct. That
173   - * would be a big performance hit to the non-xattr case, so I've copied
174   - * the whole thing for now. --clm
175   - *
176   - * the big difference is that I go backwards through the directory,
177   - * and don't mess with f->f_pos, but the idea is the same. Do some
178   - * action on each and every entry in the directory.
179   - *
180   - * we're called with i_mutex held, so there are no worries about the directory
181   - * changing underneath us.
182   - */
183   -static int __xattr_readdir(struct inode *inode, void *dirent, filldir_t filldir)
184   -{
185   - struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
186   - INITIALIZE_PATH(path_to_entry);
187   - struct buffer_head *bh;
188   - int entry_num;
189   - struct item_head *ih, tmp_ih;
190   - int search_res;
191   - char *local_buf;
192   - loff_t next_pos;
193   - char small_buf[32]; /* avoid kmalloc if we can */
194   - struct reiserfs_de_head *deh;
195   - int d_reclen;
196   - char *d_name;
197   - off_t d_off;
198   - ino_t d_ino;
199   - struct reiserfs_dir_entry de;
200   -
201   - /* form key for search the next directory entry using f_pos field of
202   - file structure */
203   - next_pos = max_reiserfs_offset(inode);
204   -
205   - while (1) {
206   - research:
207   - if (next_pos <= DOT_DOT_OFFSET)
208   - break;
209   - make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);
210   -
211   - search_res =
212   - search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
213   - &de);
214   - if (search_res == IO_ERROR) {
215   - // FIXME: we could just skip part of directory which could
216   - // not be read
217   - pathrelse(&path_to_entry);
218   - return -EIO;
219   - }
220   -
221   - if (search_res == NAME_NOT_FOUND)
222   - de.de_entry_num--;
223   -
224   - set_de_name_and_namelen(&de);
225   - entry_num = de.de_entry_num;
226   - deh = &(de.de_deh[entry_num]);
227   -
228   - bh = de.de_bh;
229   - ih = de.de_ih;
230   -
231   - if (!is_direntry_le_ih(ih)) {
232   - reiserfs_error(inode->i_sb, "jdm-20000",
233   - "not direntry %h", ih);
234   - break;
235   - }
236   - copy_item_head(&tmp_ih, ih);
237   -
238   - /* we must have found item, that is item of this directory, */
239   - RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
240   - "vs-9000: found item %h does not match to dir we readdir %K",
241   - ih, &pos_key);
242   -
243   - if (deh_offset(deh) <= DOT_DOT_OFFSET) {
244   - break;
245   - }
246   -
247   - /* look for the previous entry in the directory */
248   - next_pos = deh_offset(deh) - 1;
249   -
250   - if (!de_visible(deh))
251   - /* it is hidden entry */
252   - continue;
253   -
254   - d_reclen = entry_length(bh, ih, entry_num);
255   - d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
256   - d_off = deh_offset(deh);
257   - d_ino = deh_objectid(deh);
258   -
259   - if (!d_name[d_reclen - 1])
260   - d_reclen = strlen(d_name);
261   -
262   - if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) {
263   - /* too big to send back to VFS */
264   - continue;
265   - }
266   -
267   - /* Ignore the .reiserfs_priv entry */
268   - if (reiserfs_xattrs(inode->i_sb) &&
269   - !old_format_only(inode->i_sb) &&
270   - deh_objectid(deh) ==
271   - le32_to_cpu(INODE_PKEY
272   - (REISERFS_SB(inode->i_sb)->priv_root->d_inode)->
273   - k_objectid))
274   - continue;
275   -
276   - if (d_reclen <= 32) {
277   - local_buf = small_buf;
278   - } else {
279   - local_buf = kmalloc(d_reclen, GFP_NOFS);
280   - if (!local_buf) {
281   - pathrelse(&path_to_entry);
282   - return -ENOMEM;
283   - }
284   - if (item_moved(&tmp_ih, &path_to_entry)) {
285   - kfree(local_buf);
286   -
287   - /* sigh, must retry. Do this same offset again */
288   - next_pos = d_off;
289   - goto research;
290   - }
291   - }
292   -
293   - // Note, that we copy name to user space via temporary
294   - // buffer (local_buf) because filldir will block if
295   - // user space buffer is swapped out. At that time
296   - // entry can move to somewhere else
297   - memcpy(local_buf, d_name, d_reclen);
298   -
299   - /* the filldir function might need to start transactions,
300   - * or do who knows what. Release the path now that we've
301   - * copied all the important stuff out of the deh
302   - */
303   - pathrelse(&path_to_entry);
304   -
305   - if (filldir(dirent, local_buf, d_reclen, d_off, d_ino,
306   - DT_UNKNOWN) < 0) {
307   - if (local_buf != small_buf) {
308   - kfree(local_buf);
309   - }
310   - goto end;
311   - }
312   - if (local_buf != small_buf) {
313   - kfree(local_buf);
314   - }
315   - } /* while */
316   -
317   - end:
318   - pathrelse(&path_to_entry);
319   - return 0;
320   -}
321   -
322   -/*
323   - * this could be done with dedicated readdir ops for the xattr files,
324   - * but I want to get something working asap
325   - * this is stolen from vfs_readdir
326   - *
327   - */
328   -static
329   -int xattr_readdir(struct inode *inode, filldir_t filler, void *buf)
330   -{
331   - int res = -ENOENT;
332   - if (!IS_DEADDIR(inode)) {
333   - lock_kernel();
334   - res = __xattr_readdir(inode, buf, filler);
335   - unlock_kernel();
336   - }
337   - return res;
338   -}
339   -
340 170 /* The following are side effects of other operations that aren't explicitly
341 171 * modifying extended attributes. This includes operations such as permissions
342 172 * or ownership changes, object deletions, etc. */
  173 +struct reiserfs_dentry_buf {
  174 + struct dentry *xadir;
  175 + int count;
  176 + struct dentry *dentries[8];
  177 +};
343 178  
344 179 static int
345   -reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
346   - loff_t offset, u64 ino, unsigned int d_type)
  180 +fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
  181 + u64 ino, unsigned int d_type)
347 182 {
348   - struct dentry *xadir = (struct dentry *)buf;
  183 + struct reiserfs_dentry_buf *dbuf = buf;
349 184 struct dentry *dentry;
350   - int err = 0;
351 185  
352   - dentry = lookup_one_len(name, xadir, namelen);
  186 + if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
  187 + return -ENOSPC;
  188 +
  189 + if (name[0] == '.' && (name[1] == '\0' ||
  190 + (name[1] == '.' && name[2] == '\0')))
  191 + return 0;
  192 +
  193 + dentry = lookup_one_len(name, dbuf->xadir, namelen);
353 194 if (IS_ERR(dentry)) {
354   - err = PTR_ERR(dentry);
355   - goto out;
  195 + return PTR_ERR(dentry);
356 196 } else if (!dentry->d_inode) {
357   - err = -ENODATA;
358   - goto out_file;
  197 + /* A directory entry exists, but no file? */
  198 + reiserfs_error(dentry->d_sb, "xattr-20003",
  199 + "Corrupted directory: xattr %s listed but "
  200 + "not found for file %s.\n",
  201 + dentry->d_name.name, dbuf->xadir->d_name.name);
  202 + dput(dentry);
  203 + return -EIO;
359 204 }
360 205  
361   - /* Skip directories.. */
362   - if (S_ISDIR(dentry->d_inode->i_mode))
363   - goto out_file;
  206 + dbuf->dentries[dbuf->count++] = dentry;
  207 + return 0;
  208 +}
364 209  
365   - err = xattr_unlink(xadir->d_inode, dentry);
366   -
367   -out_file:
368   - dput(dentry);
369   -
370   -out:
371   - return err;
  210 +static void
  211 +cleanup_dentry_buf(struct reiserfs_dentry_buf *buf)
  212 +{
  213 + int i;
  214 + for (i = 0; i < buf->count; i++)
  215 + if (buf->dentries[i])
  216 + dput(buf->dentries[i]);
372 217 }
373 218  
374   -/* This is called w/ inode->i_mutex downed */
375   -int reiserfs_delete_xattrs(struct inode *inode)
  219 +static int reiserfs_for_each_xattr(struct inode *inode,
  220 + int (*action)(struct dentry *, void *),
  221 + void *data)
376 222 {
377   - int err = -ENODATA;
378   - struct dentry *dir, *root;
379   - struct reiserfs_transaction_handle th;
380   - int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 +
381   - 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
  223 + struct dentry *dir;
  224 + int i, err = 0;
  225 + loff_t pos = 0;
  226 + struct reiserfs_dentry_buf buf = {
  227 + .count = 0,
  228 + };
382 229  
383 230 /* Skip out, an xattr has no xattrs associated with it */
384 231 if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
385 232  
386 233  
387 234  
388 235  
389 236  
390 237  
391 238  
392 239  
393 240  
394 241  
395 242  
396 243  
397 244  
398 245  
... ... @@ -389,117 +236,97 @@
389 236 err = PTR_ERR(dir);
390 237 goto out;
391 238 } else if (!dir->d_inode) {
392   - dput(dir);
393   - goto out;
  239 + err = 0;
  240 + goto out_dir;
394 241 }
395 242  
396 243 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
397   - err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir);
398   - mutex_unlock(&dir->d_inode->i_mutex);
399   - if (err) {
400   - dput(dir);
401   - goto out;
  244 + buf.xadir = dir;
  245 + err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
  246 + while ((err == 0 || err == -ENOSPC) && buf.count) {
  247 + err = 0;
  248 +
  249 + for (i = 0; i < buf.count && buf.dentries[i]; i++) {
  250 + int lerr = 0;
  251 + struct dentry *dentry = buf.dentries[i];
  252 +
  253 + if (err == 0 && !S_ISDIR(dentry->d_inode->i_mode))
  254 + lerr = action(dentry, data);
  255 +
  256 + dput(dentry);
  257 + buf.dentries[i] = NULL;
  258 + err = lerr ?: err;
  259 + }
  260 + buf.count = 0;
  261 + if (!err)
  262 + err = reiserfs_readdir_dentry(dir, &buf,
  263 + fill_with_dentries, &pos);
402 264 }
  265 + mutex_unlock(&dir->d_inode->i_mutex);
403 266  
404   - root = dget(dir->d_parent);
405   - dput(dir);
  267 + /* Clean up after a failed readdir */
  268 + cleanup_dentry_buf(&buf);
406 269  
407   - /* We start a transaction here to avoid a ABBA situation
408   - * between the xattr root's i_mutex and the journal lock.
409   - * Inode creation will inherit an ACL, which requires a
410   - * lookup. The lookup locks the xattr root i_mutex with a
411   - * transaction open. Inode deletion takes teh xattr root
412   - * i_mutex to delete the directory and then starts a
413   - * transaction inside it. Boom. This doesn't incur much
414   - * additional overhead since the reiserfs_rmdir transaction
415   - * will just nest inside the outer transaction. */
416   - err = journal_begin(&th, inode->i_sb, blocks);
417 270 if (!err) {
418   - int jerror;
419   - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR);
420   - err = xattr_rmdir(root->d_inode, dir);
421   - jerror = journal_end(&th, inode->i_sb, blocks);
422   - mutex_unlock(&root->d_inode->i_mutex);
423   - err = jerror ?: err;
  271 + /* We start a transaction here to avoid a ABBA situation
  272 + * between the xattr root's i_mutex and the journal lock.
  273 + * This doesn't incur much additional overhead since the
  274 + * new transaction will just nest inside the
  275 + * outer transaction. */
  276 + int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 +
  277 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
  278 + struct reiserfs_transaction_handle th;
  279 + err = journal_begin(&th, inode->i_sb, blocks);
  280 + if (!err) {
  281 + int jerror;
  282 + mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
  283 + I_MUTEX_XATTR);
  284 + err = action(dir, data);
  285 + jerror = journal_end(&th, inode->i_sb, blocks);
  286 + mutex_unlock(&dir->d_parent->d_inode->i_mutex);
  287 + err = jerror ?: err;
  288 + }
424 289 }
425   -
426   - dput(root);
  290 +out_dir:
  291 + dput(dir);
427 292 out:
428   - if (err)
429   - reiserfs_warning(inode->i_sb, "jdm-20004",
430   - "Couldn't remove all xattrs (%d)\n", err);
  293 + /* -ENODATA isn't an error */
  294 + if (err == -ENODATA)
  295 + err = 0;
431 296 return err;
432 297 }
433 298  
434   -struct reiserfs_chown_buf {
435   - struct inode *inode;
436   - struct dentry *xadir;
437   - struct iattr *attrs;
438   -};
439   -
440   -/* XXX: If there is a better way to do this, I'd love to hear about it */
441   -static int
442   -reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
443   - loff_t offset, u64 ino, unsigned int d_type)
  299 +static int delete_one_xattr(struct dentry *dentry, void *data)
444 300 {
445   - struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
446   - struct dentry *xafile, *xadir = chown_buf->xadir;
447   - struct iattr *attrs = chown_buf->attrs;
448   - int err = 0;
  301 + struct inode *dir = dentry->d_parent->d_inode;
449 302  
450   - xafile = lookup_one_len(name, xadir, namelen);
451   - if (IS_ERR(xafile))
452   - return PTR_ERR(xafile);
453   - else if (!xafile->d_inode) {
454   - dput(xafile);
455   - return -ENODATA;
456   - }
  303 + /* This is the xattr dir, handle specially. */
  304 + if (S_ISDIR(dentry->d_inode->i_mode))
  305 + return xattr_rmdir(dir, dentry);
457 306  
458   - if (!S_ISDIR(xafile->d_inode->i_mode)) {
459   - mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD);
460   - err = reiserfs_setattr(xafile, attrs);
461   - mutex_unlock(&xafile->d_inode->i_mutex);
462   - }
463   - dput(xafile);
  307 + return xattr_unlink(dir, dentry);
  308 +}
464 309  
  310 +static int chown_one_xattr(struct dentry *dentry, void *data)
  311 +{
  312 + struct iattr *attrs = data;
  313 + return reiserfs_setattr(dentry, attrs);
  314 +}
  315 +
  316 +/* No i_mutex, but the inode is unconnected. */
  317 +int reiserfs_delete_xattrs(struct inode *inode)
  318 +{
  319 + int err = reiserfs_for_each_xattr(inode, delete_one_xattr, NULL);
  320 + if (err)
  321 + reiserfs_warning(inode->i_sb, "jdm-20004",
  322 + "Couldn't delete all xattrs (%d)\n", err);
465 323 return err;
466 324 }
467 325  
  326 +/* inode->i_mutex: down */
468 327 int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
469 328 {
470   - struct dentry *dir;
471   - int err = 0;
472   - struct reiserfs_chown_buf buf;
473   - unsigned int ia_valid = attrs->ia_valid;
474   -
475   - /* Skip out, an xattr has no xattrs associated with it */
476   - if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
477   - return 0;
478   -
479   - dir = open_xa_dir(inode, XATTR_REPLACE);
480   - if (IS_ERR(dir)) {
481   - if (PTR_ERR(dir) != -ENODATA)
482   - err = PTR_ERR(dir);
483   - goto out;
484   - } else if (!dir->d_inode)
485   - goto out_dir;
486   -
487   - attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
488   - buf.xadir = dir;
489   - buf.attrs = attrs;
490   - buf.inode = inode;
491   -
492   - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
493   - err = xattr_readdir(dir->d_inode, reiserfs_chown_xattrs_filler, &buf);
494   -
495   - if (!err)
496   - err = reiserfs_setattr(dir, attrs);
497   - mutex_unlock(&dir->d_inode->i_mutex);
498   -
499   - attrs->ia_valid = ia_valid;
500   -out_dir:
501   - dput(dir);
502   -out:
  329 + int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs);
503 330 if (err)
504 331 reiserfs_warning(inode->i_sb, "jdm-20007",
505 332 "Couldn't chown all xattrs (%d)\n", err);
... ... @@ -1004,6 +831,7 @@
1004 831 {
1005 832 struct dentry *dir;
1006 833 int err = 0;
  834 + loff_t pos = 0;
1007 835 struct listxattr_buf buf = {
1008 836 .inode = dentry->d_inode,
1009 837 .buf = buffer,
... ... @@ -1026,7 +854,7 @@
1026 854 }
1027 855  
1028 856 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
1029   - err = xattr_readdir(dir->d_inode, listxattr_filler, &buf);
  857 + err = reiserfs_readdir_dentry(dir, &buf, listxattr_filler, &pos);
1030 858 mutex_unlock(&dir->d_inode->i_mutex);
1031 859  
1032 860 if (!err)
include/linux/reiserfs_fs.h
... ... @@ -1984,6 +1984,7 @@
1984 1984 extern const struct inode_operations reiserfs_symlink_inode_operations;
1985 1985 extern const struct inode_operations reiserfs_special_inode_operations;
1986 1986 extern const struct file_operations reiserfs_dir_operations;
  1987 +int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *);
1987 1988  
1988 1989 /* tail_conversion.c */
1989 1990 int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,