Skip to contentSkip to conversation

Staging: memrar: Moved memrar_allocator struct to memrar_allocator.c

PATCH In review Henri Häkkinen 4 participants 6 messages Jun 24, 2010 Staging

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 Staging: memrar: Moved memrar_allocator struct to memrar_allocator.c

Forward declared memrar_allocator structure in memrar_allocator.h and moved the definition to memrar_allocator.c. Implemented memrar_allocator_capacity() and memrar_allocator_largest_free_area().

---
 drivers/staging/memrar/memrar_allocator.c |   43 ++++++++++++++++++++++++++
 drivers/staging/memrar/memrar_allocator.h |   48 ++++++++++++-----------------
 2 files changed, 63 insertions(+), 28 deletions(-)
drivers/staging/memrar/memrar_allocator.c +43 -0
index a4f8c58..cb74e3c 100644
@@ -41,6 +41,36 @@
 #include <linux/kernel.h>
 
 
+/**
+ * struct memrar_allocator - encapsulation of the memory allocator state
+ * @lock:		Lock used to synchronize access to the memory
+ *			allocator state.
+ * @base:		Base (start) address of the allocator memory
+ *			space.
+ * @capacity:		Size of the allocator memory space in bytes.
+ * @block_size:		The size in bytes of individual blocks within
+ *			the allocator memory space.
+ * @largest_free_area:	Largest free area of memory in the allocator
+ *			in bytes.
+ * @allocated_list:	List of allocated memory block address
+ *			ranges.
+ * @free_list:		List of free address ranges.
+ *
+ * This structure contains all memory allocator state, including the
+ * base address, capacity, free list, lock, etc.
+ */
+struct memrar_allocator {
+/* private: internal use only */
+	struct mutex lock;
+	unsigned long base;
+	size_t capacity;
+	size_t block_size;
+	size_t largest_free_area;
+	struct memrar_address_ranges allocated_list;
+	struct memrar_address_ranges free_list;
+};
+
+
 struct memrar_allocator *memrar_create_allocator(unsigned long base,
 						 size_t capacity,
 						 size_t block_size)
@@ -423,6 +453,19 @@ exit_memrar_free:
 	return 0;
 }
 
+size_t memrar_allocator_largest_free_area(struct memrar_allocator *allocator)
+{
+	if (allocator == NULL)
+		return 0;
+	return allocator->largest_free_area;
+}
+
+size_t memrar_allocator_capacity(struct memrar_allocator *allocator)
+{
+	if (allocator == NULL)
+		return 0;
+	return allocator->capacity;
+}
 
 
 /*
drivers/staging/memrar/memrar_allocator.h +20 -28

60 lines not on this page · raw message

Signature · 1 line
1.7.1
#1 lore raw

PATCH 2/2 Staging: memrar: Fixed memrar_handler.c

Fixed memrar_handler.c to use the new memrar_allocator API. Removed the corresponding issue from TODO. Implemented locking in memrar_allocator_largest_free_area().

---
 drivers/staging/memrar/TODO               |   16 +---------------
 drivers/staging/memrar/memrar_allocator.c |   12 +++++++++---
 drivers/staging/memrar/memrar_handler.c   |   13 ++++---------
 3 files changed, 14 insertions(+), 27 deletions(-)
drivers/staging/memrar/TODO +1 -15
index 0087447..9659aab 100644
@@ -16,21 +16,7 @@ memrar_allocator.[ch]
 ---------------------
 1. Address potential fragmentation issues with the memrar_allocator.
 
-2. Hide struct memrar_allocator details/fields.  They need not be
-   exposed to the user.
-     a. Forward declare struct memrar_allocator.
-     b. Move all three struct definitions to `memrar_allocator.c'
-        source file.
-     c. Add a memrar_allocator_largest_free_area() function, or
-        something like that to get access to the value of the struct
-        memrar_allocator "largest_free_area" field.  This allows the
-        struct memrar_allocator fields to be completely hidden from
-        the user.  The memrar_handler code really only needs this for
-        statistic gathering on-demand.
-     d. Do the same for the "capacity" field as the
-        "largest_free_area" field.
-
-3. Move memrar_allocator.* to kernel `lib' directory since it is HW
+2. Move memrar_allocator.* to kernel `lib' directory since it is HW
    neutral.
      a. Alternatively, use lib/genalloc.c instead.
      b. A kernel port of Doug Lea's malloc() implementation may also
drivers/staging/memrar/memrar_allocator.c +9 -3
index cb74e3c..924eab3 100644
@@ -455,9 +455,15 @@ exit_memrar_free:
 
 size_t memrar_allocator_largest_free_area(struct memrar_allocator *allocator)
 {
-	if (allocator == NULL)
-		return 0;
-	return allocator->largest_free_area;
+	size_t tmp = 0;
+
+	if (allocator != NULL) {
+		mutex_lock(&allocator->lock);
+		tmp = allocator->largest_free_area;
+		mutex_unlock(&allocator->lock);
+	}
+
+	return tmp;
 }
 
 size_t memrar_allocator_capacity(struct memrar_allocator *allocator)
drivers/staging/memrar/memrar_handler.c +4 -9
index 22208cd..a652593 100644
@@ -351,7 +351,8 @@ static int memrar_init_rar_resources(int rarnum, char const *devname)
 		devname, rarnum, (unsigned long) low, (unsigned long) high);
 
 	pr_info("%s: BRAR[%d] size = %zu KiB\n",
-			devname, rarnum, rar->allocator->capacity / 1024);
+			devname, rarnum,
+			memrar_allocator_capacity(rar->allocator) / 1024);
 
 	rar->allocated = 1;
 	return 0;
@@ -542,15 +543,9 @@ static long memrar_get_stat(struct RAR_stat *r)
 
 	BUG_ON(allocator == NULL);
 
-	/*
-	 * Allocator capacity doesn't change over time.  No
-	 * need to synchronize.
-	 */
-	r->capacity = allocator->capacity;
+	r->capacity = memrar_allocator_capacity(allocator);
+	r->largest_block_size = memrar_allocator_largest_free_area(allocator);
 
