libvtreefs: dynamically allocate long inode names

Extended by David van Moolenbroek to continue using static buffers
for short inode names, so as to prevent important file system
services such as procfs from running out of memory at runtime.

Change-Id: I6f841741ee9944fc87dbdb78b5cdaa2abee9da76
This commit is contained in:
Cristiano Giuffrida 2014-12-31 02:15:44 +01:00 committed by David van Moolenbroek
parent 5a7def9a94
commit c21aa858e2
5 changed files with 30 additions and 8 deletions

View file

@ -7,8 +7,9 @@ typedef void *cbdata_t;
#define NO_INDEX ((index_t) -1)
/* Maximum file name length, excluding terminating null character. It is set
* to a low value to limit memory usage, but can be changed to any value.
/* Maximum file name length, excluding terminating null character, for which
* the name will be allocated statically. Longer names will be allocated
* dynamically, and should not be used for system-critical file systems.
*/
#define PNAME_MAX 24

View file

@ -70,6 +70,7 @@ init_inodes(unsigned int inodes, struct inode_stat * stat,
for (i = 1; i < nr_inodes; i++) {
node = &inode[i];
node->i_num = i;
node->i_name = NULL;
node->i_parent = NULL;
node->i_count = 0;
TAILQ_INIT(&node->i_children);
@ -186,12 +187,13 @@ add_inode(struct inode * parent, const char * name, index_t index,
cbdata_t cbdata)
{
struct inode *newnode;
char *newname;
int slot;
CHECK_INODE(parent);
assert(S_ISDIR(parent->i_stat.mode));
assert(!(parent->i_flags & I_DELETED));
assert(strlen(name) <= PNAME_MAX);
assert(strlen(name) <= NAME_MAX);
assert(index >= 0 || index == NO_INDEX);
assert(stat != NULL);
assert(nr_indexed_entries >= 0);
@ -204,18 +206,28 @@ add_inode(struct inode * parent, const char * name, index_t index,
assert(!TAILQ_EMPTY(&unused_inodes));
newnode = TAILQ_FIRST(&unused_inodes);
/* Use the static name buffer if the name is short enough. Otherwise,
* allocate heap memory for the name.
*/
newname = newnode->i_namebuf;
if (strlen(name) > PNAME_MAX &&
(newname = malloc(strlen(name) + 1)) == NULL)
return NULL;
TAILQ_REMOVE(&unused_inodes, newnode, i_unused);
assert(newnode->i_count == 0);
/* Copy the relevant data to the inode. */
newnode->i_parent = parent;
newnode->i_name = newname;
newnode->i_flags = 0;
newnode->i_index = index;
newnode->i_stat = *stat;
newnode->i_indexed = nr_indexed_entries;
newnode->i_cbdata = cbdata;
strlcpy(newnode->i_name, name, sizeof(newnode->i_name));
strcpy(newnode->i_name, name);
/* Clear the extra data for this inode, if present. */
clear_inode_extra(newnode);
@ -255,6 +267,8 @@ get_inode_name(const struct inode * node)
{
CHECK_INODE(node);
assert(!(node->i_flags & I_DELETED));
assert(node->i_name != NULL);
return node->i_name;
}
@ -394,7 +408,7 @@ get_inode_by_name(const struct inode * parent, const char * name)
int slot;
CHECK_INODE(parent);
assert(strlen(name) <= PNAME_MAX);
assert(strlen(name) <= NAME_MAX);
assert(S_ISDIR(parent->i_stat.mode));
/* Get the hash value, and search for the inode. */
@ -547,6 +561,12 @@ delete_inode(struct inode * node)
if (node->i_index != NO_INDEX)
LIST_REMOVE(node, i_hindex);
/* Free the name if allocated dynamically. */
assert(node->i_name != NULL);
if (node->i_name != node->i_namebuf)
free(node->i_name);
node->i_name = NULL;
node->i_flags |= I_DELETED;
/*

View file

@ -22,7 +22,8 @@ struct inode {
/* Inode metadata */
struct inode_stat i_stat; /* POSIX attributes */
char i_name[PNAME_MAX + 1]; /* name of the inode in the parent */
char i_namebuf[PNAME_MAX + 1]; /* buffer for static (short) names */
char *i_name; /* name of the inode in the parent */
unsigned int i_count; /* reference count */
index_t i_index; /* index number in parent / NO_INDEX */
int i_indexed; /* number of indexed entries */

View file

@ -18,7 +18,7 @@ fs_lookup(ino_t dir_nr, char * name, struct fsdriver_node * node_details,
if (!S_ISDIR(node->i_stat.mode))
return ENOTDIR;
if (strlen(name) > PNAME_MAX)
if (strlen(name) > NAME_MAX)
return ENAMETOOLONG;
if (!strcmp(name, ".")) {

View file

@ -116,7 +116,7 @@ fs_statvfs(struct statvfs * buf)
{
buf->f_flag = ST_NOTRUNC;
buf->f_namemax = PNAME_MAX;
buf->f_namemax = NAME_MAX;
return OK;
}