Cached looked-up inodes for subsequent use

This commit is contained in:
jpandre 2009-12-18 08:27:05 +00:00
parent d75f69d80e
commit 6072a95591
5 changed files with 180 additions and 2 deletions

View File

@ -61,6 +61,9 @@ extern ntfschar NTFS_INDEX_R[3];
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
const ntfschar *uname, const int uname_len);
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
u64 inum);
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
const char *pathname);

View File

@ -24,10 +24,13 @@
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */
#define CACHE_LOOKUP_SIZE 64 /* lookup cache, zero or >= 3 and not too big */
#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */
#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
#define FULLCOLLATE 1
#endif /* defined _NTFS_PARAM_H */

View File

@ -235,6 +235,9 @@ struct _ntfs_volume {
#if CACHE_NIDATA_SIZE
struct CACHE_HEADER *nidata_cache;
#endif
#if CACHE_LOOKUP_SIZE
struct CACHE_HEADER *lookup_cache;
#endif
#if CACHE_SECURID_SIZE
struct CACHE_HEADER *securid_cache;
#endif

View File

@ -571,6 +571,13 @@ void ntfs_create_lru_caches(ntfs_volume *vol)
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
sizeof(struct CACHED_NIDATA),
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
#endif
#if CACHE_LOOKUP_SIZE
/* lookup cache */
vol->lookup_cache = ntfs_create_cache("lookup",
(cache_free)NULL, ntfs_dir_lookup_hash,
sizeof(struct CACHED_LOOKUP),
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
#endif
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
@ -591,6 +598,9 @@ void ntfs_free_lru_caches(ntfs_volume *vol)
#endif
#if CACHE_NIDATA_SIZE
ntfs_free_cache(vol->nidata_cache);
#endif
#if CACHE_LOOKUP_SIZE
ntfs_free_cache(vol->lookup_cache);
#endif
ntfs_free_cache(vol->securid_cache);
#if CACHE_LEGACY_SIZE

View File

@ -158,6 +158,65 @@ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached,
#endif
#if CACHE_LOOKUP_SIZE
/*
* File name comparing for entering/fetching from lookup cache
*/
static int lookup_cache_compare(const struct CACHED_GENERIC *cached,
const struct CACHED_GENERIC *wanted)
{
const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached;
const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted;
return (!c->name
|| (c->parent != w->parent)
|| (c->namesize != w->namesize)
|| memcmp(c->name, w->name, c->namesize));
}
/*
* Inode number comparing for invalidating lookup cache
*
* All entries with designated inode number are invalidated
*
* Only use associated with a CACHE_NOHASH flag
*/
static int lookup_cache_inv_compare(const struct CACHED_GENERIC *cached,
const struct CACHED_GENERIC *wanted)
{
const struct CACHED_LOOKUP *c = (const struct CACHED_LOOKUP*) cached;
const struct CACHED_LOOKUP *w = (const struct CACHED_LOOKUP*) wanted;
return (!c->name
|| (c->parent != w->parent)
|| (MREF(c->inum) != MREF(w->inum)));
}
/*
* Lookup hashing
*
* Based on first, second and and last char
*/
int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached)
{
const unsigned char *name;
int count;
unsigned int val;
name = (const unsigned char*)cached->variable;
count = cached->varsize;
if (!name || !count) {
ntfs_log_error("Bad lookup cache entry\n");
return (-1);
}
val = (name[0] << 2) + (name[1] << 1) + name[count - 1] + count;
return (val % (2*CACHE_LOOKUP_SIZE));
}
#endif
/**
* ntfs_inode_lookup_by_name - find an inode in a directory given its name
* @dir_ni: ntfs inode of the directory in which to search for the name
@ -183,8 +242,8 @@ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached,
* If the volume is mounted with the case sensitive flag set, then we only
* allow exact matches.
*/
u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
const int uname_len)
u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
const ntfschar *uname, const int uname_len)
{
VCN vcn;
u64 mref = 0;
@ -472,6 +531,94 @@ close_err_out:
goto eo_put_err_out;
}
/*
* Lookup a file in a directory from its UTF-8 name
*
* The name is first fetched from cache if one is defined
*
* Returns the inode number
* or -1 if not possible (errno tells why)
*/
u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name)
{
int uname_len;
ntfschar *uname = (ntfschar*)NULL;
u64 inum;
#if CACHE_LOOKUP_SIZE
struct CACHED_LOOKUP item;
struct CACHED_LOOKUP *cached;
/*
* fetch inode from cache
*/
if (dir_ni->vol->lookup_cache) {
item.name = name;
item.namesize = strlen(name) + 1;
item.parent = dir_ni->mft_no;
cached = (struct CACHED_LOOKUP*)ntfs_fetch_cache(
dir_ni->vol->lookup_cache, GENERIC(&item),
lookup_cache_compare);
if (cached) {
inum = cached->inum;
if (inum == (u64)-1)
errno = ENOENT;
} else {
/* Generate unicode name. */
uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len >= 0) {
inum = ntfs_inode_lookup_by_name(dir_ni,
uname, uname_len);
item.inum = inum;
/* enter into cache, even if not found */
ntfs_enter_cache(dir_ni->vol->lookup_cache,
GENERIC(&item),
lookup_cache_compare);
free(uname);
} else
inum = (s64)-1;
}
} else
#endif
{
/* Generate unicode name. */
uname_len = ntfs_mbstoucs(name, &uname);
if (uname_len >= 0)
inum = ntfs_inode_lookup_by_name(dir_ni,
uname, uname_len);
else
inum = (s64)-1;
}
return (inum);
}
/*
* Update a cache lookup record when a name has been defined
*
* The UTF-8 name is required
*/
void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name, u64 inum)
{
#if CACHE_LOOKUP_SIZE
struct CACHED_LOOKUP item;
struct CACHED_LOOKUP *cached;
if (dir_ni->vol->lookup_cache) {
item.name = name;
item.namesize = strlen(name) + 1;
item.parent = dir_ni->mft_no;
item.inum = inum;
cached = (struct CACHED_LOOKUP*)ntfs_enter_cache(
dir_ni->vol->lookup_cache,
GENERIC(&item), lookup_cache_compare);
if (cached)
cached->inum = inum;
}
#endif
}
/**
* ntfs_pathname_to_inode - Find the inode which represents the given pathname
* @vol: An ntfs volume obtained from ntfs_mount
@ -1557,6 +1704,9 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
u64 inum = (u64)-1;
int count;
#endif
#if CACHE_LOOKUP_SIZE
struct CACHED_LOOKUP lkitem;
#endif
ntfs_log_trace("Entering.\n");
@ -1670,6 +1820,15 @@ search:
* case there are no reference to this inode left, so we should free all
* non-resident attributes and mark all MFT record as not in use.
*/
#if CACHE_LOOKUP_SIZE
/* invalidate entry in lookup cache */
lkitem.name = (const char*)NULL;
lkitem.namesize = 0;
lkitem.inum = ni->mft_no;
lkitem.parent = dir_ni->mft_no;
ntfs_invalidate_cache(vol->lookup_cache, GENERIC(&lkitem),
lookup_cache_inv_compare, CACHE_NOHASH);
#endif
#if CACHE_INODE_SIZE
inum = ni->mft_no;
if (pathname) {