libntfs: Cache opened inodes.
parent
dc4e093df0
commit
c0e8e211f3
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue