オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Annotation of /trunk/1.7.x/ccs-patch/security/ccsecurity/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1054 - (hide annotations) (download) (as text)
Mon Mar 24 09:38:11 2008 UTC (16 years, 2 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/realpath.c
File MIME type: text/x-csrc
File size: 17349 byte(s)


1 kumaneko 111 /*
2     * fs/realpath.c
3     *
4     * Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO.
5     *
6 kumaneko 856 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 kumaneko 111 *
8 kumaneko 1052 * Version: 1.6.0-pre 2008/03/24
9 kumaneko 111 *
10     * This file is applicable to both 2.4.30 and 2.6.11 and later.
11     * See README.ccs for ChangeLog.
12     *
13     */
14     #include <linux/string.h>
15     #include <linux/mm.h>
16     #include <linux/utime.h>
17     #include <linux/file.h>
18     #include <linux/smp_lock.h>
19     #include <linux/module.h>
20     #include <linux/slab.h>
21     #include <asm/uaccess.h>
22     #include <asm/atomic.h>
23     #include <linux/version.h>
24 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
25 kumaneko 111 #include <linux/namei.h>
26     #include <linux/mount.h>
27     static const int lookup_flags = LOOKUP_FOLLOW;
28     #else
29     static const int lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
30     #endif
31     #include <linux/realpath.h>
32     #include <linux/proc_fs.h>
33     #include <linux/ccs_common.h>
34    
35 kumaneko 1052 /**
36     * get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
37 kumaneko 111 *
38 kumaneko 1052 * @dentry: Pointer to "struct dentry".
39     * @vfsmnt: Pointer to "struct vfsmount".
40     * @buffer: Pointer to buffer to return value in.
41     * @buflen: Sizeof @buffer.
42     *
43     * Returns 0 on success, -ENOMEM otherwise.
44     *
45     * Caller holds the dcache_lock and vfsmount_lock .
46 kumaneko 111 * Based on __d_path() in fs/dcache.c
47     *
48     * If dentry is a directory, trailing '/' is appended.
49 kumaneko 1052 * Characters out of 0x20 < c < 0x7F range are converted to
50     * \ooo style octal string.
51 kumaneko 111 * Character \ is converted to \\ string.
52     */
53 kumaneko 1052 static int get_absolute_path(struct dentry *dentry, struct vfsmount *vfsmnt,
54     char *buffer, int buflen)
55 kumaneko 111 {
56 kumaneko 1052 /***** CRITICAL SECTION START *****/
57 kumaneko 111 char *start = buffer;
58     char *end = buffer + buflen;
59 kumaneko 621 bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
60 kumaneko 111
61 kumaneko 1052 if (buflen < 256)
62     goto out;
63 kumaneko 111
64     *--end = '\0';
65     buflen--;
66    
67     for (;;) {
68     struct dentry *parent;
69    
70     if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
71     /* Global root? */
72 kumaneko 1052 if (vfsmnt->mnt_parent == vfsmnt)
73 kumaneko 111 break;
74     dentry = vfsmnt->mnt_mountpoint;
75     vfsmnt = vfsmnt->mnt_parent;
76     continue;
77     }
78     if (is_dir) {
79 kumaneko 1052 is_dir = false;
80     *--end = '/';
81     buflen--;
82 kumaneko 111 }
83     parent = dentry->d_parent;
84     {
85     const char *sp = dentry->d_name.name;
86     const char *cp = sp + dentry->d_name.len - 1;
87     unsigned char c;
88    
89 kumaneko 1052 /*
90     * Exception: Use /proc/self/ rather than
91     * /proc/\$/ for current process.
92     */
93     if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' &&
94     parent->d_sb &&
95     parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
96 kumaneko 111 char *ep;
97 kumaneko 1052 const pid_t pid
98     = (pid_t) simple_strtoul(sp, &ep, 10);
99     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
100     if (!*ep && pid == current->tgid) {
101     sp = "self";
102     cp = sp + 3;
103     }
104 kumaneko 111 #else
105 kumaneko 1052 if (!*ep && pid == current->pid) {
106     sp = "self";
107     cp = sp + 3;
108     }
109 kumaneko 111 #endif
110     }
111    
112     while (sp <= cp) {
113 kumaneko 1052 c = *(unsigned char *) cp;
114 kumaneko 111 if (c == '\\') {
115     buflen -= 2;
116 kumaneko 1052 if (buflen < 0)
117     goto out;
118 kumaneko 111 *--end = '\\';
119     *--end = '\\';
120     } else if (c > ' ' && c < 127) {
121 kumaneko 1052 if (--buflen < 0)
122     goto out;
123 kumaneko 111 *--end = (char) c;
124     } else {
125     buflen -= 4;
126 kumaneko 1052 if (buflen < 0)
127     goto out;
128 kumaneko 111 *--end = (c & 7) + '0';
129     *--end = ((c >> 3) & 7) + '0';
130     *--end = (c >> 6) + '0';
131     *--end = '\\';
132     }
133     cp--;
134     }
135 kumaneko 1052 if (--buflen < 0)
136     goto out;
137 kumaneko 111 *--end = '/';
138     }
139     dentry = parent;
140     }
141 kumaneko 1052 if (*end == '/') {
142     buflen++;
143     end++;
144     }
145 kumaneko 111 {
146     const char *sp = dentry->d_name.name;
147     const char *cp = sp + dentry->d_name.len - 1;
148     unsigned char c;
149     while (sp <= cp) {
150 kumaneko 1052 c = *(unsigned char *) cp;
151 kumaneko 111 if (c == '\\') {
152     buflen -= 2;
153 kumaneko 1052 if (buflen < 0)
154     goto out;
155 kumaneko 111 *--end = '\\';
156     *--end = '\\';
157     } else if (c > ' ' && c < 127) {
158 kumaneko 1052 if (--buflen < 0)
159     goto out;
160 kumaneko 111 *--end = (char) c;
161     } else {
162     buflen -= 4;
163 kumaneko 1052 if (buflen < 0)
164     goto out;
165 kumaneko 111 *--end = (c & 7) + '0';
166     *--end = ((c >> 3) & 7) + '0';
167     *--end = (c >> 6) + '0';
168     *--end = '\\';
169     }
170     cp--;
171     }
172     }
173     /* Move the pathname to the top of the buffer. */
174     memmove(start, end, strlen(end) + 1);
175     return 0;
176     out:
177     return -ENOMEM;
178 kumaneko 1052 /***** CRITICAL SECTION END *****/
179 kumaneko 111 }
180    
181 kumaneko 1052 /**
182 kumaneko 1054 * ccs_realpath_from_dentry2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
183 kumaneko 1052 *
184     * @dentry: Pointer to "struct dentry".
185     * @mnt: Pointer to "struct vfsmount".
186     * @newname: Pointer to buffer to return value in.
187     * @newname_len: Size of @newname .
188     *
189     * Returns 0 on success, negative value otherwise.
190     */
191     int ccs_realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt,
192     char *newname, int newname_len)
193 kumaneko 111 {
194     int error;
195     struct dentry *d_dentry;
196     struct vfsmount *d_mnt;
197 kumaneko 1052 if (!dentry || !mnt || !newname || newname_len <= 0)
198     return -EINVAL;
199 kumaneko 111 d_dentry = dget(dentry);
200     d_mnt = mntget(mnt);
201     /***** CRITICAL SECTION START *****/
202     spin_lock(&dcache_lock);
203 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
204     spin_lock(&vfsmount_lock);
205     #endif
206     error = get_absolute_path(d_dentry, d_mnt, newname, newname_len);
207     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
208     spin_unlock(&vfsmount_lock);
209     #endif
210 kumaneko 111 spin_unlock(&dcache_lock);
211     /***** CRITICAL SECTION END *****/
212     dput(d_dentry);
213     mntput(d_mnt);
214     return error;
215     }
216    
217 kumaneko 1052 /**
218 kumaneko 1054 * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname but ignores chroot'ed root.
219 kumaneko 1052 *
220     * @dentry: Pointer to "struct dentry".
221     * @mnt: Pointer to "struct vfsmount".
222     *
223     * Returns the realpath of the given @dentry and @mnt on success,
224     * NULL otherwise.
225     *
226     * These functions use ccs_alloc(), so caller must ccs_free()
227     * if these functions didn't return NULL.
228     */
229     char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
230 kumaneko 111 {
231 kumaneko 1031 char *buf = ccs_alloc(sizeof(struct ccs_page_buffer));
232 kumaneko 1052 if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,
233     CCS_MAX_PATHNAME_LEN - 1) == 0)
234     return buf;
235 kumaneko 111 ccs_free(buf);
236     return NULL;
237     }
238    
239 kumaneko 1052 /**
240     * ccs_realpath - Get realpath of a pathname.
241     *
242     * @pathname: The pathname to solve.
243     *
244     * Returns the realpath of @pathname on success, NULL otherwise.
245     */
246     char *ccs_realpath(const char *pathname)
247 kumaneko 111 {
248     struct nameidata nd;
249     if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) {
250 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
251     char *buf = ccs_realpath_from_dentry(nd.path.dentry,
252     nd.path.mnt);
253 kumaneko 990 path_put(&nd.path);
254     #else
255 kumaneko 1052 char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
256 kumaneko 111 path_release(&nd);
257 kumaneko 990 #endif
258 kumaneko 111 return buf;
259     }
260     return NULL;
261     }
262    
263 kumaneko 1052 /**
264     * ccs_realpath_nofollow - Get realpath of a pathname.
265     *
266     * @pathname: The pathname to solve.
267     *
268     * Returns the realpath of @pathname on success, NULL otherwise.
269     */
270     char *ccs_realpath_nofollow(const char *pathname)
271 kumaneko 111 {
272     struct nameidata nd;
273 kumaneko 1052 if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW,
274     &nd) == 0) {
275     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
276     char *buf = ccs_realpath_from_dentry(nd.path.dentry,
277     nd.path.mnt);
278 kumaneko 990 path_put(&nd.path);
279     #else
280 kumaneko 1052 char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
281 kumaneko 111 path_release(&nd);
282 kumaneko 990 #endif
283 kumaneko 111 return buf;
284     }
285     return NULL;
286     }
287    
288 kumaneko 1052 /**
289 kumaneko 1054 * round_up - Round up an integer so that the returned pointers are appropriately aligned.
290 kumaneko 1052 *
291     * @size: Size in bytes.
292     *
293     * Returns rounded value of @size.
294     *
295     * FIXME: Are there more requirements that is needed for assigning value
296     * atomically?
297 kumaneko 111 */
298 kumaneko 1052 static inline unsigned int round_up(const unsigned int size)
299     {
300     if (sizeof(void *) >= sizeof(long))
301     return ((size + sizeof(void *) - 1)
302     / sizeof(void *)) * sizeof(void *);
303     else
304     return ((size + sizeof(long) - 1)
305     / sizeof(long)) * sizeof(long);
306 kumaneko 111 }
307    
308 kumaneko 1052 static unsigned int allocated_memory_for_elements;
309 kumaneko 111
310 kumaneko 1052 /**
311 kumaneko 1054 * ccs_get_memory_used_for_elements - Get memory used for keeping ACL structures.
312 kumaneko 1052 *
313     * Returns memory used for keeping ACL structures.
314     */
315     unsigned int ccs_get_memory_used_for_elements(void)
316 kumaneko 111 {
317     return allocated_memory_for_elements;
318     }
319    
320 kumaneko 1052 /**
321     * ccs_alloc_element - Allocate permanent memory for structures.
322     *
323     * @size: Size in bytes.
324     *
325     * Returns pointer to allocated memory on success, NULL otherwise.
326     *
327     * The RAM is chunked, so NEVER try to kfree() the returned pointer.
328     */
329     void *ccs_alloc_element(const unsigned int size)
330 kumaneko 111 {
331 kumaneko 652 static DEFINE_MUTEX(lock);
332 kumaneko 1052 static char *buf;
333 kumaneko 111 static unsigned int buf_used_len = PAGE_SIZE;
334     char *ptr = NULL;
335 kumaneko 1052 const unsigned int word_aligned_size = round_up(size);
336     if (word_aligned_size > PAGE_SIZE)
337     return NULL;
338 kumaneko 652 mutex_lock(&lock);
339 kumaneko 111 if (buf_used_len + word_aligned_size > PAGE_SIZE) {
340 kumaneko 1052 ptr = kzalloc(PAGE_SIZE, GFP_KERNEL);
341     if (!ptr) {
342     printk(KERN_WARNING "ERROR: Out of memory "
343     "for ccs_alloc_element().\n");
344     if (!sbin_init_started)
345     panic("MAC Initialization failed.\n");
346 kumaneko 111 } else {
347     buf = ptr;
348     allocated_memory_for_elements += PAGE_SIZE;
349     buf_used_len = word_aligned_size;
350     ptr = buf;
351     }
352     } else if (word_aligned_size) {
353     int i;
354     ptr = buf + buf_used_len;
355     buf_used_len += word_aligned_size;
356     for (i = 0; i < word_aligned_size; i++) {
357 kumaneko 1052 if (!ptr[i])
358     continue;
359     printk(KERN_ERR "WARNING: Reserved memory was tainted! "
360     "The system might go wrong.\n");
361     ptr[i] = '\0';
362 kumaneko 111 }
363     }
364 kumaneko 652 mutex_unlock(&lock);
365 kumaneko 111 return ptr;
366     }
367    
368 kumaneko 1052 static unsigned int allocated_memory_for_savename;
369     static unsigned int allocated_memory_for_pool;
370 kumaneko 111
371    
372 kumaneko 1052 /**
373 kumaneko 1054 * ccs_get_memory_used_for_save_name - Get memory used for keeping string data.
374 kumaneko 1052 *
375     * Returns memory used for keeping string data.
376     */
377     unsigned int ccs_get_memory_used_for_save_name(void)
378 kumaneko 111 {
379 kumaneko 1031 return allocated_memory_for_savename + allocated_memory_for_pool;
380 kumaneko 111 }
381    
382     #define MAX_HASH 256
383    
384 kumaneko 1052 /* Structure for string data. */
385 kumaneko 214 struct name_entry {
386 kumaneko 731 struct list1_head list;
387 kumaneko 111 struct path_info entry;
388 kumaneko 214 };
389 kumaneko 111
390 kumaneko 1052 /* Structure for available memory region. */
391 kumaneko 214 struct free_memory_block_list {
392 kumaneko 731 struct list_head list;
393 kumaneko 1052 char *ptr; /* Pointer to a free area. */
394     int len; /* Length of the area. */
395 kumaneko 214 };
396 kumaneko 111
397 kumaneko 1052 /* The list for "struct name_entry". */
398     static struct list1_head name_list[MAX_HASH];
399 kumaneko 731
400 kumaneko 1052 /**
401     * ccs_save_name - Allocate permanent memory for string data.
402     *
403     * @name: The string to store into the permernent memory.
404     *
405     * Returns pointer to "struct path_info" on success, NULL otherwise.
406     *
407     * The RAM is shared, so NEVER try to modify or kfree() the returned name.
408     */
409     const struct path_info *ccs_save_name(const char *name)
410 kumaneko 111 {
411 kumaneko 731 static LIST_HEAD(fmb_list);
412 kumaneko 652 static DEFINE_MUTEX(lock);
413 kumaneko 731 struct name_entry *ptr;
414 kumaneko 111 unsigned int hash;
415 kumaneko 731 struct free_memory_block_list *fmb;
416 kumaneko 111 int len;
417 kumaneko 731 char *cp;
418 kumaneko 1052 if (!name)
419     return NULL;
420 kumaneko 111 len = strlen(name) + 1;
421     if (len > CCS_MAX_PATHNAME_LEN) {
422 kumaneko 1052 printk(KERN_WARNING "ERROR: Name too long "
423     "for ccs_save_name().\n");
424 kumaneko 111 return NULL;
425     }
426     hash = full_name_hash((const unsigned char *) name, len - 1);
427 kumaneko 652 mutex_lock(&lock);
428 kumaneko 731 list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) {
429 kumaneko 1052 if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
430     goto out;
431 kumaneko 111 }
432 kumaneko 731 list_for_each_entry(fmb, &fmb_list, list) {
433 kumaneko 1052 if (len <= fmb->len)
434     goto ready;
435 kumaneko 111 }
436 kumaneko 1016 cp = kzalloc(PAGE_SIZE, GFP_KERNEL);
437     fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
438 kumaneko 731 if (!cp || !fmb) {
439     kfree(cp);
440     kfree(fmb);
441 kumaneko 1052 printk(KERN_WARNING "ERROR: Out of memory "
442     "for ccs_save_name().\n");
443     if (!sbin_init_started)
444     panic("MAC Initialization failed.\n");
445 kumaneko 731 ptr = NULL;
446     goto out;
447     }
448     allocated_memory_for_savename += PAGE_SIZE;
449     list_add(&fmb->list, &fmb_list);
450     fmb->ptr = cp;
451     fmb->len = PAGE_SIZE;
452     ready:
453 kumaneko 1052 ptr = ccs_alloc_element(sizeof(*ptr));
454     if (!ptr)
455     goto out;
456 kumaneko 111 ptr->entry.name = fmb->ptr;
457     memmove(fmb->ptr, name, len);
458 kumaneko 1052 ccs_fill_path_info(&ptr->entry);
459 kumaneko 111 fmb->ptr += len;
460     fmb->len -= len;
461 kumaneko 731 list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]);
462 kumaneko 111 if (fmb->len == 0) {
463 kumaneko 731 list_del(&fmb->list);
464     kfree(fmb);
465 kumaneko 111 }
466     out:
467 kumaneko 652 mutex_unlock(&lock);
468 kumaneko 111 return ptr ? &ptr->entry : NULL;
469     }
470    
471 kumaneko 1052 /* Structure for temporarily allocated memory. */
472 kumaneko 214 struct cache_entry {
473 kumaneko 111 struct list_head list;
474     void *ptr;
475     int size;
476 kumaneko 214 };
477 kumaneko 111
478 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
479     static struct kmem_cache *ccs_cachep;
480 kumaneko 111 #else
481 kumaneko 1052 static kmem_cache_t *ccs_cachep;
482 kumaneko 111 #endif
483    
484 kumaneko 1031 #ifdef CCS_MAX_RESERVED_PAGES
485     #define MAX_CCS_PAGE_BUFFER_POOL (CCS_MAX_RESERVED_PAGES)
486     #else
487     #define MAX_CCS_PAGE_BUFFER_POOL 10
488     #endif
489    
490     static struct ccs_page_buffer *ccs_page_buffer_pool[MAX_CCS_PAGE_BUFFER_POOL];
491     static bool ccs_page_buffer_pool_in_use[MAX_CCS_PAGE_BUFFER_POOL];
492    
493 kumaneko 1052 /**
494     * ccs_realpath_init - Initialize realpath related code.
495     *
496     * Returns 0.
497     */
498     static int __init ccs_realpath_init(void)
499 kumaneko 111 {
500 kumaneko 731 int i;
501 kumaneko 1052 if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
502     panic("Bad size.");
503     if (sizeof(struct path_info_with_data) > sizeof(struct ccs_page_buffer))
504     panic("Bad size.");
505     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
506     ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),
507     0, 0, NULL);
508 kumaneko 316 #else
509 kumaneko 1052 ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),
510     0, 0, NULL, NULL);
511 kumaneko 316 #endif
512 kumaneko 1052 if (!ccs_cachep)
513     panic("Can't create cache.\n");
514     for (i = 0; i < MAX_HASH; i++)
515 kumaneko 731 INIT_LIST1_HEAD(&name_list[i]);
516 kumaneko 722 INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list);
517 kumaneko 1052 KERNEL_DOMAIN.domainname = ccs_save_name(ROOT_NAME);
518 kumaneko 722 list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);
519 kumaneko 1052 if (ccs_find_domain(ROOT_NAME) != &KERNEL_DOMAIN)
520     panic("Can't register KERNEL_DOMAIN");
521 kumaneko 1031 memset(ccs_page_buffer_pool, 0, sizeof(ccs_page_buffer_pool));
522 kumaneko 1052 for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++)
523     ccs_page_buffer_pool_in_use[i] = false;
524     return 0;
525 kumaneko 111 }
526    
527 kumaneko 1052 __initcall(ccs_realpath_init);
528    
529     /* The list for "struct cache_entry". */
530 kumaneko 111 static LIST_HEAD(cache_list);
531    
532 kumaneko 1052 static DEFINE_SPINLOCK(cache_list_lock);
533    
534     static unsigned int dynamic_memory_size;
535    
536     /**
537     * ccs_get_memory_used_for_dynamic - Get memory used for temporal purpose.
538     *
539     * Returns memory used for temporal purpose.
540     */
541     unsigned int ccs_get_memory_used_for_dynamic(void)
542 kumaneko 111 {
543     return dynamic_memory_size;
544     }
545    
546 kumaneko 1052 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
547     /**
548     * round2 - Rounded up to power-of-two value.
549     *
550     * @size: Size in bytes.
551     *
552     * Returns power-of-two of @size.
553     */
554 kumaneko 581 static int round2(size_t size)
555     {
556     #if PAGE_SIZE == 4096
557     size_t bsize = 32;
558     #else
559     size_t bsize = 64;
560     #endif
561     while (size > bsize) bsize <<= 1;
562     return bsize;
563     }
564     #endif
565    
566 kumaneko 1052 static DEFINE_SPINLOCK(ccs_page_buffer_pool_lock);
567 kumaneko 1031
568 kumaneko 1052 /**
569     * ccs_alloc - Allocate memory for temporal purpose.
570     *
571     * @size: Size in bytes.
572     *
573     * Returns pointer to allocated memory on success, NULL otherwise.
574     */
575 kumaneko 214 void *ccs_alloc(const size_t size)
576 kumaneko 111 {
577 kumaneko 1031 int i;
578     void *ret;
579     struct cache_entry *new_entry;
580 kumaneko 1052 if (size != sizeof(struct ccs_page_buffer))
581     goto normal;
582 kumaneko 1031 for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {
583     struct ccs_page_buffer *ptr;
584 kumaneko 1052 bool in_use;
585     if (ccs_page_buffer_pool_in_use[i])
586     continue;
587     /***** CRITICAL SECTION START *****/
588 kumaneko 1031 spin_lock(&ccs_page_buffer_pool_lock);
589 kumaneko 1052 in_use = ccs_page_buffer_pool_in_use[i];
590     if (!in_use)
591     ccs_page_buffer_pool_in_use[i] = true;
592     spin_unlock(&ccs_page_buffer_pool_lock);
593     /***** CRITICAL SECTION END *****/
594     if (in_use)
595 kumaneko 1031 continue;
596     ptr = ccs_page_buffer_pool[i];
597 kumaneko 1052 if (ptr)
598     goto ok;
599     ptr = kmalloc(sizeof(struct ccs_page_buffer), GFP_KERNEL);
600     /***** CRITICAL SECTION START *****/
601     spin_lock(&ccs_page_buffer_pool_lock);
602     if (ptr) {
603     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
604     allocated_memory_for_pool += ksize(ptr);
605 kumaneko 581 #else
606 kumaneko 1052 allocated_memory_for_pool += round2(size);
607 kumaneko 581 #endif
608 kumaneko 1052 } else {
609     ccs_page_buffer_pool_in_use[i] = false;
610 kumaneko 111 }
611 kumaneko 1052 spin_unlock(&ccs_page_buffer_pool_lock);
612     /***** CRITICAL SECTION END *****/
613     if (!ptr)
614     goto normal;
615     ccs_page_buffer_pool[i] = ptr;
616     printk(KERN_DEBUG "Allocated permanent buffer %d/%d\n",
617     i, MAX_CCS_PAGE_BUFFER_POOL);
618     ok:
619 kumaneko 1031 memset(ptr, 0, sizeof(struct ccs_page_buffer));
620     return ptr;
621 kumaneko 111 }
622 kumaneko 1031 normal:
623     ret = kzalloc(size, GFP_KERNEL);
624 kumaneko 1052 if (!ret)
625     goto out;
626 kumaneko 1031 new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);
627     if (!new_entry) {
628     kfree(ret); ret = NULL;
629     goto out;
630     }
631     INIT_LIST_HEAD(&new_entry->list);
632     new_entry->ptr = ret;
633 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
634 kumaneko 1031 new_entry->size = ksize(ret);
635     #else
636     new_entry->size = round2(size);
637     #endif
638 kumaneko 1052 /***** CRITICAL SECTION START *****/
639 kumaneko 1031 spin_lock(&cache_list_lock);
640     list_add_tail(&new_entry->list, &cache_list);
641     dynamic_memory_size += new_entry->size;
642     spin_unlock(&cache_list_lock);
643 kumaneko 1052 /***** CRITICAL SECTION END *****/
644 kumaneko 1031 out:
645 kumaneko 214 return ret;
646 kumaneko 111 }
647    
648 kumaneko 1052 /**
649     * ccs_free - Release memory allocated by ccs_alloc().
650     *
651     * @p: Pointer returned by ccs_alloc(). May be NULL.
652     *
653     * Returns nothing.
654     */
655 kumaneko 111 void ccs_free(const void *p)
656     {
657 kumaneko 1031 int i;
658 kumaneko 111 struct list_head *v;
659 kumaneko 214 struct cache_entry *entry = NULL;
660 kumaneko 1052 if (!p)
661     return;
662 kumaneko 1031 for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {
663     bool done;
664 kumaneko 1052 if (p != ccs_page_buffer_pool[i])
665     continue;
666     /***** CRITICAL SECTION START *****/
667 kumaneko 1031 spin_lock(&ccs_page_buffer_pool_lock);
668     done = ccs_page_buffer_pool_in_use[i];
669 kumaneko 1052 if (done)
670     ccs_page_buffer_pool_in_use[i] = false;
671 kumaneko 1031 spin_unlock(&ccs_page_buffer_pool_lock);
672 kumaneko 1052 /***** CRITICAL SECTION END *****/
673     if (done)
674     return;
675 kumaneko 1031 }
676 kumaneko 1052 /***** CRITICAL SECTION START *****/
677 kumaneko 111 spin_lock(&cache_list_lock);
678     list_for_each(v, &cache_list) {
679 kumaneko 214 entry = list_entry(v, struct cache_entry, list);
680 kumaneko 111 if (entry->ptr != p) {
681     entry = NULL; continue;
682     }
683     list_del(&entry->list);
684     dynamic_memory_size -= entry->size;
685     break;
686     }
687     spin_unlock(&cache_list_lock);
688 kumaneko 1052 /***** CRITICAL SECTION END *****/
689 kumaneko 111 if (entry) {
690     kfree(p);
691     kmem_cache_free(ccs_cachep, entry);
692     } else {
693 kumaneko 1052 printk(KERN_WARNING "BUG: ccs_free() with invalid pointer.\n");
694 kumaneko 111 }
695     }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26