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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [autofs/] [root.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
/* -*- linux-c -*- --------------------------------------------------------- *
2
 *
3
 * linux/fs/autofs/root.c
4
 *
5
 *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
6
 *
7
 * This file is part of the Linux kernel and is made available under
8
 * the terms of the GNU General Public License, version 2, or at your
9
 * option, any later version, incorporated herein by reference.
10
 *
11
 * ------------------------------------------------------------------------- */
12
 
13
#include <linux/errno.h>
14
#include <linux/stat.h>
15
#include <linux/param.h>
16
#include <linux/sched.h>
17
#include <linux/smp_lock.h>
18
#include "autofs_i.h"
19
 
20
static int autofs_root_readdir(struct file *,void *,filldir_t);
21
static struct dentry *autofs_root_lookup(struct inode *,struct dentry *);
22
static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
23
static int autofs_root_unlink(struct inode *,struct dentry *);
24
static int autofs_root_rmdir(struct inode *,struct dentry *);
25
static int autofs_root_mkdir(struct inode *,struct dentry *,int);
26
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
27
 
28
struct file_operations autofs_root_operations = {
29
        read:           generic_read_dir,
30
        readdir:        autofs_root_readdir,
31
        ioctl:          autofs_root_ioctl,
32
};
33
 
34
struct inode_operations autofs_root_inode_operations = {
35
        lookup:         autofs_root_lookup,
36
        unlink:         autofs_root_unlink,
37
        symlink:        autofs_root_symlink,
38
        mkdir:          autofs_root_mkdir,
39
        rmdir:          autofs_root_rmdir,
40
};
41
 
42
static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
43
{
44
        struct autofs_dir_ent *ent = NULL;
45
        struct autofs_dirhash *dirhash;
46
        struct autofs_sb_info *sbi;
47
        struct inode * inode = filp->f_dentry->d_inode;
48
        off_t onr, nr;
49
 
50
        sbi = autofs_sbi(inode->i_sb);
51
        dirhash = &sbi->dirhash;
52
        nr = filp->f_pos;
53
 
54
        switch(nr)
55
        {
56
        case 0:
57
                if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
58
                        return 0;
59
                filp->f_pos = ++nr;
60
                /* fall through */
61
        case 1:
62
                if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
63
                        return 0;
64
                filp->f_pos = ++nr;
65
                /* fall through */
66
        default:
67
                while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
68
                        if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
69
                                if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
70
                                        return 0;
71
                                filp->f_pos = nr;
72
                        }
73
                }
74
                break;
75
        }
76
 
77
        return 0;
78
}
79
 
80
static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, struct autofs_sb_info *sbi)
81
{
82
        struct inode * inode;
83
        struct autofs_dir_ent *ent;
84
        int status = 0;
85
 
86
        if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
87
                do {
88
                        if ( status && dentry->d_inode ) {
89
                                if ( status != -ENOENT )
90
                                        printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
91
                                return 0; /* Try to get the kernel to invalidate this dentry */
92
                        }
93
 
94
                        /* Turn this into a real negative dentry? */
95
                        if (status == -ENOENT) {
96
                                dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
97
                                dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
98
                                return 1;
99
                        } else if (status) {
100
                                /* Return a negative dentry, but leave it "pending" */
101
                                return 1;
102
                        }
103
                        status = autofs_wait(sbi, &dentry->d_name);
104
                } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) );
105
        }
106
 
107
        /* Abuse this field as a pointer to the directory entry, used to
108
           find the expire list pointers */
109
        dentry->d_time = (unsigned long) ent;
110
 
111
        if (!dentry->d_inode) {
112
                inode = iget(sb, ent->ino);
113
                if (!inode) {
114
                        /* Failed, but leave pending for next time */
115
                        return 1;
116
                }
117
                dentry->d_inode = inode;
118
        }
119
 
120
        /* If this is a directory that isn't a mount point, bitch at the
121
           daemon and fix it in user space */
122
        if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
123
                return !autofs_wait(sbi, &dentry->d_name);
124
        }
125
 
126
        /* We don't update the usages for the autofs daemon itself, this
127
           is necessary for recursive autofs mounts */
128
        if ( !autofs_oz_mode(sbi) ) {
129
                autofs_update_usage(&sbi->dirhash,ent);
130
        }
