OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [file.c] - Diff between revs 1275 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1275 Rev 1765
/*
/*
 *  linux/fs/file.c
 *  linux/fs/file.c
 *
 *
 *  Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
 *  Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
 *
 *
 *  Manage the dynamic fd arrays in the process files_struct.
 *  Manage the dynamic fd arrays in the process files_struct.
 */
 */
 
 
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/vmalloc.h>
 
 
#include <asm/bitops.h>
#include <asm/bitops.h>
 
 
 
 
/*
/*
 * Allocate an fd array, using kmalloc or vmalloc.
 * Allocate an fd array, using kmalloc or vmalloc.
 * Note: the array isn't cleared at allocation time.
 * Note: the array isn't cleared at allocation time.
 */
 */
struct file ** alloc_fd_array(int num)
struct file ** alloc_fd_array(int num)
{
{
        struct file **new_fds;
        struct file **new_fds;
        int size = num * sizeof(struct file *);
        int size = num * sizeof(struct file *);
 
 
        if (size <= PAGE_SIZE)
        if (size <= PAGE_SIZE)
                new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
                new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
        else
        else
                new_fds = (struct file **) vmalloc(size);
                new_fds = (struct file **) vmalloc(size);
        return new_fds;
        return new_fds;
}
}
 
 
void free_fd_array(struct file **array, int num)
void free_fd_array(struct file **array, int num)
{
{
        int size = num * sizeof(struct file *);
        int size = num * sizeof(struct file *);
 
 
        if (!array) {
        if (!array) {
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
                                __FUNCTION__, num);
                                __FUNCTION__, num);
                return;
                return;
        }
        }
 
 
        if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
        if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
                return;
                return;
        else if (size <= PAGE_SIZE)
        else if (size <= PAGE_SIZE)
                kfree(array);
                kfree(array);
        else
        else
                vfree(array);
                vfree(array);
}
}
 
 
/*
/*
 * Expand the fd array in the files_struct.  Called with the files
 * Expand the fd array in the files_struct.  Called with the files
 * spinlock held for write.
 * spinlock held for write.
 */
 */
 
 
