~ubuntu-branches/ubuntu/vivid/aufs/vivid

« back to all changes in this revision

Viewing changes to fs/aufs/br_nfs.c

  • Committer: Bazaar Package Importer
  • Author(s): Julian Andres Klode
  • Date: 2008-05-06 18:35:50 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20080506183550-0b6c974kkgc46oeh
Tags: 0+20080506-1
* New upstream release, supports Kernel 2.6.25 (Closes: #479717)
* Fix building with older Kernels (Closes: #475042)
* Update the patches 01, 04 and 07 to also patch fs/aufs25

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008 Junjiro Okajima
 
3
 *
 
4
 * This program, aufs is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
/*
 
20
 * lookup functions for NFS branch in linux-2.6.19 and later
 
21
 *
 
22
 * $Id: br_nfs.c,v 1.2 2008/04/13 23:36:34 sfjro Exp $
 
23
 */
 
24
 
 
25
#include "aufs.h"
 
26
 
 
27
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) \
 
28
        || !defined(CONFIG_AUFS_BR_NFS)
 
29
#error mis-configuraion or Makefile
 
30
#endif
 
31
 
 
32
/* ---------------------------------------------------------------------- */
 
33
 
 
34
static struct file *au_find_h_intent(struct au_hdentry *hd, struct file *file)
 
35
{
 
36
        struct file *h_file, *hf;
 
37
        struct au_hdintent *hdi, *tmp;
 
38
 
 
39
        LKTRTrace("%.*s\n", AuDLNPair(hd->hd_dentry));
 
40
 
 
41
        h_file = NULL;
 
42
        spin_lock(&hd->hd_lock);
 
43
        list_for_each_entry_safe(hdi, tmp, hd->hd_intent_list, hdi_list) {
 
44
                hf = hdi->hdi_file[AuIntent_BRANCH];
 
45
                if (hdi->hdi_file[AuIntent_AUFS] == file
 
46
                    && hf->f_dentry == hd->hd_dentry) {
 
47
                        h_file = hf;
 
48
                        list_del(&hdi->hdi_list);
 
49
                        kfree(hdi);
 
50
                        break;
 
51
                }
 
52
        }
 
53
        spin_unlock(&hd->hd_lock);
 
54
 
 
55
        return h_file;
 
56
}
 
57
 
 
58
struct file *au_h_intent(struct dentry *dentry, aufs_bindex_t bindex,
 
59
                         struct file *file)
 
60
{
 
61
        struct file *h_file;
 
62
        struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
 
63
 
 
64
        LKTRTrace("%.*s, b%d, f %p\n", AuDLNPair(dentry), bindex, file);
 
65
        DiMustAnyLock(dentry);
 
66
        AuDebugOn(bindex < au_di(dentry)->di_bstart
 
67
                  || bindex > au_di(dentry)->di_bend);
 
68
 
 
69
        h_file = NULL;
 
70
        if (!hd->hd_intent_list || !file)
 
71
                return h_file; /* success */
 
72
 
 
73
        //AuDebugOn(au_test_wkq(current));
 
74
        h_file = au_find_h_intent(hd, file);
 
75
        //AuDbgFile(h_file);
 
76
        return h_file;
 
77
}
 
78
 
 
79
static int au_set_h_intent(struct dentry *dentry, aufs_bindex_t bindex,
 
80
                           struct file *file, struct file *h_file)
 
81
{
 
82
        int err;
 
83
        struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
 
84
        struct au_hdintent *hdi;
 
85
        struct file *hf;
 
86
 
 
87
        LKTRTrace("%.*s, b%d, f %p\n", AuDLNPair(dentry), bindex, file);
 
88
        /* d_revalidate() holds read_lock */
 
89
        //DiMustWriteLock(dentry);
 
90
        AuDebugOn(bindex < au_di(dentry)->di_bstart
 
91
                  || bindex > au_di(dentry)->di_bend
 
92
                  || !file
 
93
                  || !h_file
 
94
                  /* || au_test_wkq(current) */);
 
95
 
 
96
        err = -ENOMEM;
 
97
        if (hd->hd_intent_list) {
 
98
                while (1) {
 
99
                        hf = au_find_h_intent(hd, file);
 
100
                        if (!hf)
 
101
                                break;
 
102
#if 0 //def CONFIG_AUFS_DEBUG
 
103
                        au_debug_on();
 
104
                        DbgDentry(dentry);
 
105
                        DbgFile(hf);
 
106
                        au_debug_off();
 
107
#endif
 
108
                        fput(hf);
 
109
                        AuWarn("freed hfile %.*s b%d left\n",
 
110
                               AuDLNPair(dentry), bindex);
 
111
                }
 
112
        } else {
 
113
                spin_lock(&hd->hd_lock);
 
114
                if (!hd->hd_intent_list) {
 
115
                        hd->hd_intent_list
 
116
                                = kmalloc(sizeof(*hd->hd_intent_list),
 
117
                                          GFP_ATOMIC);
 
118
                        if (unlikely(!hd->hd_intent_list)) {
 
119
                                spin_unlock(&hd->hd_lock);
 
120
                                goto out;
 
121
                        }
 
122
                        INIT_LIST_HEAD(hd->hd_intent_list);
 
123
                }
 
124
                spin_unlock(&hd->hd_lock);
 
125
        }
 
126
 
 
127
        hdi = kmalloc(sizeof(*hdi), GFP_TEMPORARY);
 
128
        if (unlikely(!hdi))
 
129
                goto out;
 
130
 
 
131
        err = 0;
 
132
        //hdi->hdi_pid = current->pid;
 
133
        hdi->hdi_file[AuIntent_AUFS] = file;
 
134
        hdi->hdi_file[AuIntent_BRANCH] = h_file;
 
135
        spin_lock(&hd->hd_lock);
 
136
        list_add(&hdi->hdi_list, hd->hd_intent_list);
 
137
        spin_unlock(&hd->hd_lock);
 
138
        //AuDbgDentry(dentry);
 
139
        //AuDbgFile(h_file);
 
140
 
 
141
 out:
 
142
        AuTraceErr(err);
 
143
        return err;
 
144
}
 
145
 
 
146
int au_br_nfs_h_intent(struct file *nd_file, struct dentry *dentry,
 
147
                       aufs_bindex_t bindex, struct nameidata *nd)
 
148
{
 
149
        int err;
 
150
 
 
151
        AuTraceEnter();
 
152
 
 
153
        err = 0;
 
154
        if (!nd_file)
 
155
                goto out;
 
156
 
 
157
        AuDebugOn(!nd);
 
158
        err = au_set_h_intent(dentry, bindex, nd->intent.open.file, nd_file);
 
159
        if (unlikely(err)) {
 
160
                fput(nd_file);
 
161
                au_set_h_dptr(dentry, bindex, NULL);
 
162
                //todo: update bstart and bend
 
163
        }
 
164
 
 
165
 out:
 
166
        AuTraceErr(err);
 
167
        return err;
 
168
}
 
169
 
 
170
/* ---------------------------------------------------------------------- */
 
171
 
 
172
void au_hintent_put(struct au_hdentry *hd, int do_free)
 
173
{
 
174
        struct au_hdintent *hdi, *tmp;
 
175
        struct file *hf;
 
176
 
 
177
        if (unlikely(hd->hd_intent_list)) {
 
178
                // no spin lock
 
179
                list_for_each_entry_safe(hdi, tmp, hd->hd_intent_list,
 
180
                                         hdi_list) {
 
181
                        LKTRTrace("hdi %p\n", hdi);
 
182
                        hf = hdi->hdi_file[AuIntent_BRANCH];
 
183
                        if (unlikely(hf))
 
184
                                fput(hf);
 
185
                        //list_del(&hdi->hdi_list);
 
186
                        kfree(hdi);
 
187
                }
 
188
                if (do_free)
 
189
                        kfree(hd->hd_intent_list);
 
190
        }
 
191
}
 
192
 
 
193
/* ---------------------------------------------------------------------- */
 
194
 
 
195
#if 0
 
196
/* subset of nameidata */
 
197
struct au_ndsub {
 
198
        struct dentry   *dentry;
 
199
        struct vfsmount *mnt;
 
200
        unsigned int    flags;
 
201
 
 
202
        union {
 
203
                struct open_intent open;
 
204
        } intent;
 
205
};
 
206
 
 
207
static void au_ndsub_restore(struct nameidata *nd, struct au_ndsub *save)
 
208
{
 
209
        nd->dentry = save->dentry;
 
210
        nd->mnt = save->mnt;
 
211
        nd->flags = save->flags;
 
212
        nd->intent = save->intent;
 
213
}
 
214
#endif
 
215
 
 
216
int au_fake_intent(/* struct au_ndsub *save,  */struct nameidata *nd,
 
217
                   int perm)
 
218
{
 
219
        int err;
 
220
 
 
221
        LKTRTrace("perm %d\n", perm);
 
222
 
 
223
        err = 0;
 
224
#if 0
 
225
        save->dentry = nd->dentry;
 
226
        save->mnt = nd->mnt;
 
227
        save->flags = nd->flags;
 
228
        save->intent = nd->intent;
 
229
#endif
 
230
 
 
231
        nd->intent.open.file = NULL;
 
232
        if (nd->flags & LOOKUP_OPEN) {
 
233
                err = -ENFILE;
 
234
                nd->intent.open.file = get_empty_filp();
 
235
                if (unlikely(!nd->intent.open.file)) {
 
236
                        //nd->intent.open.file = save->intent.open.file;
 
237
                        goto out;
 
238
                }
 
239
 
 
240
                err = 0;
 
241
                if (!au_br_writable(perm)) {
 
242
                        nd->intent.open.flags = au_file_roflags
 
243
                                (nd->intent.open.flags) | FMODE_READ;
 
244
                        nd->flags &= ~LOOKUP_CREATE;
 
245
                }
 
246
        }
 
247
 
 
248
 out:
 
249
        AuTraceErr(err);
 
250
        return err;
 
251
}
 
252
 
 
253
int au_hin_after_reval(struct nameidata *nd, struct dentry *dentry,
 
254
                       aufs_bindex_t bindex, struct file *file)
 
255
{
 
256
        int err;
 
257
 
 
258
        LKTRTrace("nd %p, %.*s, b%d, f %d\n",
 
259
                  nd, AuDLNPair(dentry), bindex, !!file);
 
260
 
 
261
        err = 0;
 
262
        if ((nd->flags & LOOKUP_OPEN)
 
263
            && nd->intent.open.file
 
264
            && !IS_ERR(nd->intent.open.file)) {
 
265
                if (nd->intent.open.file->f_dentry) {
 
266
                        //AuDbgFile(nd->intent.open.file);
 
267
                        err = au_set_h_intent(dentry, bindex, file,
 
268
                                              nd->intent.open.file);
 
269
                        if (!err)
 
270
                                nd->intent.open.file = NULL;
 
271
                }
 
272
                if (unlikely(nd->intent.open.file))
 
273
                        put_filp(nd->intent.open.file);
 
274
        }
 
275
 
 
276
        return err;
 
277
}
 
278
 
 
279
#ifdef CONFIG_AUFS_DLGT
 
280
struct au_lookup_hash_args {
 
281
        struct dentry **errp;
 
282
        struct qstr *name;
 
283
        struct dentry *base;
 
284
        struct nameidata *nd;
 
285
};
 
286
 
 
287
static void au_call_lookup_hash(void *args)
 
288
{
 
289
        struct au_lookup_hash_args *a = args;
 
290
        *a->errp = vfsub__lookup_hash(a->name, a->base, a->nd);
 
291
}
 
292
 
 
293
static struct dentry *
 
294
au_lkup_hash_dlgt(struct qstr *this, struct dentry *parent,
 
295
                  struct nameidata *nd, unsigned int flags)
 
296
{
 
297
        struct dentry *dentry;
 
298
        int dirperm1;
 
299
 
 
300
        dirperm1 = au_ftest_ndx(flags, DIRPERM1);
 
301
        if (!dirperm1 && !au_ftest_ndx(flags, DLGT))
 
302
                dentry = vfsub__lookup_hash(this, parent, nd);
 
303
        else {
 
304
                int wkq_err;
 
305
                struct au_lookup_hash_args args = {
 
306
                        .errp   = &dentry,
 
307
                        .name   = this,
 
308
                        .base   = parent,
 
309
                        .nd     = nd
 
310
                };
 
311
                wkq_err = au_wkq_wait(au_call_lookup_hash, &args,
 
312
                                      /*dlgt*/!dirperm1);
 
313
                if (unlikely(wkq_err))
 
314
                        dentry = ERR_PTR(wkq_err);
 
315
        }
 
316
 
 
317
        AuTraceErrPtr(dentry);
 
318
        return dentry;
 
319
}
 
320
#else
 
321
static struct dentry *
 
322
au_lkup_hash_dlgt(struct qstr *this, struct dentry *parent,
 
323
                  struct nameidata *nd, unsigned int flags)
 
324
{
 
325
        return vfsub__lookup_hash(this, parent, nd);
 
326
}
 
327
#endif /* CONFIG_AUFS_DLGT */
 
328
 
 
329
struct dentry *au_lkup_hash(const char *name, struct dentry *parent,
 
330
                            int len, struct au_ndx *ndx)
 
331
{
 
332
        struct dentry *dentry;
 
333
        char *p;
 
334
        unsigned long hash;
 
335
        struct qstr this;
 
336
        unsigned int c;
 
337
        struct nameidata tmp_nd, *ndo;
 
338
        int err;
 
339
 
 
340
        LKTRTrace("%.*s/%.*s\n", AuDLNPair(parent), len, name);
 
341
 
 
342
        dentry = ERR_PTR(-EACCES);
 
343
        this.name = name;
 
344
        this.len = len;
 
345
        if (unlikely(!len))
 
346
                goto out;
 
347
 
 
348
        p = (void *)name;
 
349
        hash = init_name_hash();
 
350
        while (len--) {
 
351
                c = *p++;
 
352
                if (unlikely(c == '/' || c == '\0'))
 
353
                        goto out;
 
354
                hash = partial_name_hash(c, hash);
 
355
        }
 
356
        this.hash = end_name_hash(hash);
 
357
 
 
358
        ndo = ndx->nd;
 
359
        if (ndo) {
 
360
                tmp_nd = *ndo;
 
361
                err = au_fake_intent(&tmp_nd, ndx->br->br_perm);
 
362
                dentry = ERR_PTR(err);
 
363
                if (unlikely(err))
 
364
                        goto out_intent;
 
365
        } else
 
366
                memset(&tmp_nd, 0, sizeof(tmp_nd));
 
367
 
 
368
        tmp_nd.dentry = dget(parent);
 
369
        tmp_nd.mnt = mntget(ndx->nfsmnt);
 
370
        dentry = au_lkup_hash_dlgt(&this, parent, &tmp_nd, ndx->flags);
 
371
        if (0 && !IS_ERR(dentry))
 
372
                AuDbgDentry(dentry);
 
373
        if (!IS_ERR(dentry)) {
 
374
                /* why negative dentry for a new dir was unhashed? */
 
375
                if (unlikely(d_unhashed(dentry)))
 
376
                        d_rehash(dentry);
 
377
                if (tmp_nd.intent.open.file
 
378
                    && tmp_nd.intent.open.file->f_dentry) {
 
379
                        //AuDbgFile(tmp_nd.intent.open.file);
 
380
                        ndx->nd_file = tmp_nd.intent.open.file;
 
381
                        tmp_nd.intent.open.file = NULL;
 
382
                        //au_br_get(ndx->br);
 
383
                }
 
384
        }
 
385
        path_release(&tmp_nd);
 
386
 
 
387
 out_intent:
 
388
        if (tmp_nd.intent.open.file)
 
389
                put_filp(tmp_nd.intent.open.file);
 
390
 out:
 
391
        AuTraceErrPtr(dentry);
 
392
        return dentry;
 
393
}