131
 
132
        dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
133
        return 1;
134
}
135
 
136
 
137
/*
138
 * Revalidate is called on every cache lookup.  Some of those
139
 * cache lookups may actually happen while the dentry is not
140
 * yet completely filled in, and revalidate has to delay such
141
 * lookups..
142
 */
143
static int autofs_revalidate(struct dentry * dentry, int flags)
144
{
145
        struct inode * dir;
146
        struct autofs_sb_info *sbi;
147
        struct autofs_dir_ent *ent;
148
        int res;
149
 
150
        lock_kernel();
151
        dir = dentry->d_parent->d_inode;
152
        sbi = autofs_sbi(dir->i_sb);
153
 
154
        /* Pending dentry */
155
        if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
156
                if (autofs_oz_mode(sbi))
157
                        res = 1;
158
                else
159
                        res = try_to_fill_dentry(dentry, dir->i_sb, sbi);
160
                unlock_kernel();
161
                return res;
162
        }
163
 
164
        /* Negative dentry.. invalidate if "old" */
165
        if (!dentry->d_inode) {
166
                unlock_kernel();
167
                return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
168
        }
169
 
170
        /* Check for a non-mountpoint directory */
171
        if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
172
                if (autofs_oz_mode(sbi))
173
                        res = 1;
174
                else
175
                        res = try_to_fill_dentry(dentry, dir->i_sb, sbi);
176
                unlock_kernel();
177
                return res;
178
        }
179
 
180
        /* Update the usage list */
181
        if ( !autofs_oz_mode(sbi) ) {
182
                ent = (struct autofs_dir_ent *) dentry->d_time;
183
                if ( ent )
184
                        autofs_update_usage(&sbi->dirhash,ent);
185
        }
186
        unlock_kernel();
187
        return 1;
188
}
189
 
190
static struct dentry_operations autofs_dentry_operations = {
191
        d_revalidate:   autofs_revalidate,
192
};
193
 
194
static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
195
{
196
        struct autofs_sb_info *sbi;
197
        int oz_mode;
198
 
199
        DPRINTK(("autofs_root_lookup: name = "));
200
        autofs_say(dentry->d_name.name,dentry->d_name.len);
201
 
202
        if (dentry->d_name.len > NAME_MAX)
203
                return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
204
 
205
        sbi = autofs_sbi(dir->i_sb);
206
 
207
        oz_mode = autofs_oz_mode(sbi);
208
        DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
209
                 current->pid, current->pgrp, sbi->catatonic, oz_mode));
210
 
211
        /*
212
         * Mark the dentry incomplete, but add it. This is needed so
213
         * that the VFS layer knows about the dentry, and we can count
214
         * on catching any lookups through the revalidate.
215
         *
216
         * Let all the hard work be done by the revalidate function that
217
         * needs to be able to do this anyway..
218
         *
219
         * We need to do this before we release the directory semaphore.
220
         */
221
        dentry->d_op = &autofs_dentry_operations;
222
        dentry->d_flags |= DCACHE_AUTOFS_PENDING;
223
        d_add(dentry, NULL);
224
 
225
        up(&dir->i_sem);
226
        autofs_revalidate(dentry, 0);
227
        down(&dir->i_sem);
228
 
229
        /*
230
         * If we are still pending, check if we had to handle
231
         * a signal. If so we can force a restart..
232
         */
233
        if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
234
                if (signal_pending(current))
235
                        return ERR_PTR(-ERESTARTNOINTR);
236
        }
237
 
238
        /*
239
         * If this dentry is unhashed, then we shouldn't honour this
240
         * lookup even if the dentry is positive.  Returning ENOENT here
241
         * doesn't do the right thing for all system calls, but it should
242
         * be OK for the operations we permit from an autofs.
243
         */
244
        if ( dentry->d_inode && d_unhashed(dentry) )
245
                return ERR_PTR(-ENOENT);
246
 
247
        return NULL;
248
}
249
 
