libntfs: Cache opened inodes.

edge.strict_endians
Yura Pakhuchiy 2007-09-20 14:00:55 +03:00
parent dc4e093df0
commit c0e8e211f3
5 changed files with 81 additions and 6 deletions

View File

@ -27,6 +27,7 @@
/* Forward declaration */
typedef struct _ntfs_inode ntfs_inode;
#include "list.h"
#include "types.h"
#include "layout.h"
#include "support.h"
@ -132,7 +133,7 @@ struct _ntfs_inode {
/* Below fields are valid only for base inode. */
/*
* This two fields are used to sync filename index and guaranteed to be
* These two fields are used to sync filename index and guaranteed to be
* correct, however value in index itself maybe wrong (windows itself
* do not update them properly).
*/
@ -144,12 +145,26 @@ struct _ntfs_inode {
of the unnamed data attribute for sparse or
compressed files.) */
/*
* These four fields are copy of relevant fields from
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
* attribute in the index.
*/
time_t creation_time;
time_t last_data_change_time;
time_t last_mft_change_time;
time_t last_access_time;
/* These 2 fields are used to keep track of opened inodes. */
struct list_head list_entry; /* Keep pointers to the next/prev list
entry. */
int nr_references; /* How many times this inode was
opened. We really close inode only
when this reaches zero. */
};
extern void __ntfs_inode_add_to_cache(ntfs_inode *ni);
extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);
extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);

View File

@ -44,6 +44,7 @@
/* Forward declaration */
typedef struct _ntfs_volume ntfs_volume;
#include "list.h"
#include "types.h"
#include "support.h"
#include "device.h"
@ -131,6 +132,9 @@ typedef enum {
#define NTFS_BUF_SIZE 8192
#define NTFS_INODE_CACHE_SIZE 512 /* WARNING: This should be power of 2. */
#define NTFS_INODE_CACHE_SIZE_BITS (NTFS_INODE_CACHE_SIZE - 1)
/**
* struct _ntfs_volume - structure describing an open volume in memory.
*/
@ -211,6 +215,9 @@ struct _ntfs_volume {
long nr_free_clusters; /* This two are self explaining. */
long nr_free_mft_records;
struct list_head inode_cache[NTFS_INODE_CACHE_SIZE]; /* List of opened
inodes. */
};
extern ntfs_volume *ntfs_volume_alloc(void);

View File

@ -99,6 +99,16 @@ static int __ntfs_inode_release(ntfs_inode *ni)
return 0;
}
/**
* __ntfs_inode_add_to_cache - do not use me! Only for internal library use.
*/
void __ntfs_inode_add_to_cache(ntfs_inode *ni)
{
list_add_tail(&ni->list_entry, &ni->vol->inode_cache[
ni->mft_no & NTFS_INODE_CACHE_SIZE_BITS]);
ni->nr_references = 1;
}
/**
* ntfs_inode_open - open an inode ready for access
* @vol: volume to get the inode from
@ -129,12 +139,27 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
ntfs_attr_search_ctx *ctx;
int err = 0;
STANDARD_INFORMATION *std_info;
struct list_head *pos;
ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));
if (!vol) {
errno = EINVAL;
return NULL;
}
/* Check cache, maybe this inode already opened? */
list_for_each(pos, &vol->inode_cache[MREF(mref) &
NTFS_INODE_CACHE_SIZE_BITS]) {
ntfs_inode *tmp_ni;
tmp_ni = list_entry(pos, ntfs_inode, list_entry);
if (tmp_ni->mft_no == MREF(mref)) {
ntfs_log_trace("Found this inode in cache, increment "
"reference count and return it.\n");
tmp_ni->nr_references++;
return tmp_ni;
}
}
/* Search failed. Properly open inode. */
ni = __ntfs_inode_allocate(vol);
if (!ni)
return NULL;
@ -212,6 +237,7 @@ get_size:
}
}
ntfs_attr_put_search_ctx(ctx);
__ntfs_inode_add_to_cache(ni);
return ni;
put_err_out:
if (!err)
@ -254,6 +280,18 @@ int ntfs_inode_close(ntfs_inode *ni)
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
/* Decrement number of users. If there are left then just return. */
if (ni->nr_extents != -1) {
ni->nr_references--;
if (ni->nr_references) {
ntfs_log_trace("There are %d more references left to "
"this inode.\n",
ni->nr_references);
return 0;
} else
ntfs_log_trace("There are no more references left to "
"this inode.\n");
}
/* If we have dirty metadata, write it out. */
if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
if (ntfs_inode_sync(ni)) {
@ -312,9 +350,12 @@ int ntfs_inode_close(ntfs_inode *ni)
break;
}
if (i != -1)
ntfs_log_debug("Extent inode was not attached to base inode! "
"Weird! Continuing regardless.\n");
ntfs_log_debug("Extent inode was not attached to base "
"inode! Continuing regardless.\n");
}
/* Remove inode from the list of opened inodes. */
if (ni->nr_extents != -1)
list_del(&ni->list_entry);
return __ntfs_inode_release(ni);
}

View File

@ -1460,9 +1460,12 @@ mft_rec_already_initialized:
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = time(NULL);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
if (!base_ni) {
/* Update the default mft allocation position if it was used. */
vol->mft_data_pos = bit + 1;
/* Add inode to cache. */
__ntfs_inode_add_to_cache(ni);
}
/* Return the opened, allocated inode of the allocated mft record. */
ntfs_log_debug("Returning opened, allocated %sinode 0x%llx.\n",
base_ni ? "extent " : "", (long long)bit);

View File

@ -76,7 +76,15 @@
*/
ntfs_volume *ntfs_volume_alloc(void)
{
return calloc(1, sizeof(ntfs_volume));
ntfs_volume *vol;
int i;
vol = calloc(1, sizeof(ntfs_volume));
if (vol) {
for (i = 0; i < NTFS_INODE_CACHE_SIZE; i++)
INIT_LIST_HEAD(&vol->inode_cache[i]);
}
return vol;
}
/**
@ -162,6 +170,7 @@ static int ntfs_mft_load(ntfs_volume *vol)
}
vol->mft_ni->mft_no = 0;
vol->mft_ni->mrec = mb;
__ntfs_inode_add_to_cache(vol->mft_ni);
/* Can't use any of the higher level functions yet! */
l = ntfs_mst_pread(vol->dev, vol->mft_lcn << vol->cluster_size_bits, 1,
vol->mft_record_size, mb);