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

Subversion Repositories or1k

[/] [or1k/] [tags/] [LINUX_2_4_26_OR32/] [linux/] [linux-2.4/] [fs/] [intermezzo/] [dcache.c] - Blame information for rev 1275

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

Line No. Rev Author Line
1 1275 phoenix
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2
 * vim:expandtab:shiftwidth=8:tabstop=8:
3
 *
4
 *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
5
 *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
6
 *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
7
 *
8
 *   This file is part of InterMezzo, http://www.inter-mezzo.org.
9
 *
10
 *   InterMezzo is free software; you can redistribute it and/or
11
 *   modify it under the terms of version 2 of the GNU General Public
12
 *   License as published by the Free Software Foundation.
13
 *
14
 *   InterMezzo is distributed in the hope that it will be useful,
15
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *   GNU General Public License for more details.
18
 *
19
 *   You should have received a copy of the GNU General Public License
20
 *   along with InterMezzo; if not, write to the Free Software
21
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
 *
23
 * Directory operations for InterMezzo filesystem
24
 */
25
 
26
/* inode dentry alias list walking code adapted from linux/fs/dcache.c
27
 *
28
 * fs/dcache.c
29
 *
30
 * (C) 1997 Thomas Schoebel-Theuer,
31
 * with heavy changes by Linus Torvalds
32
 */
33
 
34
#define __NO_VERSION__
35
#include <linux/types.h>
36
#include <linux/kernel.h>
37
#include <linux/sched.h>
38
#include <linux/fs.h>
39
#include <linux/stat.h>
40
#include <linux/errno.h>
41
#include <linux/locks.h>
42
#include <linux/slab.h>
43
#include <asm/segment.h>
44
#include <asm/uaccess.h>
45
#include <linux/string.h>
46
#include <linux/smp_lock.h>
47
#include <linux/vmalloc.h>
48
 
49
#include <linux/intermezzo_fs.h>
50
 
51
kmem_cache_t * presto_dentry_slab;
52
 
53
/* called when a cache lookup succeeds */
54
static int presto_d_revalidate(struct dentry *de, int flag)
55
{
56
        struct inode *inode = de->d_inode;
57
        struct presto_file_set * root_fset;
58
 
59
        ENTRY;
60
        if (!inode) {
61
                EXIT;
62
                return 0;
63
        }
64
 
65
        if (is_bad_inode(inode)) {
66
                EXIT;
67
                return 0;
68
        }
69
 
70
        if (!presto_d2d(de)) {
71
                presto_set_dd(de);
72
        }
73
 
74
        if (!presto_d2d(de)) {
75
                EXIT;
76
                return 0;
77
        }
78
 
79
        root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
80
        if (root_fset->fset_flags & FSET_FLAT_BRANCH &&
81
            (presto_d2d(de)->dd_fset != root_fset )) {
82
                presto_d2d(de)->dd_fset = root_fset;
83
        }
84
 
85
        EXIT;
86
        return 1;
87
 
88
#if 0
89
        /* The following is needed for metadata on demand. */
90
        if ( S_ISDIR(inode->i_mode) ) {
91
                EXIT;
92
                return (presto_chk(de, PRESTO_DATA) &&
93
                        (presto_chk(de, PRESTO_ATTR)));
94
        } else {
95
                EXIT;
96
                return presto_chk(de, PRESTO_ATTR);
97
        }
98
#endif
99
}
100
 
101
static void presto_d_release(struct dentry *dentry)
102
{
103
        if (!presto_d2d(dentry)) {
104
                /* This can happen for dentries from NFSd */
105
                return;
106
        }
107
        presto_d2d(dentry)->dd_count--;
108
 
109
        if (!presto_d2d(dentry)->dd_count) {
110
                kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
111
                dentry->d_fsdata = NULL;
112
        }
113
}
114
 
115
struct dentry_operations presto_dentry_ops =
116
{
117
        .d_revalidate =  presto_d_revalidate,
118
        .d_release = presto_d_release
119
};
120
 