-	mutex_lock(&allocator->lock);
-	r->largest_block_size = allocator->largest_free_area;
-	mutex_unlock(&allocator->lock);
 	return 0;
 }
 
Signature · 1 line
1.7.1
#2 lore raw

Re: [PATCH 2/2] Staging: memrar: Fixed memrar_handler.c

drivers/staging/memrar/memrar_allocator.c exit_memrar_free: · line 463

Quoted 11 lines

size_t memrar_allocator_largest_free_area(struct memrar_allocator *allocator) {

drivers/staging/memrar/memrar_allocator.c +6 -3
-	if (allocator == NULL)
-		return 0;
-	return allocator->largest_free_area;
+	size_t tmp = 0;
+
+	if (allocator != NULL) {
+		mutex_lock(&allocator->lock);
+		tmp = allocator->largest_free_area;
+		mutex_unlock(&allocator->lock);

This doesn't seem to make any sense (in either version). The moment you drop the lock the value in "tmp" becomes stale as the allocator could change it. ?

#3 lore raw

RE: [PATCH 2/2] Staging: memrar: Fixed memrar_handler.c

Hi Alan,

Quoted 16 lines
Quoted 1 line

size_t memrar_allocator_largest_free_area(struct memrar_allocator

*allocator)

drivers/staging/memrar/memrar_allocator.c exit_memrar_free: · line 463

Quoted 10 lines

{

drivers/staging/memrar/memrar_allocator.c +6 -3
-	if (allocator == NULL)
-		return 0;
-	return allocator->largest_free_area;
+	size_t tmp = 0;
+
+	if (allocator != NULL) {
+		mutex_lock(&allocator->lock);
+		tmp = allocator->largest_free_area;
+		mutex_unlock(&allocator->lock);

This doesn't seem to make any sense (in either version). The moment you drop the lock the value in "tmp" becomes stale as the allocator could change it. ?

Agreed, but I don't think there's anything we can do about it with the current interface. We will always have a time-of-check-time-of-use TOCTOU race with this function as it stands. I pointed out the issue in my response to Henri as well, but I focused more on hiding the lock from the caller. The TOCTOU race exists in both versions, i.e. the old code and proposed new code. The value returned from this function in this particular case will ultimately be passed to the user when the user issues a RAR_HANDLER_STAT ioctl to the /dev/memrar device. For the most part, this function is only used for debugging. It is not needed for general operation of the memrar_allocator or the memrar_handler (/dev/memrar).

-Ossama

#4 lore raw
In reply to Henri Häkkinen

drivers/staging/memrar/memrar_allocator.c exit_memrar_free: · line 461

Quoted 6 lines
drivers/staging/memrar/memrar_allocator.c +6 -0
+size_t memrar_allocator_largest_free_area(struct memrar_allocator *allocator)
+{
+	if (allocator == NULL)
+		return 0;
+	return allocator->largest_free_area;
+}

static ?

#5 lore raw
Quoted 8 lines · Alan Cox

drivers/staging/memrar/memrar_allocator.c exit_memrar_free: · line 461

Quoted 6 lines
drivers/staging/memrar/memrar_allocator.c +6 -0
+size_t memrar_allocator_largest_free_area(struct memrar_allocator *allocator)
+{
+	if (allocator == NULL)
+		return 0;
+	return allocator->largest_free_area;
+}

static ?

The entire point of these two patches was to hide the memrar_allocator structure by moving it to memrar_allocator.c, forward declaring it in memrar_allocator.h and then providing accessor functions memrar_allocator_largest_free_area and memrar_allocator_capacity (this was the #2 issue for memrar_allocator.[ch] in the TODO file). By defining memrar_allocator_largest_free_area function as static (this is what you mean, right?) would make no sense.