int expand_fd_array(struct files_struct *files, int nr)
int expand_fd_array(struct files_struct *files, int nr)
{
{
        struct file **new_fds;
        struct file **new_fds;
        int error, nfds;
        int error, nfds;
 
 
 
 
        error = -EMFILE;
        error = -EMFILE;
        if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)
        if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)
                goto out;
                goto out;
 
 
        nfds = files->max_fds;
        nfds = files->max_fds;
        write_unlock(&files->file_lock);
        write_unlock(&files->file_lock);
 
 
        /*
        /*
         * Expand to the max in easy steps, and keep expanding it until
         * Expand to the max in easy steps, and keep expanding it until
         * we have enough for the requested fd array size.
         * we have enough for the requested fd array size.
         */
         */
 
 
        do {
        do {
#if NR_OPEN_DEFAULT < 256
#if NR_OPEN_DEFAULT < 256
                if (nfds < 256)
                if (nfds < 256)
                        nfds = 256;
                        nfds = 256;
                else
                else
#endif
#endif
                if (nfds < (PAGE_SIZE / sizeof(struct file *)))
                if (nfds < (PAGE_SIZE / sizeof(struct file *)))
                        nfds = PAGE_SIZE / sizeof(struct file *);
                        nfds = PAGE_SIZE / sizeof(struct file *);
                else {
                else {
                        nfds = nfds * 2;
                        nfds = nfds * 2;
                        if (nfds > NR_OPEN)
                        if (nfds > NR_OPEN)
                                nfds = NR_OPEN;
                                nfds = NR_OPEN;
                }
                }
        } while (nfds <= nr);
        } while (nfds <= nr);
 
 
        error = -ENOMEM;
        error = -ENOMEM;
        new_fds = alloc_fd_array(nfds);
        new_fds = alloc_fd_array(nfds);
        write_lock(&files->file_lock);
        write_lock(&files->file_lock);
        if (!new_fds)
        if (!new_fds)
                goto out;
                goto out;
 
 
        /* Copy the existing array and install the new pointer */
        /* Copy the existing array and install the new pointer */
 
 
        if (nfds > files->max_fds) {
        if (nfds > files->max_fds) {
                struct file **old_fds;
                struct file **old_fds;
                int i;
                int i;
 
 
                old_fds = xchg(&files->fd, new_fds);
                old_fds = xchg(&files->fd, new_fds);
                i = xchg(&files->max_fds, nfds);
                i = xchg(&files->max_fds, nfds);
 
 
                /* Don't copy/clear the array if we are creating a new
                /* Don't copy/clear the array if we are creating a new
                   fd array for fork() */
                   fd array for fork() */
                if (i) {
                if (i) {
                        memcpy(new_fds, old_fds, i * sizeof(struct file *));
                        memcpy(new_fds, old_fds, i * sizeof(struct file *));
                        /* clear the remainder of the array */
                        /* clear the remainder of the array */
                        memset(&new_fds[i], 0,
                        memset(&new_fds[i], 0,
                               (nfds-i) * sizeof(struct file *));
                               (nfds-i) * sizeof(struct file *));
 
 
                        write_unlock(&files->file_lock);
                        write_unlock(&files->file_lock);
                        free_fd_array(old_fds, i);
                        free_fd_array(old_fds, i);
                        write_lock(&files->file_lock);
                        write_lock(&files->file_lock);
                }
                }
        } else {
        } else {
                /* Somebody expanded the array while we slept ... */
                /* Somebody expanded the array while we slept ... */
                write_unlock(&files->file_lock);
                write_unlock(&files->file_lock);
                free_fd_array(new_fds, nfds);
                free_fd_array(new_fds, nfds);
                write_lock(&files->file_lock);
                write_lock(&files->file_lock);
        }
        }
        error = 0;
        error = 0;
out:
out:
        return error;
        return error;
}
}
 
 
/*
/*
 * Allocate an fdset array, using kmalloc or vmalloc.
 * Allocate an fdset array, using kmalloc or vmalloc.
 * Note: the array isn't cleared at allocation time.
 * Note: the array isn't cleared at allocation time.
 */
 */
fd_set * alloc_fdset(int num)
fd_set * alloc_fdset(int num)
{
{
        fd_set *new_fdset;
        fd_set *new_fdset;
        int size = num / 8;
        int size = num / 8;
 
 
        if (size <= PAGE_SIZE)
        if (size <= PAGE_SIZE)
                new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
                new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
        else
        else
                new_fdset = (fd_set *) vmalloc(size);
                new_fdset = (fd_set *) vmalloc(size);
        return new_fdset;
        return new_fdset;
}
}
 
 
void free_fdset(fd_set *array, int num)
void free_fdset(fd_set *array, int num)
{
{
        int size = num / 8;
        int size = num / 8;
 
 
        if (!array) {
        if (!array) {
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
                                __FUNCTION__, num);
                                __FUNCTION__, num);
                return;
                return;
        }
        }
 
 
        if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
        if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
                return;
                return;
        else if (size <= PAGE_SIZE)
        else if (size <= PAGE_SIZE)
                kfree(array);
                kfree(array);
        else
        else
                vfree(array);
                vfree(array);
}
}
 
 
/*
/*
 * Expand the fdset in the files_struct.  Called with the files spinlock
 * Expand the fdset in the files_struct.  Called with the files spinlock
 * held for write.
 * held for write.
 */
 */