121
static inline int presto_is_dentry_ROOT (struct dentry *dentry)
122
{
123
        return(dentry_name_cmp(dentry,"ROOT") &&
124
               !dentry_name_cmp(dentry->d_parent,".intermezzo"));
125
}
126
 
127
static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
128
                int *is_under_d_intermezzo)
129
{
130
        struct dentry* temp_dentry;
131
        struct presto_dentry_data *d_data;
132
        int found_root=0;
133
 
134
        ENTRY;
135
        CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry,
136
                        dentry->d_name.name);
137
 
138
        *is_under_d_intermezzo = 0;
139
 
140
        /* walk up through the branch to get the fileset */
141
        /* The dentry we are passed presumably does not have the correct
142
         * fset information. However, we still want to start walking up
143
         * the branch from this dentry to get our found_root and
144
         * is_under_d_intermezzo decisions correct
145
         */
146
        for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
147
                CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry,
148
                        temp_dentry->d_name.len,temp_dentry->d_name.name);
149
                if (presto_is_dentry_ROOT(temp_dentry))
150
                        found_root = 1;
151
                if (!found_root &&
152
                    dentry_name_cmp(temp_dentry, ".intermezzo")) {
153
                        *is_under_d_intermezzo = 1;
154
                }
155
                d_data = presto_d2d(temp_dentry);
156
                if (d_data) {
157
                        /* If we found a "ROOT" dentry while walking up the
158
                         * branch, we will journal regardless of whether
159
                         * we are under .intermezzo or not.
160
                         * If we are already under d_intermezzo don't reverse
161
                         * the decision here...even if we found a "ROOT"
162
                         * dentry above .intermezzo (if we were ever to
163
                         * modify the directory structure).
164
                         */
165
                        if (!*is_under_d_intermezzo)
166
                                *is_under_d_intermezzo = !found_root &&
167
                                  (d_data->dd_flags & PRESTO_DONT_JOURNAL);
168
                        EXIT;
169
                        return d_data->dd_fset;
170
                }
171
                if (temp_dentry->d_parent == temp_dentry) {
172
                        break;
173
                }
174
        }
175
        EXIT;
176
        return NULL;
177
}
178
 
179
/* Only call this function on positive dentries */
180
static struct presto_dentry_data* presto_try_find_alias_with_dd (
181
                  struct dentry* dentry)
182
{
183
        struct inode *inode=dentry->d_inode;
184
        struct list_head *head, *next, *tmp;
185
        struct dentry *tmp_dentry;
186
 
187
        /* Search through the alias list for dentries with d_fsdata */
188
        spin_lock(&dcache_lock);
189
        head = &inode->i_dentry;
190
        next = inode->i_dentry.next;
191
        while (next != head) {
192
                tmp = next;
193
                next = tmp->next;
194
                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
195
                if (!presto_d2d(tmp_dentry)) {
196
                        spin_unlock(&dcache_lock);
197
                        return presto_d2d(tmp_dentry);
198
                }
199
        }
200
        spin_unlock(&dcache_lock);
201
        return NULL;
202
}
203
 
204
/* Only call this function on positive dentries */
205
static void presto_set_alias_dd (struct dentry *dentry,
206
                struct presto_dentry_data* dd)
207
{
208
        struct inode *inode=dentry->d_inode;
209
        struct list_head *head, *next, *tmp;
210
        struct dentry *tmp_dentry;
211
 
212
        /* Set d_fsdata for this dentry */
213
        dd->dd_count++;
214
        dentry->d_fsdata = dd;
215
 
216
        /* Now set d_fsdata for all dentries in the alias list. */
217
        spin_lock(&dcache_lock);
218
        head = &inode->i_dentry;
219
        next = inode->i_dentry.next;
220
        while (next != head) {
221
                tmp = next;
222
                next = tmp->next;
223
                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
224
                if (!presto_d2d(tmp_dentry)) {
225
                        dd->dd_count++;
226
                        tmp_dentry->d_fsdata = dd;
227
                }
228
        }
229
        spin_unlock(&dcache_lock);
230
        return;
231
}
232
 
