aboutsummaryrefslogtreecommitdiffstats
path: root/fs/reiserfs/xattr.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2009-03-30 14:02:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-03-30 15:16:38 -0400
commita41f1a4715f26f7bc4d047d0bc7710145c8e69c7 (patch)
tree8b5d94368e774ec490619593300e8b3f4b7c5cb1 /fs/reiserfs/xattr.c
parent0ab2621ebd9a28bf7a524ecd50d492a10579dfcc (diff)
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>
Diffstat (limited to 'fs/reiserfs/xattr.c')
-rw-r--r--fs/reiserfs/xattr.c402
1 files changed, 115 insertions, 287 deletions
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index c2e3a92aaf2b..1baafec64331 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -167,218 +167,65 @@ static struct dentry *open_xa_dir(const struct inode *inode, int flags)
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 */
183static 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 */
328static
329int 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/* The following are side effects of other operations that aren't explicitly 170/* The following are side effects of other operations that aren't explicitly
341 * modifying extended attributes. This includes operations such as permissions 171 * modifying extended attributes. This includes operations such as permissions
342 * or ownership changes, object deletions, etc. */ 172 * or ownership changes, object deletions, etc. */
173struct reiserfs_dentry_buf {
174 struct dentry *xadir;
175 int count;
176 struct dentry *dentries[8];
177};
343 178
344static int 179static int
345reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen, 180fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
346 loff_t offset, u64 ino, unsigned int d_type) 181 u64 ino, unsigned int d_type)
347{ 182{
348 struct dentry *xadir = (struct dentry *)buf; 183 struct reiserfs_dentry_buf *dbuf = buf;
349 struct dentry *dentry; 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 if (IS_ERR(dentry)) { 194 if (IS_ERR(dentry)) {
354 err = PTR_ERR(dentry); 195 return PTR_ERR(dentry);
355 goto out;
356 } else if (!dentry->d_inode) { 196 } else if (!dentry->d_inode) {
357 err = -ENODATA; 197 /* A directory entry exists, but no file? */
358 goto out_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.. */ 206 dbuf->dentries[dbuf->count++] = dentry;
362 if (S_ISDIR(dentry->d_inode->i_mode)) 207 return 0;
363 goto out_file; 208}
364
365 err = xattr_unlink(xadir->d_inode, dentry);
366
367out_file:
368 dput(dentry);
369 209
370out: 210static void
371 return err; 211cleanup_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 */ 219static int reiserfs_for_each_xattr(struct inode *inode,
375int reiserfs_delete_xattrs(struct inode *inode) 220 int (*action)(struct dentry *, void *),
221 void *data)
376{ 222{
377 int err = -ENODATA; 223 struct dentry *dir;
378 struct dentry *dir, *root; 224 int i, err = 0;
379 struct reiserfs_transaction_handle th; 225 loff_t pos = 0;
380 int blocks = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 226 struct reiserfs_dentry_buf buf = {
381 4 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); 227 .count = 0,
228 };
382 229
383 /* Skip out, an xattr has no xattrs associated with it */ 230 /* Skip out, an xattr has no xattrs associated with it */
384 if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) 231 if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
@@ -389,117 +236,97 @@ int reiserfs_delete_xattrs(struct inode *inode)
389 err = PTR_ERR(dir); 236 err = PTR_ERR(dir);
390 goto out; 237 goto out;
391 } else if (!dir->d_inode) { 238 } else if (!dir->d_inode) {
392 dput(dir); 239 err = 0;
393 goto out; 240 goto out_dir;
394 } 241 }
395 242
396 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); 243 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
397 err = xattr_readdir(dir->d_inode, reiserfs_delete_xattrs_filler, dir); 244 buf.xadir = dir;
398 mutex_unlock(&dir->d_inode->i_mutex); 245 err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
399 if (err) { 246 while ((err == 0 || err == -ENOSPC) && buf.count) {
400 dput(dir); 247 err = 0;
401 goto out; 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); 267 /* Clean up after a failed readdir */
405 dput(dir); 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 if (!err) { 270 if (!err) {
418 int jerror; 271 /* We start a transaction here to avoid a ABBA situation
419 mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_XATTR); 272 * between the xattr root's i_mutex and the journal lock.
420 err = xattr_rmdir(root->d_inode, dir); 273 * This doesn't incur much additional overhead since the
421 jerror = journal_end(&th, inode->i_sb, blocks); 274 * new transaction will just nest inside the
422 mutex_unlock(&root->d_inode->i_mutex); 275 * outer transaction. */
423 err = jerror ?: err; 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 290out_dir:
426 dput(root); 291 dput(dir);
427out: 292out:
428 if (err) 293 /* -ENODATA isn't an error */
429 reiserfs_warning(inode->i_sb, "jdm-20004", 294 if (err == -ENODATA)
430 "Couldn't remove all xattrs (%d)\n", err); 295 err = 0;
431 return err; 296 return err;
432} 297}
433 298
434struct reiserfs_chown_buf { 299static int delete_one_xattr(struct dentry *dentry, void *data)
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 */
441static int
442reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
443 loff_t offset, u64 ino, unsigned int d_type)
444{ 300{
445 struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf; 301 struct inode *dir = dentry->d_parent->d_inode;
446 struct dentry *xafile, *xadir = chown_buf->xadir;
447 struct iattr *attrs = chown_buf->attrs;
448 int err = 0;
449 302
450 xafile = lookup_one_len(name, xadir, namelen); 303 /* This is the xattr dir, handle specially. */
451 if (IS_ERR(xafile)) 304 if (S_ISDIR(dentry->d_inode->i_mode))
452 return PTR_ERR(xafile); 305 return xattr_rmdir(dir, dentry);
453 else if (!xafile->d_inode) {
454 dput(xafile);
455 return -ENODATA;
456 }
457 306
458 if (!S_ISDIR(xafile->d_inode->i_mode)) { 307 return xattr_unlink(dir, dentry);
459 mutex_lock_nested(&xafile->d_inode->i_mutex, I_MUTEX_CHILD); 308}
460 err = reiserfs_setattr(xafile, attrs); 309
461 mutex_unlock(&xafile->d_inode->i_mutex); 310static int chown_one_xattr(struct dentry *dentry, void *data)
462 } 311{
463 dput(xafile); 312 struct iattr *attrs = data;
313 return reiserfs_setattr(dentry, attrs);
314}
464 315
316/* No i_mutex, but the inode is unconnected. */
317int 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 return err; 323 return err;
466} 324}
467 325
326/* inode->i_mutex: down */
468int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs) 327int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
469{ 328{
470 struct dentry *dir; 329 int err = reiserfs_for_each_xattr(inode, chown_one_xattr, attrs);
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;
500out_dir:
501 dput(dir);
502out:
503 if (err) 330 if (err)
504 reiserfs_warning(inode->i_sb, "jdm-20007", 331 reiserfs_warning(inode->i_sb, "jdm-20007",
505 "Couldn't chown all xattrs (%d)\n", err); 332 "Couldn't chown all xattrs (%d)\n", err);
@@ -1004,6 +831,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
1004{ 831{
1005 struct dentry *dir; 832 struct dentry *dir;
1006 int err = 0; 833 int err = 0;
834 loff_t pos = 0;
1007 struct listxattr_buf buf = { 835 struct listxattr_buf buf = {
1008 .inode = dentry->d_inode, 836 .inode = dentry->d_inode,
1009 .buf = buffer, 837 .buf = buffer,
@@ -1026,7 +854,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
1026 } 854 }
1027 855
1028 mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); 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 mutex_unlock(&dir->d_inode->i_mutex); 858 mutex_unlock(&dir->d_inode->i_mutex);
1031 859
1032 if (!err) 860 if (!err)