diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-15 16:26:31 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-17 22:16:14 +0200 |
commit | 4266bb02b1f3342d3fc4920c07c71592a14acdd9 (patch) | |
tree | a8312d2209709d962cd3f71cc3cf0b3641a6b951 | |
parent | c234e34ad80801acd902c6d4892a7722fd084a87 (diff) |
isofs: port to libdiskfs' node cache
* isofs/inode.c: Drop all cache-related code.
(diskfs_user_make_node): New function.
(calculate_file_start): Check for `record' being null.
(cache_id): New function.
(read_node): Rename to diskfs_user_read_node and adopt accordingly.
(diskfs_try_dropping_softrefs): Rename to diskfs_user_try_dropping_softrefs.
* isofs/isofs.h (struct lookup_context): New definition.
(cache_id): New declaration.
* isofs/lookup.c (diskfs_lookup_hard): Adjust accordingly.
* isofs/main.c (fetch_root): Likewise.
-rw-r--r-- | isofs/inode.c | 326 | ||||
-rw-r--r-- | isofs/isofs.h | 13 | ||||
-rw-r--r-- | isofs/lookup.c | 18 | ||||
-rw-r--r-- | isofs/main.c | 15 |
4 files changed, 70 insertions, 302 deletions
diff --git a/isofs/inode.c b/isofs/inode.c index e79ebddb..eef2a6a4 100644 --- a/isofs/inode.c +++ b/isofs/inode.c @@ -31,72 +31,6 @@ record for symlinks and zero length files, and file_start otherwise. Only for hard links to zero length files we get extra inodes. */ -#define INOHSZ 512 -#if ((INOHSZ&(INOHSZ-1)) == 0) -#define INOHASH(ino) ((ino>>8)&(INOHSZ-1)) -#else -#define INOHASH(ino) (((unsigned)(ino>>8))%INOHSZ) -#endif - -struct node_cache -{ - struct dirrect *dr; /* somewhere in disk_image */ - off_t file_start; /* start of file */ - - off_t id; /* UNIQUE identifier. */ - - struct node *np; /* if live */ -}; - -/* The node_cache is a cache of nodes. - - Access to node_cache, node_cache_size, and node_cache_alloced is - protected by nodecache_lock. - - Every node in the node_cache carries a light reference. When we - are asked to give up that light reference, we reacquire our lock - momentarily to check whether someone else reacquired a reference - through the node_cache. */ -static int node_cache_size = 0; -static int node_cache_alloced = 0; -struct node_cache *node_cache = 0; -static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; - -/* Forward */ -static error_t read_disknode (struct node *, - struct dirrect *, struct rrip_lookup *); - - -/* Lookup node with id ID. Returns NULL if the node is not found in - the node cache. */ -static struct node * -lookup (off_t id) -{ - int i; - for (i = 0; i < node_cache_size; i++) - if (node_cache[i].id == id - && node_cache[i].np) - return node_cache[i].np; - return NULL; -} - -/* See if node with identifier ID is in the cache. If so, return it, - with one additional reference. nodecache_lock must be held - on entry to the call, and will be released iff the node was found - in the cache. */ -void -inode_cache_find (off_t id, struct node **npp) -{ - *npp = lookup (id); - if (*npp) - { - diskfs_nref (*npp); - pthread_rwlock_unlock (&nodecache_lock); - pthread_mutex_lock (&(*npp)->lock); - } -} - - /* Determine if we use file_start or struct dirrect * as node id. */ int use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) @@ -108,140 +42,35 @@ use_file_start_id (struct dirrect *record, struct rrip_lookup *rr) return 1; } -/* Enter NP into the cache. The directory entry we used is DR, the - cached Rock-Ridge info RR. nodecache_lock must be held. */ -void -cache_inode (struct node *np, struct dirrect *record, - struct rrip_lookup *rr) -{ - int i; - struct node_cache *c = 0; - off_t id; - - if (use_file_start_id (record, rr)) - id = np->dn->file_start << store->log2_block_size; - else - id = (off_t) ((void *) record - (void *) disk_image); - - /* First see if there's already an entry. */ - for (i = 0; i < node_cache_size; i++) - if (node_cache[i].id == id) - break; - - if (i == node_cache_size) - { - if (node_cache_size >= node_cache_alloced) - { - if (!node_cache_alloced) - { - /* Initialize */ - node_cache_alloced = 10; - node_cache = malloc (sizeof (struct node_cache) * 10); - } - else - { - node_cache_alloced *= 2; - node_cache = realloc (node_cache, - sizeof (struct node_cache) - * node_cache_alloced); - } - assert (node_cache); - } - node_cache_size++; - } - - c = &node_cache[i]; - c->id = id; - c->dr = record; - c->file_start = np->dn->file_start; - diskfs_nref_light (np); - c->np = np; - - /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */ - np->cache_id = i + 1; -} - -/* Fetch inode with cache id ID; set *NPP to the node structure; - gain one user reference and lock the node. */ +/* The user must define this function if she wants to use the node + cache. Create and initialize a node. */ error_t -diskfs_cached_lookup (ino_t id, struct node **npp) +diskfs_user_make_node (struct node **npp, struct lookup_context *ctx) { - struct node *np; error_t err; + struct node *np; + struct disknode *dn; - /* Cache ID's are incremented when presented to diskfs - to avoid presenting zero cache ID's. */ - id--; - - pthread_rwlock_rdlock (&nodecache_lock); - assert (id < node_cache_size); - - np = node_cache[id].np; + /* Create the new node. */ + np = diskfs_make_node_alloc (sizeof *dn); + if (np == NULL) + return ENOMEM; - if (!np) + /* Format specific data for the new node. */ + dn = diskfs_node_disknode (np); + dn->fileinfo = 0; + dn->dr = ctx->dr; + err = calculate_file_start (ctx->dr, &dn->file_start, &ctx->rr); + if (err) { - struct node_cache *c = &node_cache[id]; - struct rrip_lookup rr; - struct disknode *dn; - - pthread_rwlock_unlock (&nodecache_lock); - - rrip_lookup (node_cache[id].dr, &rr, 1); - - /* We should never cache the wrong directory entry */ - assert (!(rr.valid & VALID_CL)); - - dn = malloc (sizeof (struct disknode)); - if (!dn) - { - pthread_rwlock_unlock (&nodecache_lock); - release_rrip (&rr); - return ENOMEM; - } - dn->fileinfo = 0; - dn->dr = c->dr; - dn->file_start = c->file_start; - np = diskfs_make_node (dn); - if (!np) - { - free (dn); - pthread_rwlock_unlock (&nodecache_lock); - release_rrip (&rr); - return ENOMEM; - } - np->cache_id = id + 1; /* see above for rationale for increment */ - pthread_mutex_lock (&np->lock); - - pthread_rwlock_wrlock (&nodecache_lock); - if (c->np != NULL) - { - /* We lost a race. */ - diskfs_nput (np); - np = c->np; - goto gotit; - } - c->np = np; - diskfs_nref_light (np); - pthread_rwlock_unlock (&nodecache_lock); - - err = read_disknode (np, dn->dr, &rr); - if (!err) - *npp = np; - - release_rrip (&rr); - + diskfs_nrele (np); return err; } - gotit: - diskfs_nref (np); - pthread_rwlock_unlock (&nodecache_lock); - pthread_mutex_lock (&np->lock); *npp = np; return 0; } - /* Return Epoch-based time from a seven byte according to 9.1.5 */ char * isodate_915 (char *c, struct timespec *ts) @@ -315,6 +144,9 @@ calculate_file_start (struct dirrect *record, off_t *file_start, *file_start = rr->realfilestart; else { + if (record == NULL) + return ENOENT; + err = diskfs_catch_exception (); if (err) return err; @@ -327,90 +159,40 @@ calculate_file_start (struct dirrect *record, off_t *file_start, return 0; } - -/* Load the inode with directory entry RECORD and cached Rock-Ridge - info RR into NP. The directory entry is at OFFSET in BLOCK. */ +/* Given RECORD and RR, calculate the cache id. */ error_t -load_inode (struct node **npp, struct dirrect *record, - struct rrip_lookup *rr) +cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp) { error_t err; off_t file_start; - struct disknode *dn; - struct node *np, *tmp; - off_t id; - err = calculate_file_start (record, &file_start, rr); if (err) return err; + if (rr->valid & VALID_CL) record = rr->realdirent; - /* First check the cache */ if (use_file_start_id (record, rr)) - id = file_start << store->log2_block_size; + *idp = file_start << store->log2_block_size; else - id = (off_t) ((void *) record - (void *) disk_image); - - pthread_rwlock_rdlock (&nodecache_lock); - inode_cache_find (id, npp); - pthread_rwlock_unlock (&nodecache_lock); - if (*npp) - return 0; - - /* Create a new node */ - dn = malloc (sizeof (struct disknode)); - if (!dn) - return ENOMEM; - - dn->fileinfo = 0; - dn->dr = record; - dn->file_start = file_start; - - np = diskfs_make_node (dn); - if (!np) - { - free (dn); - return ENOMEM; - } - - pthread_mutex_lock (&np->lock); - - pthread_rwlock_wrlock (&nodecache_lock); - tmp = lookup (id); - if (tmp) - { - /* We lost a race. */ - diskfs_nput (np); - diskfs_nref (tmp); - *npp = tmp; - pthread_rwlock_unlock (&nodecache_lock); - return 0; - } - - cache_inode (np, record, rr); - pthread_rwlock_unlock (&nodecache_lock); - - err = read_disknode (np, record, rr); - *npp = np; - return err; + *idp = (off_t) ((void *) record - (void *) disk_image); + return 0; } - -/* Read stat information from the directory entry at DR and the - contents of RL. */ -static error_t -read_disknode (struct node *np, struct dirrect *dr, - struct rrip_lookup *rl) +/* The user must define this function if she wants to use the node + cache. Read stat information out of the on-disk node. */ +error_t +diskfs_user_read_node (struct node *np, struct lookup_context *ctx) { error_t err; struct stat *st = &np->dn_stat; + /* Read stat information from the directory entry at DR and the + contents of RL. */ + struct dirrect *dr = ctx->dr; + struct rrip_lookup *rl = &ctx->rr; st->st_fstype = FSTYPE_ISO9660; st->st_fsid = getpid (); - if (use_file_start_id (dr, rl)) - st->st_ino = (ino_t) np->dn->file_start << store->log2_block_size; - else - st->st_ino = (ino_t) ((void *) dr - (void *) disk_image); + st->st_ino = np->cache_id; st->st_gen = 0; st->st_rdev = 0; @@ -547,39 +329,15 @@ diskfs_node_norefs (struct node *np) free (np->dn->translator); assert (!np->dn->fileinfo); - free (np->dn); free (np); } -/* The last hard reference to a node has gone away; arrange to have - all the weak references dropped that can be. */ +/* The user must define this function if she wants to use the node + cache. The last hard reference to a node has gone away; arrange to + have all the weak references dropped that can be. */ void -diskfs_try_dropping_softrefs (struct node *np) +diskfs_user_try_dropping_softrefs (struct node *np) { - pthread_rwlock_wrlock (&nodecache_lock); - if (np->cache_id != 0) - { - assert (node_cache[np->cache_id - 1].np == np); - - /* Check if someone reacquired a reference through the - node_cache. */ - struct references result; - refcounts_references (&np->refcounts, &result); - - if (result.hard > 0) - { - /* A reference was reacquired through a hash table lookup. - It's fine, we didn't touch anything yet. */ - pthread_rwlock_unlock (&nodecache_lock); - return; - } - - node_cache[np->cache_id - 1].np = 0; - np->cache_id = 0; - diskfs_nrele_light (np); - } - pthread_rwlock_unlock (&nodecache_lock); - drop_pager_softrefs (np); } @@ -640,14 +398,6 @@ diskfs_validate_author_change (struct node *np, uid_t author) return EROFS; } -error_t -diskfs_node_iterate (error_t (*fun)(struct node *)) -{ - /* We never actually have to do anything, because this function - is only used for things that have to do with read-write media. */ - return 0; -} - void diskfs_write_disknode (struct node *np, int wait) { diff --git a/isofs/isofs.h b/isofs/isofs.h index 68a94e93..3f6690be 100644 --- a/isofs/isofs.h +++ b/isofs/isofs.h @@ -56,6 +56,15 @@ struct user_pager_info struct pager *p; }; +struct lookup_context +{ + /* The directory record. Points somewhere into the disk_image. */ + struct dirrect *dr; + + /* The results of an rrip_scan_lookup call for this node. */ + struct rrip_lookup rr; +}; + /* The physical media */ extern struct store *store; @@ -87,7 +96,9 @@ void drop_pager_softrefs (struct node *); void allow_pager_softrefs (struct node *); void create_disk_pager (void); -error_t load_inode (struct node **, struct dirrect *, struct rrip_lookup *); +/* Given RECORD and RR, calculate the cache id. */ +error_t cache_id (struct dirrect *record, struct rrip_lookup *rr, ino_t *idp); + error_t calculate_file_start (struct dirrect *, off_t *, struct rrip_lookup *); char *isodate_915 (char *, struct timespec *); diff --git a/isofs/lookup.c b/isofs/lookup.c index e51b9cb1..f375212a 100644 --- a/isofs/lookup.c +++ b/isofs/lookup.c @@ -70,12 +70,12 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, struct node **npp, struct dirstat *ds, struct protid *cred) { error_t err = 0; - struct dirrect *record; + struct lookup_context ctx; int namelen; int spec_dotdot; void *buf; void *blockaddr; - struct rrip_lookup rr; + ino_t id; if ((type == REMOVE) || (type == RENAME)) assert (npp); @@ -99,7 +99,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, blockaddr < buf + dp->dn_stat.st_size; blockaddr += logical_sector_size) { - err = dirscanblock (blockaddr, name, namelen, &record, &rr); + err = dirscanblock (blockaddr, name, namelen, &ctx.dr, &ctx.rr); if (!err) break; @@ -115,6 +115,10 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, if (err) return err; + err = cache_id (ctx.dr, &ctx.rr, &id); + if (err) + return err; + /* Load the inode */ if (namelen == 2 && name[0] == '.' && name[1] == '.') { @@ -125,7 +129,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, /* renames and removes can't get this far. */ assert (type == LOOKUP); diskfs_nput (dp); - err = load_inode (npp, record, &rr); + err = diskfs_cached_lookup_context (id, npp, &ctx); } else { @@ -133,7 +137,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, we are permanently read-only, so things are necessarily quiescent. Just be careful to honor the locking order. */ pthread_mutex_unlock (&dp->lock); - err = load_inode (npp, record, &rr); + err = diskfs_cached_lookup_context (id, npp, &ctx); pthread_mutex_lock (&dp->lock); } } @@ -143,9 +147,9 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, diskfs_nref (dp); } else - err = load_inode (npp, record, &rr); + err = diskfs_cached_lookup_context (id, npp, &ctx); - release_rrip (&rr); + release_rrip (&ctx.rr); return err; } diff --git a/isofs/main.c b/isofs/main.c index 4f531f7e..95c90fe8 100644 --- a/isofs/main.c +++ b/isofs/main.c @@ -44,20 +44,23 @@ int diskfs_maxsymlinks = 8; static void fetch_root () { - struct rrip_lookup rl; - struct dirrect *dr; + struct lookup_context ctx; + ino_t id; error_t err; - dr = (struct dirrect *) sblock->root; + ctx.dr = (struct dirrect *) sblock->root; /* First check for SUSP and all relevant extensions */ - rrip_initialize (dr); + rrip_initialize (ctx.dr); /* Now rescan the node for real */ - rrip_lookup (dr, &rl, 1); + rrip_lookup (ctx.dr, &ctx.rr, 1); + + err = cache_id (ctx.dr, &ctx.rr, &id); + assert_perror (err); /* And fetch the node. */ - err = load_inode (&diskfs_root_node, dr, &rl); + err = diskfs_cached_lookup_context (id, &diskfs_root_node, &ctx); assert_perror (err); pthread_mutex_unlock (&diskfs_root_node->lock); |