Blame view
fs/cachefiles/namei.c
24.8 KB
9ae326a69 CacheFiles: A cac... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* CacheFiles path walking and related routines * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ #include <linux/module.h> #include <linux/sched.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/fsnotify.h> #include <linux/quotaops.h> #include <linux/xattr.h> #include <linux/mount.h> #include <linux/namei.h> #include <linux/security.h> |
5a0e3ad6a include cleanup: ... |
22 |
#include <linux/slab.h> |
5d6c31910 xattr: Add __vfs_... |
23 |
#include <linux/xattr.h> |
9ae326a69 CacheFiles: A cac... |
24 |
#include "internal.h" |
d0e27b780 CacheFiles: Bette... |
25 26 27 28 29 30 31 32 33 34 35 36 |
#define CACHEFILES_KEYBUF_SIZE 512 /* * dump debugging info about an object */ static noinline void __cachefiles_printk_object(struct cachefiles_object *object, const char *prefix, u8 *keybuf) { struct fscache_cookie *cookie; unsigned keylen, loop; |
4e1eb8830 FS/CACHEFILES: co... |
37 38 39 40 |
pr_err("%sobject: OBJ%x ", prefix, object->fscache.debug_id); pr_err("%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx] ", |
caaef6900 FS-Cache: Fix obj... |
41 |
prefix, object->fscache.state->name, |
8b8edefa2 fscache: convert ... |
42 |
object->fscache.flags, work_busy(&object->fscache.work), |
c2d35bfe4 FS-Cache: Don't m... |
43 |
object->fscache.events, object->fscache.event_mask); |
4e1eb8830 FS/CACHEFILES: co... |
44 45 |
pr_err("%sops=%u inp=%u exc=%u ", |
d0e27b780 CacheFiles: Bette... |
46 47 |
prefix, object->fscache.n_ops, object->fscache.n_in_progress, object->fscache.n_exclusive); |
4e1eb8830 FS/CACHEFILES: co... |
48 49 |
pr_err("%sparent=%p ", |
d0e27b780 CacheFiles: Bette... |
50 51 52 53 54 |
prefix, object->fscache.parent); spin_lock(&object->fscache.lock); cookie = object->fscache.cookie; if (cookie) { |
4e1eb8830 FS/CACHEFILES: co... |
55 56 |
pr_err("%scookie=%p [pr=%p nd=%p fl=%lx] ", |
d0e27b780 CacheFiles: Bette... |
57 58 59 60 61 |
prefix, object->fscache.cookie, object->fscache.cookie->parent, object->fscache.cookie->netfs_data, object->fscache.cookie->flags); |
509bf24d1 CacheFiles: Don't... |
62 |
if (keybuf && cookie->def) |
d0e27b780 CacheFiles: Bette... |
63 64 65 66 67 |
keylen = cookie->def->get_key(cookie->netfs_data, keybuf, CACHEFILES_KEYBUF_SIZE); else keylen = 0; } else { |
4e1eb8830 FS/CACHEFILES: co... |
68 69 |
pr_err("%scookie=NULL ", prefix); |
d0e27b780 CacheFiles: Bette... |
70 71 72 73 74 |
keylen = 0; } spin_unlock(&object->fscache.lock); if (keylen) { |
4e1eb8830 FS/CACHEFILES: co... |
75 |
pr_err("%skey=[%u] '", prefix, keylen); |
d0e27b780 CacheFiles: Bette... |
76 |
for (loop = 0; loop < keylen; loop++) |
4e1eb8830 FS/CACHEFILES: co... |
77 78 79 |
pr_cont("%02x", keybuf[loop]); pr_cont("' "); |
d0e27b780 CacheFiles: Bette... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
} } /* * dump debugging info about a pair of objects */ static noinline void cachefiles_printk_object(struct cachefiles_object *object, struct cachefiles_object *xobject) { u8 *keybuf; keybuf = kmalloc(CACHEFILES_KEYBUF_SIZE, GFP_NOIO); if (object) __cachefiles_printk_object(object, "", keybuf); if (xobject) __cachefiles_printk_object(xobject, "x", keybuf); kfree(keybuf); } |
9ae326a69 CacheFiles: A cac... |
98 |
/* |
c61ea31da CacheFiles: Fix o... |
99 100 101 102 103 104 |
* mark the owner of a dentry, if there is one, to indicate that that dentry * has been preemptively deleted * - the caller must hold the i_mutex on the dentry's parent as required to * call vfs_unlink(), vfs_rmdir() or vfs_rename() */ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache, |
182d919b8 FS-Cache: Count c... |
105 106 |
struct dentry *dentry, enum fscache_why_object_killed why) |
c61ea31da CacheFiles: Fix o... |
107 108 109 |
{ struct cachefiles_object *object; struct rb_node *p; |
a455589f1 assorted conversi... |
110 |
_enter(",'%pd'", dentry); |
c61ea31da CacheFiles: Fix o... |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
write_lock(&cache->active_lock); p = cache->active_nodes.rb_node; while (p) { object = rb_entry(p, struct cachefiles_object, active_node); if (object->dentry > dentry) p = p->rb_left; else if (object->dentry < dentry) p = p->rb_right; else goto found_dentry; } write_unlock(&cache->active_lock); _leave(" [no owner]"); return; /* found the dentry for */ found_dentry: kdebug("preemptive burial: OBJ%x [%s] %p", object->fscache.debug_id, |
caaef6900 FS-Cache: Fix obj... |
133 |
object->fscache.state->name, |
c61ea31da CacheFiles: Fix o... |
134 |
dentry); |
493f7bc11 FS-Cache: Wrap ch... |
135 |
if (fscache_object_is_live(&object->fscache)) { |
4e1eb8830 FS/CACHEFILES: co... |
136 137 |
pr_err(" "); |
0227d6abb fs/cachefiles: re... |
138 139 |
pr_err("Error: Can't preemptively bury live object "); |
c61ea31da CacheFiles: Fix o... |
140 |
cachefiles_printk_object(object, NULL); |
182d919b8 FS-Cache: Count c... |
141 142 143 |
} else { if (why != FSCACHE_OBJECT_IS_STALE) fscache_object_mark_killed(&object->fscache, why); |
c61ea31da CacheFiles: Fix o... |
144 145 146 147 148 149 150 |
} write_unlock(&cache->active_lock); _leave(" [owner marked]"); } /* |
9ae326a69 CacheFiles: A cac... |
151 152 |
* record the fact that an object is now active */ |
fee096deb CacheFiles: Catch... |
153 154 |
static int cachefiles_mark_object_active(struct cachefiles_cache *cache, struct cachefiles_object *object) |
9ae326a69 CacheFiles: A cac... |
155 156 157 158 159 160 161 162 163 |
{ struct cachefiles_object *xobject; struct rb_node **_p, *_parent = NULL; struct dentry *dentry; _enter(",%p", object); try_again: write_lock(&cache->active_lock); |
d0e27b780 CacheFiles: Bette... |
164 |
if (test_and_set_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags)) { |
0227d6abb fs/cachefiles: re... |
165 166 |
pr_err("Error: Object already active "); |
d0e27b780 CacheFiles: Bette... |
167 |
cachefiles_printk_object(object, NULL); |
9ae326a69 CacheFiles: A cac... |
168 |
BUG(); |
d0e27b780 CacheFiles: Bette... |
169 |
} |
9ae326a69 CacheFiles: A cac... |
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
dentry = object->dentry; _p = &cache->active_nodes.rb_node; while (*_p) { _parent = *_p; xobject = rb_entry(_parent, struct cachefiles_object, active_node); ASSERT(xobject != object); if (xobject->dentry > dentry) _p = &(*_p)->rb_left; else if (xobject->dentry < dentry) _p = &(*_p)->rb_right; else goto wait_for_old_object; } rb_link_node(&object->active_node, _parent, _p); rb_insert_color(&object->active_node, &cache->active_nodes); write_unlock(&cache->active_lock); |
fee096deb CacheFiles: Catch... |
192 193 |
_leave(" = 0"); return 0; |
9ae326a69 CacheFiles: A cac... |
194 195 196 197 |
/* an old object from a previous incarnation is hogging the slot - we * need to wait for it to be destroyed */ wait_for_old_object: |
a30efe261 CacheFiles: Fix i... |
198 |
if (fscache_object_is_live(&xobject->fscache)) { |
4e1eb8830 FS/CACHEFILES: co... |
199 200 |
pr_err(" "); |
0227d6abb fs/cachefiles: re... |
201 202 |
pr_err("Error: Unexpected object collision "); |
d0e27b780 CacheFiles: Bette... |
203 |
cachefiles_printk_object(object, xobject); |
9ae326a69 CacheFiles: A cac... |
204 205 206 207 |
BUG(); } atomic_inc(&xobject->usage); write_unlock(&cache->active_lock); |
fee096deb CacheFiles: Catch... |
208 209 210 211 212 213 214 215 216 |
if (test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { wait_queue_head_t *wq; signed long timeout = 60 * HZ; wait_queue_t wait; bool requeue; /* if the object we're waiting for is queued for processing, * then just put ourselves on the queue behind it */ |
8b8edefa2 fscache: convert ... |
217 |
if (work_pending(&xobject->fscache.work)) { |
fee096deb CacheFiles: Catch... |
218 219 220 221 222 223 224 |
_debug("queue OBJ%x behind OBJ%x immediately", object->fscache.debug_id, xobject->fscache.debug_id); goto requeue; } /* otherwise we sleep until either the object we're waiting for |
8b8edefa2 fscache: convert ... |
225 |
* is done, or the fscache_object is congested */ |
fee096deb CacheFiles: Catch... |
226 227 228 229 230 231 232 |
wq = bit_waitqueue(&xobject->flags, CACHEFILES_OBJECT_ACTIVE); init_wait(&wait); requeue = false; do { prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); if (!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) break; |
8b8edefa2 fscache: convert ... |
233 234 |
requeue = fscache_object_sleep_till_congested(&timeout); |
fee096deb CacheFiles: Catch... |
235 236 237 238 239 240 241 242 243 244 245 246 |
} while (timeout > 0 && !requeue); finish_wait(wq, &wait); if (requeue && test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)) { _debug("queue OBJ%x behind OBJ%x after wait", object->fscache.debug_id, xobject->fscache.debug_id); goto requeue; } if (timeout <= 0) { |
4e1eb8830 FS/CACHEFILES: co... |
247 248 |
pr_err(" "); |
0227d6abb fs/cachefiles: re... |
249 250 |
pr_err("Error: Overlong wait for old active object to go away "); |
fee096deb CacheFiles: Catch... |
251 252 253 254 255 256 |
cachefiles_printk_object(object, xobject); goto requeue; } } ASSERT(!test_bit(CACHEFILES_OBJECT_ACTIVE, &xobject->flags)); |
9ae326a69 CacheFiles: A cac... |
257 258 259 |
cache->cache.ops->put_object(&xobject->fscache); goto try_again; |
fee096deb CacheFiles: Catch... |
260 261 262 263 264 265 |
requeue: clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); cache->cache.ops->put_object(&xobject->fscache); _leave(" = -ETIMEDOUT"); return -ETIMEDOUT; |
9ae326a69 CacheFiles: A cac... |
266 267 268 |
} /* |
a5b3a80b8 CacheFiles: Provi... |
269 270 271 |
* Mark an object as being inactive. */ void cachefiles_mark_object_inactive(struct cachefiles_cache *cache, |
a818101d7 cachefiles: Fix a... |
272 273 |
struct cachefiles_object *object, blkcnt_t i_blocks) |
a5b3a80b8 CacheFiles: Provi... |
274 275 276 277 278 279 280 281 282 283 284 |
{ write_lock(&cache->active_lock); rb_erase(&object->active_node, &cache->active_nodes); clear_bit(CACHEFILES_OBJECT_ACTIVE, &object->flags); write_unlock(&cache->active_lock); wake_up_bit(&object->flags, CACHEFILES_OBJECT_ACTIVE); /* This object can now be culled, so we need to let the daemon know * that there is something it can remove if it needs to. */ |
db20a8925 cachefiles: Fix r... |
285 |
atomic_long_add(i_blocks, &cache->b_released); |
a5b3a80b8 CacheFiles: Provi... |
286 287 288 289 290 |
if (atomic_inc_return(&cache->f_released)) cachefiles_state_changed(cache); } /* |
9ae326a69 CacheFiles: A cac... |
291 292 293 294 295 296 297 298 |
* delete an object representation from the cache * - file backed objects are unlinked * - directory backed objects are stuffed into the graveyard for userspace to * delete * - unlocks the directory mutex */ static int cachefiles_bury_object(struct cachefiles_cache *cache, struct dentry *dir, |
c61ea31da CacheFiles: Fix o... |
299 |
struct dentry *rep, |
182d919b8 FS-Cache: Count c... |
300 301 |
bool preemptive, enum fscache_why_object_killed why) |
9ae326a69 CacheFiles: A cac... |
302 303 |
{ struct dentry *grave, *trap; |
821404434 CacheFiles: Add c... |
304 |
struct path path, path_to_graveyard; |
9ae326a69 CacheFiles: A cac... |
305 306 |
char nbuffer[8 + 8 + 1]; int ret; |
a455589f1 assorted conversi... |
307 |
_enter(",'%pd','%pd'", dir, rep); |
9ae326a69 CacheFiles: A cac... |
308 |
|
c61ea31da CacheFiles: Fix o... |
309 |
_debug("remove %p from %p", rep, dir); |
9ae326a69 CacheFiles: A cac... |
310 |
/* non-directories can just be unlinked */ |
e36cb0b89 VFS: (Scripted) C... |
311 |
if (!d_is_dir(rep)) { |
9ae326a69 CacheFiles: A cac... |
312 |
_debug("unlink stale object"); |
9ae326a69 CacheFiles: A cac... |
313 |
|
821404434 CacheFiles: Add c... |
314 315 316 317 318 319 |
path.mnt = cache->mnt; path.dentry = dir; ret = security_path_unlink(&path, rep); if (ret < 0) { cachefiles_io_error(cache, "Unlink security error"); } else { |
5153bc817 VFS: Cachefiles s... |
320 |
ret = vfs_unlink(d_inode(dir), rep, NULL); |
821404434 CacheFiles: Add c... |
321 322 |
if (preemptive) |
182d919b8 FS-Cache: Count c... |
323 |
cachefiles_mark_object_buried(cache, rep, why); |
821404434 CacheFiles: Add c... |
324 |
} |
c61ea31da CacheFiles: Fix o... |
325 |
|
5955102c9 wrappers for ->i_... |
326 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
327 328 329 330 331 332 333 334 335 336 |
if (ret == -EIO) cachefiles_io_error(cache, "Unlink failed"); _leave(" = %d", ret); return ret; } /* directories have to be moved to the graveyard */ _debug("move stale object to graveyard"); |
5955102c9 wrappers for ->i_... |
337 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
try_again: /* first step is to make up a grave dentry in the graveyard */ sprintf(nbuffer, "%08x%08x", (uint32_t) get_seconds(), (uint32_t) atomic_inc_return(&cache->gravecounter)); /* do the multiway lock magic */ trap = lock_rename(cache->graveyard, dir); /* do some checks before getting the grave dentry */ if (rep->d_parent != dir) { /* the entry was probably culled when we dropped the parent dir * lock */ unlock_rename(cache->graveyard, dir); _leave(" = 0 [culled?]"); return 0; } |
ce40fa78e Cachefiles: Fix u... |
356 |
if (!d_can_lookup(cache->graveyard)) { |
9ae326a69 CacheFiles: A cac... |
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
unlock_rename(cache->graveyard, dir); cachefiles_io_error(cache, "Graveyard no longer a directory"); return -EIO; } if (trap == rep) { unlock_rename(cache->graveyard, dir); cachefiles_io_error(cache, "May not make directory loop"); return -EIO; } if (d_mountpoint(rep)) { unlock_rename(cache->graveyard, dir); cachefiles_io_error(cache, "Mountpoint in cache"); return -EIO; } grave = lookup_one_len(nbuffer, cache->graveyard, strlen(nbuffer)); if (IS_ERR(grave)) { unlock_rename(cache->graveyard, dir); if (PTR_ERR(grave) == -ENOMEM) { _leave(" = -ENOMEM"); return -ENOMEM; } cachefiles_io_error(cache, "Lookup error %ld", PTR_ERR(grave)); return -EIO; } |
466b77bc9 VFS: fs/cachefile... |
387 |
if (d_is_positive(grave)) { |
9ae326a69 CacheFiles: A cac... |
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
unlock_rename(cache->graveyard, dir); dput(grave); grave = NULL; cond_resched(); goto try_again; } if (d_mountpoint(grave)) { unlock_rename(cache->graveyard, dir); dput(grave); cachefiles_io_error(cache, "Mountpoint in graveyard"); return -EIO; } /* target should not be an ancestor of source */ if (trap == grave) { unlock_rename(cache->graveyard, dir); dput(grave); cachefiles_io_error(cache, "May not make directory loop"); return -EIO; } /* attempt the rename */ |
821404434 CacheFiles: Add c... |
411 412 413 414 |
path.mnt = cache->mnt; path.dentry = dir; path_to_graveyard.mnt = cache->mnt; path_to_graveyard.dentry = cache->graveyard; |
0b3974eb0 security: add fla... |
415 |
ret = security_path_rename(&path, rep, &path_to_graveyard, grave, 0); |
821404434 CacheFiles: Add c... |
416 417 418 |
if (ret < 0) { cachefiles_io_error(cache, "Rename security error %d", ret); } else { |
5153bc817 VFS: Cachefiles s... |
419 420 |
ret = vfs_rename(d_inode(dir), rep, d_inode(cache->graveyard), grave, NULL, 0); |
821404434 CacheFiles: Add c... |
421 422 423 |
if (ret != 0 && ret != -ENOMEM) cachefiles_io_error(cache, "Rename failed with error %d", ret); |
9ae326a69 CacheFiles: A cac... |
424 |
|
821404434 CacheFiles: Add c... |
425 |
if (preemptive) |
182d919b8 FS-Cache: Count c... |
426 |
cachefiles_mark_object_buried(cache, rep, why); |
821404434 CacheFiles: Add c... |
427 |
} |
c61ea31da CacheFiles: Fix o... |
428 |
|
9ae326a69 CacheFiles: A cac... |
429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
unlock_rename(cache->graveyard, dir); dput(grave); _leave(" = 0"); return 0; } /* * delete an object representation from the cache */ int cachefiles_delete_object(struct cachefiles_cache *cache, struct cachefiles_object *object) { struct dentry *dir; int ret; |
c61ea31da CacheFiles: Fix o... |
443 |
_enter(",OBJ%x{%p}", object->fscache.debug_id, object->dentry); |
9ae326a69 CacheFiles: A cac... |
444 445 |
ASSERT(object->dentry); |
466b77bc9 VFS: fs/cachefile... |
446 |
ASSERT(d_backing_inode(object->dentry)); |
9ae326a69 CacheFiles: A cac... |
447 448 449 |
ASSERT(object->dentry->d_parent); dir = dget_parent(object->dentry); |
5955102c9 wrappers for ->i_... |
450 |
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); |
8f9941aec CacheFiles: Fix a... |
451 |
|
182d919b8 FS-Cache: Count c... |
452 |
if (test_bit(FSCACHE_OBJECT_KILLED_BY_CACHE, &object->fscache.flags)) { |
c61ea31da CacheFiles: Fix o... |
453 454 455 |
/* object allocation for the same key preemptively deleted this * object's file so that it could create its own file */ _debug("object preemptively buried"); |
5955102c9 wrappers for ->i_... |
456 |
inode_unlock(d_inode(dir)); |
8f9941aec CacheFiles: Fix a... |
457 |
ret = 0; |
c61ea31da CacheFiles: Fix o... |
458 459 460 461 462 |
} else { /* we need to check that our parent is _still_ our parent - it * may have been renamed */ if (dir == object->dentry->d_parent) { ret = cachefiles_bury_object(cache, dir, |
182d919b8 FS-Cache: Count c... |
463 464 |
object->dentry, false, FSCACHE_OBJECT_WAS_RETIRED); |
c61ea31da CacheFiles: Fix o... |
465 466 467 468 |
} else { /* it got moved, presumably by cachefilesd culling it, * so it's no longer in the key path and we can ignore * it */ |
5955102c9 wrappers for ->i_... |
469 |
inode_unlock(d_inode(dir)); |
c61ea31da CacheFiles: Fix o... |
470 471 |
ret = 0; } |
8f9941aec CacheFiles: Fix a... |
472 |
} |
9ae326a69 CacheFiles: A cac... |
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 |
dput(dir); _leave(" = %d", ret); return ret; } /* * walk from the parent object to the child object through the backing * filesystem, creating directories as we go */ int cachefiles_walk_to_object(struct cachefiles_object *parent, struct cachefiles_object *object, const char *key, struct cachefiles_xattr *auxdata) { struct cachefiles_cache *cache; struct dentry *dir, *next = NULL; |
821404434 CacheFiles: Add c... |
490 |
struct path path; |
9ae326a69 CacheFiles: A cac... |
491 492 493 |
unsigned long start; const char *name; int ret, nlen; |
c61ea31da CacheFiles: Fix o... |
494 495 496 |
_enter("OBJ%x{%p},OBJ%x,%s,", parent->fscache.debug_id, parent->dentry, object->fscache.debug_id, key); |
9ae326a69 CacheFiles: A cac... |
497 498 499 |
cache = container_of(parent->fscache.cache, struct cachefiles_cache, cache); |
821404434 CacheFiles: Add c... |
500 |
path.mnt = cache->mnt; |
9ae326a69 CacheFiles: A cac... |
501 502 |
ASSERT(parent->dentry); |
466b77bc9 VFS: fs/cachefile... |
503 |
ASSERT(d_backing_inode(parent->dentry)); |
9ae326a69 CacheFiles: A cac... |
504 |
|
e36cb0b89 VFS: (Scripted) C... |
505 |
if (!(d_is_dir(parent->dentry))) { |
9ae326a69 CacheFiles: A cac... |
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
// TODO: convert file to dir _leave("looking up in none directory"); return -ENOBUFS; } dir = dget(parent->dentry); advance: /* attempt to transit the first directory component */ name = key; nlen = strlen(key); /* key ends in a double NUL */ key = key + nlen + 1; if (!*key) key = NULL; lookup_again: /* search the current directory for the element name */ _debug("lookup '%s'", name); |
5955102c9 wrappers for ->i_... |
526 |
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); |
9ae326a69 CacheFiles: A cac... |
527 528 529 530 531 532 |
start = jiffies; next = lookup_one_len(name, dir, nlen); cachefiles_hist(cachefiles_lookup_histogram, start); if (IS_ERR(next)) goto lookup_error; |
466b77bc9 VFS: fs/cachefile... |
533 |
_debug("next -> %p %s", next, d_backing_inode(next) ? "positive" : "negative"); |
9ae326a69 CacheFiles: A cac... |
534 535 |
if (!key) |
466b77bc9 VFS: fs/cachefile... |
536 |
object->new = !d_backing_inode(next); |
9ae326a69 CacheFiles: A cac... |
537 538 539 540 |
/* if this element of the path doesn't exist, then the lookup phase * failed, and we can release any readers in the certain knowledge that * there's nothing for them to actually read */ |
466b77bc9 VFS: fs/cachefile... |
541 |
if (d_is_negative(next)) |
9ae326a69 CacheFiles: A cac... |
542 543 544 545 546 |
fscache_object_lookup_negative(&object->fscache); /* we need to create the object if it's negative */ if (key || object->type == FSCACHE_COOKIE_TYPE_INDEX) { /* index objects and intervening tree levels must be subdirs */ |
466b77bc9 VFS: fs/cachefile... |
547 |
if (d_is_negative(next)) { |
9ae326a69 CacheFiles: A cac... |
548 549 |
ret = cachefiles_has_space(cache, 1, 0); if (ret < 0) |
182d919b8 FS-Cache: Count c... |
550 |
goto no_space_error; |
9ae326a69 CacheFiles: A cac... |
551 |
|
821404434 CacheFiles: Add c... |
552 553 554 555 |
path.dentry = dir; ret = security_path_mkdir(&path, next, 0); if (ret < 0) goto create_error; |
9ae326a69 CacheFiles: A cac... |
556 |
start = jiffies; |
5153bc817 VFS: Cachefiles s... |
557 |
ret = vfs_mkdir(d_inode(dir), next, 0); |
9ae326a69 CacheFiles: A cac... |
558 559 560 |
cachefiles_hist(cachefiles_mkdir_histogram, start); if (ret < 0) goto create_error; |
466b77bc9 VFS: fs/cachefile... |
561 |
ASSERT(d_backing_inode(next)); |
9ae326a69 CacheFiles: A cac... |
562 563 |
_debug("mkdir -> %p{%p{ino=%lu}}", |
466b77bc9 VFS: fs/cachefile... |
564 |
next, d_backing_inode(next), d_backing_inode(next)->i_ino); |
9ae326a69 CacheFiles: A cac... |
565 |
|
ce40fa78e Cachefiles: Fix u... |
566 |
} else if (!d_can_lookup(next)) { |
6ff66ac77 fs/cachefiles: ad... |
567 568 |
pr_err("inode %lu is not a directory ", |
466b77bc9 VFS: fs/cachefile... |
569 |
d_backing_inode(next)->i_ino); |
9ae326a69 CacheFiles: A cac... |
570 571 572 573 574 575 |
ret = -ENOBUFS; goto error; } } else { /* non-index objects start out life as files */ |
466b77bc9 VFS: fs/cachefile... |
576 |
if (d_is_negative(next)) { |
9ae326a69 CacheFiles: A cac... |
577 578 |
ret = cachefiles_has_space(cache, 1, 0); if (ret < 0) |
182d919b8 FS-Cache: Count c... |
579 |
goto no_space_error; |
9ae326a69 CacheFiles: A cac... |
580 |
|
821404434 CacheFiles: Add c... |
581 582 583 584 |
path.dentry = dir; ret = security_path_mknod(&path, next, S_IFREG, 0); if (ret < 0) goto create_error; |
9ae326a69 CacheFiles: A cac... |
585 |
start = jiffies; |
5153bc817 VFS: Cachefiles s... |
586 |
ret = vfs_create(d_inode(dir), next, S_IFREG, true); |
9ae326a69 CacheFiles: A cac... |
587 588 589 |
cachefiles_hist(cachefiles_create_histogram, start); if (ret < 0) goto create_error; |
466b77bc9 VFS: fs/cachefile... |
590 |
ASSERT(d_backing_inode(next)); |
9ae326a69 CacheFiles: A cac... |
591 592 |
_debug("create -> %p{%p{ino=%lu}}", |
466b77bc9 VFS: fs/cachefile... |
593 |
next, d_backing_inode(next), d_backing_inode(next)->i_ino); |
9ae326a69 CacheFiles: A cac... |
594 |
|
ce40fa78e Cachefiles: Fix u... |
595 |
} else if (!d_can_lookup(next) && |
e36cb0b89 VFS: (Scripted) C... |
596 |
!d_is_reg(next) |
9ae326a69 CacheFiles: A cac... |
597 |
) { |
6ff66ac77 fs/cachefiles: ad... |
598 599 |
pr_err("inode %lu is not a file or directory ", |
466b77bc9 VFS: fs/cachefile... |
600 |
d_backing_inode(next)->i_ino); |
9ae326a69 CacheFiles: A cac... |
601 602 603 604 605 606 607 608 |
ret = -ENOBUFS; goto error; } } /* process the next component */ if (key) { _debug("advance"); |
5955102c9 wrappers for ->i_... |
609 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
610 611 612 613 614 615 616 617 618 619 620 621 |
dput(dir); dir = next; next = NULL; goto advance; } /* we've found the object we were looking for */ object->dentry = next; /* if we've found that the terminal object exists, then we need to * check its attributes and delete it if it's out of date */ if (!object->new) { |
a455589f1 assorted conversi... |
622 |
_debug("validate '%pd'", next); |
9ae326a69 CacheFiles: A cac... |
623 624 625 626 627 628 |
ret = cachefiles_check_object_xattr(object, auxdata); if (ret == -ESTALE) { /* delete the object (the deleter drops the directory * mutex) */ object->dentry = NULL; |
182d919b8 FS-Cache: Count c... |
629 630 |
ret = cachefiles_bury_object(cache, dir, next, true, FSCACHE_OBJECT_IS_STALE); |
9ae326a69 CacheFiles: A cac... |
631 632 633 634 635 636 637 |
dput(next); next = NULL; if (ret < 0) goto delete_error; _debug("redo lookup"); |
182d919b8 FS-Cache: Count c... |
638 |
fscache_object_retrying_stale(&object->fscache); |
9ae326a69 CacheFiles: A cac... |
639 640 641 642 643 |
goto lookup_again; } } /* note that we're now using this object */ |
fee096deb CacheFiles: Catch... |
644 |
ret = cachefiles_mark_object_active(cache, object); |
9ae326a69 CacheFiles: A cac... |
645 |
|
5955102c9 wrappers for ->i_... |
646 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
647 648 |
dput(dir); dir = NULL; |
fee096deb CacheFiles: Catch... |
649 650 |
if (ret == -ETIMEDOUT) goto mark_active_timed_out; |
9ae326a69 CacheFiles: A cac... |
651 652 653 654 655 656 657 658 659 660 661 662 |
_debug("=== OBTAINED_OBJECT ==="); if (object->new) { /* attach data to a newly constructed terminal object */ ret = cachefiles_set_object_xattr(object, auxdata); if (ret < 0) goto check_error; } else { /* always update the atime on an object we've just looked up * (this is used to keep track of culling, and atimes are only * updated by read, write and readdir but not lookup or * open) */ |
68ac1234f switch touch_atim... |
663 664 |
path.dentry = next; touch_atime(&path); |
9ae326a69 CacheFiles: A cac... |
665 666 667 668 |
} /* open a file interface onto a data file */ if (object->type != FSCACHE_COOKIE_TYPE_INDEX) { |
e36cb0b89 VFS: (Scripted) C... |
669 |
if (d_is_reg(object->dentry)) { |
9ae326a69 CacheFiles: A cac... |
670 671 672 |
const struct address_space_operations *aops; ret = -EPERM; |
466b77bc9 VFS: fs/cachefile... |
673 |
aops = d_backing_inode(object->dentry)->i_mapping->a_ops; |
9ae326a69 CacheFiles: A cac... |
674 675 |
if (!aops->bmap) goto check_error; |
95201a406 cachefiles: perfo... |
676 677 |
if (object->dentry->d_sb->s_blocksize > PAGE_SIZE) goto check_error; |
9ae326a69 CacheFiles: A cac... |
678 679 680 681 682 683 684 685 686 |
object->backer = object->dentry; } else { BUG(); // TODO: open file in data-class subdir } } object->new = 0; fscache_obtained_object(&object->fscache); |
466b77bc9 VFS: fs/cachefile... |
687 |
_leave(" = 0 [%lu]", d_backing_inode(object->dentry)->i_ino); |
9ae326a69 CacheFiles: A cac... |
688 |
return 0; |
182d919b8 FS-Cache: Count c... |
689 690 |
no_space_error: fscache_object_mark_killed(&object->fscache, FSCACHE_OBJECT_NO_SPACE); |
9ae326a69 CacheFiles: A cac... |
691 692 693 694 695 |
create_error: _debug("create error %d", ret); if (ret == -EIO) cachefiles_io_error(cache, "Create/mkdir failed"); goto error; |
fee096deb CacheFiles: Catch... |
696 697 698 |
mark_active_timed_out: _debug("mark active timed out"); goto release_dentry; |
9ae326a69 CacheFiles: A cac... |
699 700 |
check_error: _debug("check error %d", ret); |
a818101d7 cachefiles: Fix a... |
701 702 |
cachefiles_mark_object_inactive( cache, object, d_backing_inode(object->dentry)->i_blocks); |
fee096deb CacheFiles: Catch... |
703 |
release_dentry: |
9ae326a69 CacheFiles: A cac... |
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
dput(object->dentry); object->dentry = NULL; goto error_out; delete_error: _debug("delete error %d", ret); goto error_out2; lookup_error: _debug("lookup error %ld", PTR_ERR(next)); ret = PTR_ERR(next); if (ret == -EIO) cachefiles_io_error(cache, "Lookup failed"); next = NULL; error: |
5955102c9 wrappers for ->i_... |
719 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
720 721 722 723 |
dput(next); error_out2: dput(dir); error_out: |
9ae326a69 CacheFiles: A cac... |
724 725 726 727 728 729 730 731 732 733 734 735 736 |
_leave(" = error %d", -ret); return ret; } /* * get a subdirectory */ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, struct dentry *dir, const char *dirname) { struct dentry *subdir; unsigned long start; |
821404434 CacheFiles: Add c... |
737 |
struct path path; |
9ae326a69 CacheFiles: A cac... |
738 739 740 741 742 |
int ret; _enter(",,%s", dirname); /* search the current directory for the element name */ |
5955102c9 wrappers for ->i_... |
743 |
inode_lock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
744 745 746 747 748 749 750 751 752 753 754 |
start = jiffies; subdir = lookup_one_len(dirname, dir, strlen(dirname)); cachefiles_hist(cachefiles_lookup_histogram, start); if (IS_ERR(subdir)) { if (PTR_ERR(subdir) == -ENOMEM) goto nomem_d_alloc; goto lookup_error; } _debug("subdir -> %p %s", |
466b77bc9 VFS: fs/cachefile... |
755 |
subdir, d_backing_inode(subdir) ? "positive" : "negative"); |
9ae326a69 CacheFiles: A cac... |
756 757 |
/* we need to create the subdir if it doesn't exist yet */ |
466b77bc9 VFS: fs/cachefile... |
758 |
if (d_is_negative(subdir)) { |
9ae326a69 CacheFiles: A cac... |
759 760 761 762 763 |
ret = cachefiles_has_space(cache, 1, 0); if (ret < 0) goto mkdir_error; _debug("attempt mkdir"); |
821404434 CacheFiles: Add c... |
764 765 766 767 768 |
path.mnt = cache->mnt; path.dentry = dir; ret = security_path_mkdir(&path, subdir, 0700); if (ret < 0) goto mkdir_error; |
5153bc817 VFS: Cachefiles s... |
769 |
ret = vfs_mkdir(d_inode(dir), subdir, 0700); |
9ae326a69 CacheFiles: A cac... |
770 771 |
if (ret < 0) goto mkdir_error; |
466b77bc9 VFS: fs/cachefile... |
772 |
ASSERT(d_backing_inode(subdir)); |
9ae326a69 CacheFiles: A cac... |
773 774 775 |
_debug("mkdir -> %p{%p{ino=%lu}}", subdir, |
466b77bc9 VFS: fs/cachefile... |
776 777 |
d_backing_inode(subdir), d_backing_inode(subdir)->i_ino); |
9ae326a69 CacheFiles: A cac... |
778 |
} |
5955102c9 wrappers for ->i_... |
779 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
780 781 |
/* we need to make sure the subdir is a directory */ |
466b77bc9 VFS: fs/cachefile... |
782 |
ASSERT(d_backing_inode(subdir)); |
9ae326a69 CacheFiles: A cac... |
783 |
|
ce40fa78e Cachefiles: Fix u... |
784 |
if (!d_can_lookup(subdir)) { |
6ff66ac77 fs/cachefiles: ad... |
785 786 |
pr_err("%s is not a directory ", dirname); |
9ae326a69 CacheFiles: A cac... |
787 788 789 790 791 |
ret = -EIO; goto check_error; } ret = -EPERM; |
5d6c31910 xattr: Add __vfs_... |
792 |
if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) || |
466b77bc9 VFS: fs/cachefile... |
793 794 795 |
!d_backing_inode(subdir)->i_op->lookup || !d_backing_inode(subdir)->i_op->mkdir || !d_backing_inode(subdir)->i_op->create || |
2773bf00a fs: rename "renam... |
796 |
!d_backing_inode(subdir)->i_op->rename || |
466b77bc9 VFS: fs/cachefile... |
797 798 |
!d_backing_inode(subdir)->i_op->rmdir || !d_backing_inode(subdir)->i_op->unlink) |
9ae326a69 CacheFiles: A cac... |
799 |
goto check_error; |
466b77bc9 VFS: fs/cachefile... |
800 |
_leave(" = [%lu]", d_backing_inode(subdir)->i_ino); |
9ae326a69 CacheFiles: A cac... |
801 802 803 804 805 806 807 808 |
return subdir; check_error: dput(subdir); _leave(" = %d [check]", ret); return ERR_PTR(ret); mkdir_error: |
5955102c9 wrappers for ->i_... |
809 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
810 |
dput(subdir); |
6ff66ac77 fs/cachefiles: ad... |
811 812 |
pr_err("mkdir %s failed with error %d ", dirname, ret); |
9ae326a69 CacheFiles: A cac... |
813 814 815 |
return ERR_PTR(ret); lookup_error: |
5955102c9 wrappers for ->i_... |
816 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
817 |
ret = PTR_ERR(subdir); |
6ff66ac77 fs/cachefiles: ad... |
818 819 |
pr_err("Lookup %s failed with error %d ", dirname, ret); |
9ae326a69 CacheFiles: A cac... |
820 821 822 |
return ERR_PTR(ret); nomem_d_alloc: |
5955102c9 wrappers for ->i_... |
823 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
_leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } /* * find out if an object is in use or not * - if finds object and it's not in use: * - returns a pointer to the object and a reference on it * - returns with the directory locked */ static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache, struct dentry *dir, char *filename) { struct cachefiles_object *object; struct rb_node *_n; struct dentry *victim; unsigned long start; int ret; |
a455589f1 assorted conversi... |
843 844 |
//_enter(",%pd/,%s", // dir, filename); |
9ae326a69 CacheFiles: A cac... |
845 846 |
/* look up the victim */ |
5955102c9 wrappers for ->i_... |
847 |
inode_lock_nested(d_inode(dir), I_MUTEX_PARENT); |
9ae326a69 CacheFiles: A cac... |
848 849 850 851 852 853 854 855 |
start = jiffies; victim = lookup_one_len(filename, dir, strlen(filename)); cachefiles_hist(cachefiles_lookup_histogram, start); if (IS_ERR(victim)) goto lookup_error; //_debug("victim -> %p %s", |
466b77bc9 VFS: fs/cachefile... |
856 |
// victim, d_backing_inode(victim) ? "positive" : "negative"); |
9ae326a69 CacheFiles: A cac... |
857 858 859 860 |
/* if the object is no longer there then we probably retired the object * at the netfs's request whilst the cull was in progress */ |
466b77bc9 VFS: fs/cachefile... |
861 |
if (d_is_negative(victim)) { |
5955102c9 wrappers for ->i_... |
862 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 |
dput(victim); _leave(" = -ENOENT [absent]"); return ERR_PTR(-ENOENT); } /* check to see if we're using this object */ read_lock(&cache->active_lock); _n = cache->active_nodes.rb_node; while (_n) { object = rb_entry(_n, struct cachefiles_object, active_node); if (object->dentry > victim) _n = _n->rb_left; else if (object->dentry < victim) _n = _n->rb_right; else goto object_in_use; } read_unlock(&cache->active_lock); //_leave(" = %p", victim); return victim; object_in_use: read_unlock(&cache->active_lock); |
5955102c9 wrappers for ->i_... |
891 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
892 893 894 895 896 |
dput(victim); //_leave(" = -EBUSY [in use]"); return ERR_PTR(-EBUSY); lookup_error: |
5955102c9 wrappers for ->i_... |
897 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
898 899 900 901 902 903 904 905 906 907 |
ret = PTR_ERR(victim); if (ret == -ENOENT) { /* file or dir now absent - probably retired by netfs */ _leave(" = -ESTALE [absent]"); return ERR_PTR(-ESTALE); } if (ret == -EIO) { cachefiles_io_error(cache, "Lookup failed"); } else if (ret != -ENOMEM) { |
6ff66ac77 fs/cachefiles: ad... |
908 909 |
pr_err("Internal error: %d ", ret); |
9ae326a69 CacheFiles: A cac... |
910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
ret = -EIO; } _leave(" = %d", ret); return ERR_PTR(ret); } /* * cull an object if it's not in use * - called only by cache manager daemon */ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir, char *filename) { struct dentry *victim; int ret; |
a455589f1 assorted conversi... |
926 |
_enter(",%pd/,%s", dir, filename); |
9ae326a69 CacheFiles: A cac... |
927 928 929 930 931 932 |
victim = cachefiles_check_active(cache, dir, filename); if (IS_ERR(victim)) return PTR_ERR(victim); _debug("victim -> %p %s", |
466b77bc9 VFS: fs/cachefile... |
933 |
victim, d_backing_inode(victim) ? "positive" : "negative"); |
9ae326a69 CacheFiles: A cac... |
934 935 936 937 938 939 940 941 942 943 944 945 |
/* okay... the victim is not being used so we can cull it * - start by marking it as stale */ _debug("victim is cullable"); ret = cachefiles_remove_object_xattr(cache, victim); if (ret < 0) goto error_unlock; /* actually remove the victim (drops the dir mutex) */ _debug("bury"); |
182d919b8 FS-Cache: Count c... |
946 947 |
ret = cachefiles_bury_object(cache, dir, victim, false, FSCACHE_OBJECT_WAS_CULLED); |
9ae326a69 CacheFiles: A cac... |
948 949 950 951 952 953 954 955 |
if (ret < 0) goto error; dput(victim); _leave(" = 0"); return 0; error_unlock: |
5955102c9 wrappers for ->i_... |
956 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
957 958 959 960 961 962 963 964 965 |
error: dput(victim); if (ret == -ENOENT) { /* file or dir now absent - probably retired by netfs */ _leave(" = -ESTALE [absent]"); return -ESTALE; } if (ret != -ENOMEM) { |
6ff66ac77 fs/cachefiles: ad... |
966 967 |
pr_err("Internal error: %d ", ret); |
9ae326a69 CacheFiles: A cac... |
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
ret = -EIO; } _leave(" = %d", ret); return ret; } /* * find out if an object is in use or not * - called only by cache manager daemon * - returns -EBUSY or 0 to indicate whether an object is in use or not */ int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir, char *filename) { struct dentry *victim; |
a455589f1 assorted conversi... |
984 985 |
//_enter(",%pd/,%s", // dir, filename); |
9ae326a69 CacheFiles: A cac... |
986 987 988 989 |
victim = cachefiles_check_active(cache, dir, filename); if (IS_ERR(victim)) return PTR_ERR(victim); |
5955102c9 wrappers for ->i_... |
990 |
inode_unlock(d_inode(dir)); |
9ae326a69 CacheFiles: A cac... |
991 992 993 994 |
dput(victim); //_leave(" = 0"); return 0; } |