233
inline struct presto_dentry_data *izo_alloc_ddata(void)
234
{
235
        struct presto_dentry_data *dd;
236
 
237
        dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
238
        if (dd == NULL) {
239
                CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
240
                return NULL;
241
        }
242
        memset(dd, 0, sizeof(*dd));
243
        dd->dd_count = 1;
244
 
245
        return dd;
246
}
247
 
248
/* This uses the BKL! */
249
int presto_set_dd(struct dentry * dentry)
250
{
251
        struct presto_file_set *fset;
252
        struct presto_dentry_data *dd;
253
        int is_under_d_izo;
254
        int error=0;
255
 
256
        ENTRY;
257
 
258
        if (!dentry)
259
                BUG();
260
 
261
        lock_kernel();
262
 
263
        /* Did we lose a race? */
264
        if (dentry->d_fsdata) {
265
                CERROR("dentry %p already has d_fsdata set\n", dentry);
266
                if (dentry->d_inode)
267
                        CERROR("    inode: %ld\n", dentry->d_inode->i_ino);
268
                EXIT;
269
                goto out_unlock;
270
        }
271
 
272
        if (dentry->d_inode != NULL) {
273
                /* NFSd runs find_fh_dentry which instantiates disconnected
274
                 * dentries which are then connected without a lookup().
275
                 * So it is possible to have connected dentries that do not
276
                 * have d_fsdata set. So we walk the list trying to find
277
                 * an alias which has its d_fsdata set and then use that
278
                 * for all the other dentries  as well.
279
                 * - SHP,Vinny.
280
                 */
281
 
282
                /* If there is an alias with d_fsdata use it. */
283
                if ((dd = presto_try_find_alias_with_dd (dentry))) {
284
                        presto_set_alias_dd (dentry, dd);
285
                        EXIT;
286
                        goto out_unlock;
287
                }
288
        } else {
289
                /* Negative dentry */
290
                CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry,
291
                                dentry->d_name.len, dentry->d_name.name);
292
        }
293
 
294
        /* No pre-existing d_fsdata, we need to construct one.
295
         * First, we must walk up the tree to find the fileset
296
         * If a fileset can't be found, we leave a null fsdata
297
         * and return EROFS to indicate that we can't journal
298
         * updates.
299
         */
300
        fset = presto_try_find_fset (dentry, &is_under_d_izo);
301
        if (!fset) {
302
#ifdef PRESTO_NO_NFS
303
                CERROR("No fileset for dentry %p: %*s\n", dentry,
304
                                dentry->d_name.len, dentry->d_name.name);
305
#endif
306
                error = -EROFS;
307
                EXIT;
308
                goto out_unlock;
309
        }
310
 
311
        dentry->d_fsdata = izo_alloc_ddata();
312
        if (!presto_d2d(dentry)) {
313
                CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
314
                error = -ENOMEM;
315
                goto out_unlock;
316
        }
317
        presto_d2d(dentry)->dd_fset = fset;
318
        if (is_under_d_izo)
319
                presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
320
        EXIT;
321
 
322
out_unlock:
323
        CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n",
324
                        dentry, dentry->d_name.len, dentry->d_name.name,
325
                        dentry->d_fsdata);
326
        unlock_kernel();
327
        return error;
328
}
329
 
330
int presto_init_ddata_cache(void)
331
{
332
        ENTRY;
333
        presto_dentry_slab =
334
                kmem_cache_create("presto_cache",
335
                                  sizeof(struct presto_dentry_data), 0,
336
                                  SLAB_HWCACHE_ALIGN, NULL,
337
                                  NULL);
338
        EXIT;
339
        return (presto_dentry_slab != NULL);
340
}
341
 
342
void presto_cleanup_ddata_cache(void)
343
{
344
        kmem_cache_destroy(presto_dentry_slab);
345
}

powered by: WebSVN 2.1.0

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