The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/autofs4/root.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* -*- c -*- --------------------------------------------------------------- *
    2  *
    3  * linux/fs/autofs/root.c
    4  *
    5  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
    6  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
    7  *
    8  * This file is part of the Linux kernel and is made available under
    9  * the terms of the GNU General Public License, version 2, or at your
   10  * option, any later version, incorporated herein by reference.
   11  *
   12  * ------------------------------------------------------------------------- */
   13 
   14 #include <linux/errno.h>
   15 #include <linux/stat.h>
   16 #include <linux/param.h>
   17 #include <linux/sched.h>
   18 #include <linux/smp_lock.h>
   19 #include "autofs_i.h"
   20 
   21 static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *);
   22 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
   23 static int autofs4_dir_unlink(struct inode *,struct dentry *);
   24 static int autofs4_dir_rmdir(struct inode *,struct dentry *);
   25 static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
   26 static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
   27 static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *);
   28 
   29 struct file_operations autofs4_root_operations = {
   30         open:           dcache_dir_open,
   31         release:        dcache_dir_close,
   32         llseek:         dcache_dir_lseek,
   33         read:           generic_read_dir,
   34         readdir:        dcache_readdir,
   35         fsync:          dcache_dir_fsync,
   36         ioctl:          autofs4_root_ioctl,
   37 };
   38 
   39 struct inode_operations autofs4_root_inode_operations = {
   40         lookup:         autofs4_root_lookup,
   41         unlink:         autofs4_dir_unlink,
   42         symlink:        autofs4_dir_symlink,
   43         mkdir:          autofs4_dir_mkdir,
   44         rmdir:          autofs4_dir_rmdir,
   45 };
   46 
   47 struct inode_operations autofs4_dir_inode_operations = {
   48         lookup:         autofs4_dir_lookup,
   49         unlink:         autofs4_dir_unlink,
   50         symlink:        autofs4_dir_symlink,
   51         mkdir:          autofs4_dir_mkdir,
   52         rmdir:          autofs4_dir_rmdir,
   53 };
   54 
   55 /* Update usage from here to top of tree, so that scan of
   56    top-level directories will give a useful result */
   57 static void autofs4_update_usage(struct dentry *dentry)
   58 {
   59         struct dentry *top = dentry->d_sb->s_root;
   60 
   61         for(; dentry != top; dentry = dentry->d_parent) {
   62                 struct autofs_info *ino = autofs4_dentry_ino(dentry);
   63 
   64                 if (ino) {
   65                         update_atime(dentry->d_inode);
   66                         ino->last_used = jiffies;
   67                 }
   68         }
   69 }
   70 
   71 static int try_to_fill_dentry(struct dentry *dentry, 
   72                               struct super_block *sb,
   73                               struct autofs_sb_info *sbi)
   74 {
   75         struct autofs_info *de_info = autofs4_dentry_ino(dentry);
   76         int status = 0;
   77 
   78         /* Block on any pending expiry here; invalidate the dentry
   79            when expiration is done to trigger mount request with a new
   80            dentry */
   81         if (de_info && (de_info->flags & AUTOFS_INF_EXPIRING)) {
   82                 DPRINTK(("try_to_fill_entry: waiting for expire %p name=%.*s, flags&PENDING=%s de_info=%p de_info->flags=%x\n",
   83                          dentry, dentry->d_name.len, dentry->d_name.name, 
   84                          dentry->d_flags & DCACHE_AUTOFS_PENDING?"t":"f",
   85                          de_info, de_info?de_info->flags:0));
   86                 status = autofs4_wait(sbi, &dentry->d_name, NFY_NONE);
   87                 
   88                 DPRINTK(("try_to_fill_entry: expire done status=%d\n", status));
   89                 
   90                 return 0;
   91         }
   92 
   93         DPRINTK(("try_to_fill_entry: dentry=%p %.*s ino=%p\n", 
   94                  dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode));
   95 
   96         /* Wait for a pending mount, triggering one if there isn't one already */
   97         while(dentry->d_inode == NULL) {
   98                 DPRINTK(("try_to_fill_entry: waiting for mount name=%.*s, de_info=%p de_info->flags=%x\n",
   99                          dentry->d_name.len, dentry->d_name.name, 
  100                          de_info, de_info?de_info->flags:0));
  101                 status = autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT);
  102                  
  103                 DPRINTK(("try_to_fill_entry: mount done status=%d\n", status));
  104 
  105                 if (status && dentry->d_inode)
  106                         return 0; /* Try to get the kernel to invalidate this dentry */
  107                 
  108                 /* Turn this into a real negative dentry? */
  109                 if (status == -ENOENT) {
  110                         dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
  111                         dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
  112                         return 1;
  113                 } else if (status) {
  114                         /* Return a negative dentry, but leave it "pending" */
  115                         return 1;
  116                 }
  117         }
  118 
  119         /* If this is an unused directory that isn't a mount point,
  120            bitch at the daemon and fix it in user space */
  121         spin_lock(&dcache_lock);
  122         if (S_ISDIR(dentry->d_inode->i_mode) &&
  123             !d_mountpoint(dentry) && 
  124             list_empty(&dentry->d_subdirs)) {
  125                 DPRINTK(("try_to_fill_entry: mounting existing dir\n"));
  126                 spin_unlock(&dcache_lock);
  127                 return autofs4_wait(sbi, &dentry->d_name, NFY_MOUNT) == 0;
  128         }
  129         spin_unlock(&dcache_lock);
  130 
  131         /* We don't update the usages for the autofs daemon itself, this
  132            is necessary for recursive autofs mounts */
  133         if (!autofs4_oz_mode(sbi))
  134                 autofs4_update_usage(dentry);
  135 
  136         dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
  137         return 1;
  138 }
  139 
  140 
  141 /*
  142  * Revalidate is called on every cache lookup.  Some of those
  143  * cache lookups may actually happen while the dentry is not
  144  * yet completely filled in, and revalidate has to delay such
  145  * lookups..
  146  */
  147 static int autofs4_root_revalidate(struct dentry * dentry, int flags)
  148 {
  149         struct inode * dir = dentry->d_parent->d_inode;
  150         struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
  151         int oz_mode = autofs4_oz_mode(sbi);
  152 
  153         /* Pending dentry */
  154         if (autofs4_ispending(dentry)) {
  155                 if (autofs4_oz_mode(sbi))
  156                         return 1;
  157                 else
  158                         return try_to_fill_dentry(dentry, dir->i_sb, sbi);
  159         }
  160 
  161         /* Negative dentry.. invalidate if "old" */
  162         if (dentry->d_inode == NULL)
  163                 return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
  164 
  165         /* Check for a non-mountpoint directory with no contents */
  166         spin_lock(&dcache_lock);
  167         if (S_ISDIR(dentry->d_inode->i_mode) &&
  168             !d_mountpoint(dentry) && 
  169             list_empty(&dentry->d_subdirs)) {
  170                 DPRINTK(("autofs_root_revalidate: dentry=%p %.*s, emptydir\n",
  171                          dentry, dentry->d_name.len, dentry->d_name.name));
  172                 spin_unlock(&dcache_lock);
  173                 if (oz_mode)
  174                         return 1;
  175                 else
  176                         return try_to_fill_dentry(dentry, dir->i_sb, sbi);
  177         }
  178         spin_unlock(&dcache_lock);
  179 
  180         /* Update the usage list */
  181         if (!oz_mode)
  182                 autofs4_update_usage(dentry);
  183 
  184         return 1;
  185 }
  186 
  187 static int autofs4_revalidate(struct dentry *dentry, int flags)
  188 {
  189         struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
  190 
  191         if (!autofs4_oz_mode(sbi))
  192                 autofs4_update_usage(dentry);
  193 
  194         return 1;
  195 }
  196 
  197 static void autofs4_dentry_release(struct dentry *de)
  198 {
  199         struct autofs_info *inf;
  200 
  201         lock_kernel();
  202 
  203         DPRINTK(("autofs4_dentry_release: releasing %p\n", de));
  204 
  205         inf = autofs4_dentry_ino(de);
  206         de->d_fsdata = NULL;
  207 
  208         if (inf) {
  209                 inf->dentry = NULL;
  210                 inf->inode = NULL;
  211 
  212                 autofs4_free_ino(inf);
  213         }
  214 
  215         unlock_kernel();
  216 }
  217 
  218 /* For dentries of directories in the root dir */
  219 static struct dentry_operations autofs4_root_dentry_operations = {
  220         d_revalidate:   autofs4_root_revalidate,
  221         d_release:      autofs4_dentry_release,
  222 };
  223 
  224 /* For other dentries */
  225 static struct dentry_operations autofs4_dentry_operations = {
  226         d_revalidate:   autofs4_revalidate,
  227         d_release:      autofs4_dentry_release,
  228 };
  229 
  230 /* Lookups in non-root dirs never find anything - if it's there, it's
  231    already in the dcache */
  232 static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry)
  233 {
  234 #if 0
  235         DPRINTK(("autofs_dir_lookup: ignoring lookup of %.*s/%.*s\n",
  236                  dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
  237                  dentry->d_name.len, dentry->d_name.name));
  238 #endif
  239 
  240         dentry->d_fsdata = NULL;
  241         d_add(dentry, NULL);
  242         return NULL;
  243 }
  244 
  245 /* Lookups in the root directory */
  246 static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry)
  247 {
  248         struct autofs_sb_info *sbi;
  249         int oz_mode;
  250 
  251         DPRINTK(("autofs_root_lookup: name = %.*s\n", 
  252                  dentry->d_name.len, dentry->d_name.name));
  253 
  254         if (dentry->d_name.len > NAME_MAX)
  255                 return ERR_PTR(-ENAMETOOLONG);/* File name too long to exist */
  256 
  257         sbi = autofs4_sbi(dir->i_sb);
  258 
  259         oz_mode = autofs4_oz_mode(sbi);
  260         DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
  261                  current->pid, current->pgrp, sbi->catatonic, oz_mode));
  262 
  263         /*
  264          * Mark the dentry incomplete, but add it. This is needed so
  265          * that the VFS layer knows about the dentry, and we can count
  266          * on catching any lookups through the revalidate.
  267          *
  268          * Let all the hard work be done by the revalidate function that
  269          * needs to be able to do this anyway..
  270          *
  271          * We need to do this before we release the directory semaphore.
  272          */
  273         dentry->d_op = &autofs4_root_dentry_operations;
  274 
  275         if (!oz_mode)
  276                 dentry->d_flags |= DCACHE_AUTOFS_PENDING;
  277         dentry->d_fsdata = NULL;
  278         d_add(dentry, NULL);
  279 
  280         if (dentry->d_op && dentry->d_op->d_revalidate) {
  281                 up(&dir->i_sem);
  282                 (dentry->d_op->d_revalidate)(dentry, 0);
  283                 down(&dir->i_sem);
  284         }
  285 
  286         /*
  287          * If we are still pending, check if we had to handle
  288          * a signal. If so we can force a restart..
  289          */
  290         if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
  291                 if (signal_pending(current))
  292                         return ERR_PTR(-ERESTARTNOINTR);
  293         }
  294 
  295         /*
  296          * If this dentry is unhashed, then we shouldn't honour this
  297          * lookup even if the dentry is positive.  Returning ENOENT here
  298          * doesn't do the right thing for all system calls, but it should
  299          * be OK for the operations we permit from an autofs.
  300          */
  301         if ( dentry->d_inode && d_unhashed(dentry) )
  302                 return ERR_PTR(-ENOENT);
  303 
  304         return NULL;
  305 }
  306 
  307 static int autofs4_dir_symlink(struct inode *dir, 
  308                                struct dentry *dentry,
  309                                const char *symname)
  310 {
  311         struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
  312         struct autofs_info *ino = autofs4_dentry_ino(dentry);
  313         struct inode *inode;
  314         char *cp;
  315 
  316         DPRINTK(("autofs_dir_symlink: %s <- %.*s\n", symname, 
  317                  dentry->d_name.len, dentry->d_name.name));
  318 
  319         if (!autofs4_oz_mode(sbi))
  320                 return -EACCES;
  321 
  322         ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
  323         if (ino == NULL)
  324                 return -ENOSPC;
  325 
  326         ino->size = strlen(symname);
  327         ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL);
  328 
  329         if (cp == NULL) {
  330                 kfree(ino);
  331                 return -ENOSPC;
  332         }
  333 
  334         strcpy(cp, symname);
  335 
  336         inode = autofs4_get_inode(dir->i_sb, ino);
  337         d_instantiate(dentry, inode);
  338 
  339         if (dir == dir->i_sb->s_root->d_inode)
  340                 dentry->d_op = &autofs4_root_dentry_operations;
  341         else
  342                 dentry->d_op = &autofs4_dentry_operations;
  343 
  344         dentry->d_fsdata = ino;
  345         ino->dentry = dget(dentry);
  346         ino->inode = inode;
  347 
  348         dir->i_mtime = CURRENT_TIME;
  349 
  350         return 0;
  351 }
  352 
  353 /*
  354  * NOTE!
  355  *
  356  * Normal filesystems would do a "d_delete()" to tell the VFS dcache
  357  * that the file no longer exists. However, doing that means that the
  358  * VFS layer can turn the dentry into a negative dentry.  We don't want
  359  * this, because since the unlink is probably the result of an expire.
  360  * We simply d_drop it, which allows the dentry lookup to remount it
  361  * if necessary.
  362  *
  363  * If a process is blocked on the dentry waiting for the expire to finish,
  364  * it will invalidate the dentry and try to mount with a new one.
  365  *
  366  * Also see autofs_dir_rmdir().. 
  367  */
  368 static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
  369 {
  370         struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
  371         struct autofs_info *ino = autofs4_dentry_ino(dentry);
  372         
  373         /* This allows root to remove symlinks */
  374         if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
  375                 return -EACCES;
  376 
  377         dput(ino->dentry);
  378 
  379         dentry->d_inode->i_size = 0;
  380         dentry->d_inode->i_nlink = 0;
  381 
  382         dir->i_mtime = CURRENT_TIME;
  383 
  384         d_drop(dentry);
  385         
  386         return 0;
  387 }
  388 
  389 static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
  390 {
  391         struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
  392         struct autofs_info *ino = autofs4_dentry_ino(dentry);
  393         
  394         if (!autofs4_oz_mode(sbi))
  395                 return -EACCES;
  396 
  397         spin_lock(&dcache_lock);
  398         if (!list_empty(&dentry->d_subdirs)) {
  399                 spin_unlock(&dcache_lock);
  400                 return -ENOTEMPTY;
  401         }
  402         list_del_init(&dentry->d_hash);
  403         spin_unlock(&dcache_lock);
  404 
  405         dput(ino->dentry);
  406 
  407         dentry->d_inode->i_size = 0;
  408         dentry->d_inode->i_nlink = 0;
  409 
  410         if (dir->i_nlink)
  411                 dir->i_nlink--;
  412 
  413         return 0;
  414 }
  415 
  416 
  417 
  418 static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
  419 {
  420         struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
  421         struct autofs_info *ino = autofs4_dentry_ino(dentry);
  422         struct inode *inode;
  423 
  424         if ( !autofs4_oz_mode(sbi) )
  425                 return -EACCES;
  426 
  427         DPRINTK(("autofs_dir_mkdir: dentry %p, creating %.*s\n",
  428                  dentry, dentry->d_name.len, dentry->d_name.name));
  429 
  430         ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);
  431         if (ino == NULL)
  432                 return -ENOSPC;
  433 
  434         inode = autofs4_get_inode(dir->i_sb, ino);
  435         d_instantiate(dentry, inode);
  436 
  437         if (dir == dir->i_sb->s_root->d_inode)
  438                 dentry->d_op = &autofs4_root_dentry_operations;
  439         else
  440                 dentry->d_op = &autofs4_dentry_operations;
  441 
  442         dentry->d_fsdata = ino;
  443         ino->dentry = dget(dentry);
  444         ino->inode = inode;
  445         dir->i_nlink++;
  446         dir->i_mtime = CURRENT_TIME;
  447 
  448         return 0;
  449 }
  450 
  451 /* Get/set timeout ioctl() operation */
  452 static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
  453                                          unsigned long *p)
  454 {
  455         int rv;
  456         unsigned long ntimeout;
  457 
  458         if ( (rv = get_user(ntimeout, p)) ||
  459              (rv = put_user(sbi->exp_timeout/HZ, p)) )
  460                 return rv;
  461 
  462         if ( ntimeout > ULONG_MAX/HZ )
  463                 sbi->exp_timeout = 0;
  464         else
  465                 sbi->exp_timeout = ntimeout * HZ;
  466 
  467         return 0;
  468 }
  469 
  470 /* Return protocol version */
  471 static inline int autofs4_get_protover(struct autofs_sb_info *sbi, int *p)
  472 {
  473         return put_user(sbi->version, p);
  474 }
  475 
  476 /* Identify autofs_dentries - this is so we can tell if there's
  477    an extra dentry refcount or not.  We only hold a refcount on the
  478    dentry if its non-negative (ie, d_inode != NULL)
  479 */
  480 int is_autofs4_dentry(struct dentry *dentry)
  481 {
  482         return dentry && dentry->d_inode &&
  483                 (dentry->d_op == &autofs4_root_dentry_operations ||
  484                  dentry->d_op == &autofs4_dentry_operations) &&
  485                 dentry->d_fsdata != NULL;
  486 }
  487 
  488 /*
  489  * ioctl()'s on the root directory is the chief method for the daemon to
  490  * generate kernel reactions
  491  */
  492 static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
  493                              unsigned int cmd, unsigned long arg)
  494 {
  495         struct autofs_sb_info *sbi = autofs4_sbi(inode->i_sb);
  496 
  497         DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",
  498                  cmd,arg,sbi,current->pgrp));
  499 
  500         if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
  501              _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
  502                 return -ENOTTY;
  503         
  504         if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
  505                 return -EPERM;
  506         
  507         switch(cmd) {
  508         case AUTOFS_IOC_READY:  /* Wait queue: go ahead and retry */
  509                 return autofs4_wait_release(sbi,(autofs_wqt_t)arg,0);
  510         case AUTOFS_IOC_FAIL:   /* Wait queue: fail with ENOENT */
  511                 return autofs4_wait_release(sbi,(autofs_wqt_t)arg,-ENOENT);
  512         case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */
  513                 autofs4_catatonic_mode(sbi);
  514                 return 0;
  515         case AUTOFS_IOC_PROTOVER: /* Get protocol version */
  516                 return autofs4_get_protover(sbi, (int *)arg);
  517         case AUTOFS_IOC_SETTIMEOUT:
  518                 return autofs4_get_set_timeout(sbi,(unsigned long *)arg);
  519 
  520         /* return a single thing to expire */
  521         case AUTOFS_IOC_EXPIRE:
  522                 return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi,
  523                                           (struct autofs_packet_expire *)arg);
  524         /* same as above, but can send multiple expires through pipe */
  525         case AUTOFS_IOC_EXPIRE_MULTI:
  526                 return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi,
  527                                             (int *)arg);
  528 
  529         default:
  530                 return -ENOSYS;
  531         }
  532 }

Cache object: f528d0b2ac9ceb129c58c7557e3185d4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.