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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [file.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/file.c
3
 *
4
 *  Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
5
 *
6
 *  Manage the dynamic fd arrays in the process files_struct.
7
 */
8
 
9
#include <linux/fs.h>
10
#include <linux/mm.h>
11
#include <linux/sched.h>
12
#include <linux/slab.h>
13
#include <linux/vmalloc.h>
14
 
15
#include <asm/bitops.h>
16
 
17
 
18
/*
19
 * Allocate an fd array, using kmalloc or vmalloc.
20
 * Note: the array isn't cleared at allocation time.
21
 */
22
struct file ** alloc_fd_array(int num)
23
{
24
        struct file **new_fds;
25
        int size = num * sizeof(struct file *);
26
 
27
        if (size <= PAGE_SIZE)
28
                new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
29
        else
30
                new_fds = (struct file **) vmalloc(size);
31
        return new_fds;
32
}
33
 
34
void free_fd_array(struct file **array, int num)
35
{
36
        int size = num * sizeof(struct file *);
37
 
38
        if (!array) {
39
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
40
                                __FUNCTION__, num);
41
                return;
42
        }
43
 
44
        if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
45
                return;
46
        else if (size <= PAGE_SIZE)
47
                kfree(array);
48
        else
49
                vfree(array);
50
}
51
 
52
/*
53
 * Expand the fd array in the files_struct.  Called with the files
54
 * spinlock held for write.
55
 */
56
 
57
int expand_fd_array(struct files_struct *files, int nr)
58
{
59
        struct file **new_fds;
60
        int error, nfds;
61
 
62
 
63
        error = -EMFILE;
64
        if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)
65
                goto out;
66
 
67
        nfds = files->max_fds;
68
        write_unlock(&files->file_lock);
69
 
70
        /*
71
         * Expand to the max in easy steps, and keep expanding it until
72
         * we have enough for the requested fd array size.
73
         */
74
 
75
        do {
76
#if NR_OPEN_DEFAULT < 256
77
                if (nfds < 256)
78
                        nfds = 256;
79
                else
80
#endif
81
                if (nfds < (PAGE_SIZE / sizeof(struct file *)))
82
                        nfds = PAGE_SIZE / sizeof(struct file *);
83
                else {
84
                        nfds = nfds * 2;
85
                        if (nfds > NR_OPEN)
86
                                nfds = NR_OPEN;
87
                }
88
        } while (nfds <= nr);
89
 
90
        error = -ENOMEM;
91
        new_fds = alloc_fd_array(nfds);
92
        write_lock(&files->file_lock);
93
        if (!new_fds)
94
                goto out;
95
 
96
        /* Copy the existing array and install the new pointer */
97
 
98
        if (nfds > files->max_fds) {
99
                struct file **old_fds;
100
                int i;
101
 
102
                old_fds = xchg(&files->fd, new_fds);
103
                i = xchg(&files->max_fds, nfds);
104
 
105
                /* Don't copy/clear the array if we are creating a new
106
                   fd array for fork() */
107
                if (i) {
108
                        memcpy(new_fds, old_fds, i * sizeof(struct file *));
109
                        /* clear the remainder of the array */
110
                        memset(&new_fds[i], 0,
111
                               (nfds-i) * sizeof(struct file *));
112
 
113
                        write_unlock(&files->file_lock);
114
                        free_fd_array(old_fds, i);
115
                        write_lock(&files->file_lock);
116
                }
117
        } else {
118
                /* Somebody expanded the array while we slept ... */
119
                write_unlock(&files->file_lock);
120
                free_fd_array(new_fds, nfds);
121
                write_lock(&files->file_lock);
122
        }
123
        error = 0;
124
out:
125
        return error;
126
}
127
 
128
/*
129
 * Allocate an fdset array, using kmalloc or vmalloc.
130
 * Note: the array isn't cleared at allocation time.
131
 */
132
fd_set * alloc_fdset(int num)
133
{
134
        fd_set *new_fdset;
135
        int size = num / 8;
136
 
137
        if (size <= PAGE_SIZE)
138
                new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
139
        else
140
                new_fdset = (fd_set *) vmalloc(size);
141
        return new_fdset;
142
}
143
 
144
void free_fdset(fd_set *array, int num)
145
{
146
        int size = num / 8;
147
 
148
        if (!array) {
149
                printk(KERN_ERR "%s array = 0 (num = %d)\n",
150
                                __FUNCTION__, num);
151
                return;
152
        }
153
 
154
        if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
155
                return;
156
        else if (size <= PAGE_SIZE)
157
                kfree(array);
158
        else
159
                vfree(array);
160
}
161
 
162
/*
163
 * Expand the fdset in the files_struct.  Called with the files spinlock
164
 * held for write.
165
 */
166
int expand_fdset(struct files_struct *files, int nr)
167
{
168
        fd_set *new_openset = 0, *new_execset = 0;
169
        int error, nfds = 0;
170
 
171
        error = -EMFILE;
172
        if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
173
                goto out;
174
 
175
        nfds = files->max_fdset;
176
        write_unlock(&files->file_lock);
177
 
178
        /* Expand to the max in easy steps */
179
        do {
180
                if (nfds < (PAGE_SIZE * 8))
181
                        nfds = PAGE_SIZE * 8;
182
                else {
183
                        nfds = nfds * 2;
184
                        if (nfds > NR_OPEN)
185
                                nfds = NR_OPEN;
186
                }
187
        } while (nfds <= nr);
188
 
189
        error = -ENOMEM;
190
        new_openset = alloc_fdset(nfds);
191
        new_execset = alloc_fdset(nfds);
192
        write_lock(&files->file_lock);
193
        if (!new_openset || !new_execset)
194
                goto out;
195
 
196
        error = 0;
197
 
198
        /* Copy the existing tables and install the new pointers */
199
        if (nfds > files->max_fdset) {
200
                int i = files->max_fdset / (sizeof(unsigned long) * 8);
201
                int count = (nfds - files->max_fdset) / 8;
202
 
203
                /*
204
                 * Don't copy the entire array if the current fdset is
205
                 * not yet initialised.
206
                 */
207
                if (i) {
208
                        memcpy (new_openset, files->open_fds, files->max_fdset/8);
209
                        memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
210
                        memset (&new_openset->fds_bits[i], 0, count);
211
                        memset (&new_execset->fds_bits[i], 0, count);
212
                }
213
 
214
                nfds = xchg(&files->max_fdset, nfds);
215
                new_openset = xchg(&files->open_fds, new_openset);
216
                new_execset = xchg(&files->close_on_exec, new_execset);
217
                write_unlock(&files->file_lock);
218
                free_fdset (new_openset, nfds);
219
                free_fdset (new_execset, nfds);
220
                write_lock(&files->file_lock);
221
                return 0;
222
        }
223
        /* Somebody expanded the array while we slept ... */
224
 
225
out:
226
        write_unlock(&files->file_lock);
227
        if (new_openset)
228
                free_fdset(new_openset, nfds);
229
        if (new_execset)
230
                free_fdset(new_execset, nfds);
231
        write_lock(&files->file_lock);
232
        return error;
233
}
234
 

powered by: WebSVN 2.1.0

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