From: Cristiano Giuffrida Date: Wed, 31 Dec 2014 01:15:44 +0000 (+0100) Subject: libvtreefs: dynamically allocate long inode names X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=c21aa858e206a580693d3705485ebfc26ae29170;p=minix.git 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 --- diff --git a/minix/include/minix/vtreefs.h b/minix/include/minix/vtreefs.h index 00e6db0d3..7c1d6ed22 100644 --- a/minix/include/minix/vtreefs.h +++ b/minix/include/minix/vtreefs.h @@ -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 diff --git a/minix/lib/libvtreefs/inode.c b/minix/lib/libvtreefs/inode.c index 3b40f8cb0..6ad4a4bee 100644 --- a/minix/lib/libvtreefs/inode.c +++ b/minix/lib/libvtreefs/inode.c @@ -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; /* diff --git a/minix/lib/libvtreefs/inode.h b/minix/lib/libvtreefs/inode.h index 01716edd8..3340cca32 100644 --- a/minix/lib/libvtreefs/inode.h +++ b/minix/lib/libvtreefs/inode.h @@ -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 */ diff --git a/minix/lib/libvtreefs/path.c b/minix/lib/libvtreefs/path.c index 23b8d68c8..7d604306a 100644 --- a/minix/lib/libvtreefs/path.c +++ b/minix/lib/libvtreefs/path.c @@ -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, ".")) { diff --git a/minix/lib/libvtreefs/stadir.c b/minix/lib/libvtreefs/stadir.c index 5a4a5e5c8..bb15049db 100644 --- a/minix/lib/libvtreefs/stadir.c +++ b/minix/lib/libvtreefs/stadir.c @@ -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; }