250
static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
251
{
252
        struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
253
        struct autofs_dirhash *dh = &sbi->dirhash;
254
        struct autofs_dir_ent *ent;
255
        unsigned int n;
256
        int slsize;
257
        struct autofs_symlink *sl;
258
 
259
        DPRINTK(("autofs_root_symlink: %s <- ", symname));
260
        autofs_say(dentry->d_name.name,dentry->d_name.len);
261
 
262
        if ( !autofs_oz_mode(sbi) )
263
                return -EACCES;
264
 
265
        if ( autofs_hash_lookup(dh, &dentry->d_name) )
266
                return -EEXIST;
267
 
268
        n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
269
        if ( n >= AUTOFS_MAX_SYMLINKS )
270
                return -ENOSPC;
271
 
272
        set_bit(n,sbi->symlink_bitmap);
273
        sl = &sbi->symlink[n];
274
        sl->len = strlen(symname);
275
        sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
276
        if ( !sl->data ) {
277
                clear_bit(n,sbi->symlink_bitmap);
278
                return -ENOSPC;
279
        }
280
 
281
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
282
        if ( !ent ) {
283
                kfree(sl->data);
284
                clear_bit(n,sbi->symlink_bitmap);
285
                return -ENOSPC;
286
        }
287
 
288
        ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
289
        if ( !ent->name ) {
290
                kfree(sl->data);
291
                kfree(ent);
292
                clear_bit(n,sbi->symlink_bitmap);
293
                return -ENOSPC;
294
        }
295
 
296
        memcpy(sl->data,symname,slsize);
297
        sl->mtime = CURRENT_TIME;
298
 
299
        ent->ino = AUTOFS_FIRST_SYMLINK + n;
300
        ent->hash = dentry->d_name.hash;
301
        memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
302
        ent->dentry = NULL;     /* We don't keep the dentry for symlinks */
303
 
304
        autofs_hash_insert(dh,ent);
305
        d_instantiate(dentry, iget(dir->i_sb,ent->ino));
306
 
307
        return 0;
308
}
309
 
310
/*
311
 * NOTE!
312
 *
313
 * Normal filesystems would do a "d_delete()" to tell the VFS dcache
314
 * that the file no longer exists. However, doing that means that the
315
 * VFS layer can turn the dentry into a negative dentry, which we
316
 * obviously do not want (we're dropping the entry not because it
317
 * doesn't exist, but because it has timed out).
318
 *
319
 * Also see autofs_root_rmdir()..
320
 */
321
static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
322
{
323
        struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
324
        struct autofs_dirhash *dh = &sbi->dirhash;
325
        struct autofs_dir_ent *ent;
326
        unsigned int n;
327
 
328
        /* This allows root to remove symlinks */
329
        if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
330
                return -EACCES;
331
 
332
        ent = autofs_hash_lookup(dh, &dentry->d_name);
333
        if ( !ent )
334
                return -ENOENT;
335
 
336
        n = ent->ino - AUTOFS_FIRST_SYMLINK;
337
        if ( n >= AUTOFS_MAX_SYMLINKS )
338
                return -EISDIR; /* It's a directory, dummy */
339
        if ( !test_bit(n,sbi->symlink_bitmap) )
340
                return -EINVAL; /* Nonexistent symlink?  Shouldn't happen */
341
 
342
        dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL;
343
        autofs_hash_delete(ent);
344
        clear_bit(n,sbi->symlink_bitmap);
345
        kfree(sbi->symlink[n].data);
346
        d_drop(dentry);
347
 
348
        return 0;
349
}
350
 
351
static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
352
{
353
        struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
354
        struct autofs_dirhash *dh = &sbi->dirhash;
355
        struct autofs_dir_ent *ent;
356
 
357
        if ( !autofs_oz_mode(sbi) )
358
                return -EACCES;
359
 
360
        ent = autofs_hash_lookup(dh, &dentry->d_name);
361
        if ( !ent )
362
                return -ENOENT;
363
 
364
        if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO )
365
                return -ENOTDIR; /* Not a directory */
366
 
367
        if ( ent->dentry != dentry ) {
368
                printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
369
        }
370
 
371
        dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
372
        autofs_hash_delete(ent);
373
        dir->i_nlink--;
374
        d_drop(dentry);
375
 
376
        return 0;
377
}
378
 