int expand_fdset(struct files_struct *files, int nr)
int expand_fdset(struct files_struct *files, int nr)
{
{
        fd_set *new_openset = 0, *new_execset = 0;
        fd_set *new_openset = 0, *new_execset = 0;
        int error, nfds = 0;
        int error, nfds = 0;
 
 
        error = -EMFILE;
        error = -EMFILE;
        if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
        if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
                goto out;
                goto out;
 
 
        nfds = files->max_fdset;
        nfds = files->max_fdset;
        write_unlock(&files->file_lock);
        write_unlock(&files->file_lock);
 
 
        /* Expand to the max in easy steps */
        /* Expand to the max in easy steps */
        do {
        do {
                if (nfds < (PAGE_SIZE * 8))
                if (nfds < (PAGE_SIZE * 8))
                        nfds = PAGE_SIZE * 8;
                        nfds = PAGE_SIZE * 8;
                else {
                else {
                        nfds = nfds * 2;
                        nfds = nfds * 2;
                        if (nfds > NR_OPEN)
                        if (nfds > NR_OPEN)
                                nfds = NR_OPEN;
                                nfds = NR_OPEN;
                }
                }
        } while (nfds <= nr);
        } while (nfds <= nr);
 
 
        error = -ENOMEM;
        error = -ENOMEM;
        new_openset = alloc_fdset(nfds);
        new_openset = alloc_fdset(nfds);
        new_execset = alloc_fdset(nfds);
        new_execset = alloc_fdset(nfds);
        write_lock(&files->file_lock);
        write_lock(&files->file_lock);
        if (!new_openset || !new_execset)
        if (!new_openset || !new_execset)
                goto out;
                goto out;
 
 
        error = 0;
        error = 0;
 
 
        /* Copy the existing tables and install the new pointers */
        /* Copy the existing tables and install the new pointers */
        if (nfds > files->max_fdset) {
        if (nfds > files->max_fdset) {
                int i = files->max_fdset / (sizeof(unsigned long) * 8);
                int i = files->max_fdset / (sizeof(unsigned long) * 8);
                int count = (nfds - files->max_fdset) / 8;
                int count = (nfds - files->max_fdset) / 8;
 
 
                /*
                /*
                 * Don't copy the entire array if the current fdset is
                 * Don't copy the entire array if the current fdset is
                 * not yet initialised.
                 * not yet initialised.
                 */
                 */
                if (i) {
                if (i) {
                        memcpy (new_openset, files->open_fds, files->max_fdset/8);
                        memcpy (new_openset, files->open_fds, files->max_fdset/8);
                        memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
                        memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
                        memset (&new_openset->fds_bits[i], 0, count);
                        memset (&new_openset->fds_bits[i], 0, count);
                        memset (&new_execset->fds_bits[i], 0, count);
                        memset (&new_execset->fds_bits[i], 0, count);
                }
                }
 
 
                nfds = xchg(&files->max_fdset, nfds);
                nfds = xchg(&files->max_fdset, nfds);
                new_openset = xchg(&files->open_fds, new_openset);
                new_openset = xchg(&files->open_fds, new_openset);
                new_execset = xchg(&files->close_on_exec, new_execset);
                new_execset = xchg(&files->close_on_exec, new_execset);
                write_unlock(&files->file_lock);
                write_unlock(&files->file_lock);
                free_fdset (new_openset, nfds);
                free_fdset (new_openset, nfds);
                free_fdset (new_execset, nfds);
                free_fdset (new_execset, nfds);
                write_lock(&files->file_lock);
                write_lock(&files->file_lock);
                return 0;
                return 0;
        }
        }
        /* Somebody expanded the array while we slept ... */
        /* Somebody expanded the array while we slept ... */
 
 
out:
out:
        write_unlock(&files->file_lock);
        write_unlock(&files->file_lock);
        if (new_openset)
        if (new_openset)
                free_fdset(new_openset, nfds);
                free_fdset(new_openset, nfds);
        if (new_execset)
        if (new_execset)
                free_fdset(new_execset, nfds);
                free_fdset(new_execset, nfds);
        write_lock(&files->file_lock);
        write_lock(&files->file_lock);
        return error;
        return error;
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.