379
static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
380
{
381
        struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
382
        struct autofs_dirhash *dh = &sbi->dirhash;
383
        struct autofs_dir_ent *ent;
384
        ino_t ino;
385
 
386
        if ( !autofs_oz_mode(sbi) )
387
                return -EACCES;
388
 
389
        ent = autofs_hash_lookup(dh, &dentry->d_name);
390
        if ( ent )
391
                return -EEXIST;
392
 
393
        if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
394
                printk("autofs: Out of inode numbers -- what the heck did you do??\n");
395
                return -ENOSPC;
396
        }
397
        ino = sbi->next_dir_ino++;
398
 
399
        ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
400
        if ( !ent )
401
                return -ENOSPC;
402
 
403
        ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
404
        if ( !ent->name ) {
405
                kfree(ent);
406
                return -ENOSPC;
407
        }
408
 
409
        ent->hash = dentry->d_name.hash;
410
        memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len));
411
        ent->ino = ino;
412
        ent->dentry = dentry;
413
        autofs_hash_insert(dh,ent);
414
 
415
        dir->i_nlink++;
416
        d_instantiate(dentry, iget(dir->i_sb,ino));
417
 
418
        return 0;
419
}
420
 
421
/* Get/set timeout ioctl() operation */
422
static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi,
423
                                         unsigned long *p)
424
{
425
        unsigned long ntimeout;
426
 
427
        if (get_user(ntimeout, p) ||
428
            put_user(sbi->exp_timeout / HZ, p))
429
                return -EFAULT;
430
 
431
        if ( ntimeout > ULONG_MAX/HZ )
432
                sbi->exp_timeout = 0;
433
        else
434
                sbi->exp_timeout = ntimeout * HZ;
435
 
436
        return 0;
437
}
438
 
439
/* Return protocol version */
440
static inline int autofs_get_protover(int *p)
441
{
442
        return put_user(AUTOFS_PROTO_VERSION, p);
443
}
444
 
445
/* Perform an expiry operation */
446
static inline int autofs_expire_run(struct super_block *sb,
447
                                    struct autofs_sb_info *sbi,
448
                                    struct vfsmount *mnt,
449
                                    struct autofs_packet_expire *pkt_p)
450
{
451
        struct autofs_dir_ent *ent;
452
        struct autofs_packet_expire pkt;
453
 
454
        memset(&pkt,0,sizeof pkt);
455
 
456
        pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
457
        pkt.hdr.type = autofs_ptype_expire;
458
 
459
        if ( !sbi->exp_timeout ||
460
             !(ent = autofs_expire(sb,sbi,mnt)) )
461
                return -EAGAIN;
462
 
463
        pkt.len = ent->len;
464
        memcpy(pkt.name, ent->name, pkt.len);
465
        pkt.name[pkt.len] = '\0';
466
 
467
        if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
468
                return -EFAULT;
469
 
470
        return 0;
471
}
472
 
473
/*
474
 * ioctl()'s on the root directory is the chief method for the daemon to
475
 * generate kernel reactions
476
 */
477
static int autofs_root_ioctl(struct inode *inode, struct file *filp,
478
                             unsigned int cmd, unsigned long arg)
479
{
480
        struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);
481
 
482
        DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));
483
 
484
        if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
485
             _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
486
                return -ENOTTY;
487
 
488
        if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
489
                return -EPERM;
490
 
491
        switch(cmd) {
492
        case AUTOFS_IOC_READY:  /* Wait queue: go ahead and retry */
493
                return autofs_wait_release(sbi,(autofs_wqt_t)arg,0);
494
        case AUTOFS_IOC_FAIL:   /* Wait queue: fail with ENOENT */
495
                return autofs_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT);
496
        case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
497
                autofs_catatonic_mode(sbi);
498
                return 0;
499
        case AUTOFS_IOC_PROTOVER: /* Get protocol version */
500
                return autofs_get_protover((int *)arg);
501
        case AUTOFS_IOC_SETTIMEOUT:
502
                return autofs_get_set_timeout(sbi,(unsigned long *)arg);
503
        case AUTOFS_IOC_EXPIRE:
504
                return autofs_expire_run(inode->i_sb, sbi, filp->f_vfsmnt,
505
                                         (struct autofs_packet_expire *)arg);
506
        default:
507
                return -ENOSYS;
508
        }
509
}

powered by: WebSVN 2.1.0

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