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/lockd/svcsubs.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 /*
    2  * linux/fs/lockd/svcsubs.c
    3  *
    4  * Various support routines for the NLM server.
    5  *
    6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
    7  */
    8 
    9 #include <linux/config.h>
   10 #include <linux/types.h>
   11 #include <linux/string.h>
   12 #include <linux/sched.h>
   13 #include <linux/in.h>
   14 #include <linux/sunrpc/svc.h>
   15 #include <linux/sunrpc/clnt.h>
   16 #include <linux/nfsd/nfsfh.h>
   17 #include <linux/nfsd/export.h>
   18 #include <linux/lockd/lockd.h>
   19 #include <linux/lockd/share.h>
   20 #include <linux/lockd/sm_inter.h>
   21 
   22 #define NLMDBG_FACILITY         NLMDBG_SVCSUBS
   23 
   24 
   25 /*
   26  * Global file hash table
   27  */
   28 #define FILE_HASH_BITS          5
   29 #define FILE_NRHASH             (1<<FILE_HASH_BITS)
   30 static struct nlm_file *        nlm_files[FILE_NRHASH];
   31 static DECLARE_MUTEX(nlm_file_sema);
   32 
   33 static inline unsigned int file_hash(struct nfs_fh *f)
   34 {
   35         unsigned int tmp=0;
   36         int i;
   37         for (i=0; i<NFS2_FHSIZE;i++)
   38                 tmp += f->data[i];
   39         return tmp & (FILE_NRHASH - 1);
   40 }
   41 
   42 /*
   43  * Lookup file info. If it doesn't exist, create a file info struct
   44  * and open a (VFS) file for the given inode.
   45  *
   46  * FIXME:
   47  * Note that we open the file O_RDONLY even when creating write locks.
   48  * This is not quite right, but for now, we assume the client performs
   49  * the proper R/W checking.
   50  */
   51 u32
   52 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
   53                                         struct nfs_fh *f)
   54 {
   55         struct nlm_file *file;
   56         unsigned int    hash;
   57         u32             nfserr;
   58         u32             *fhp = (u32*)f->data;
   59 
   60         dprintk("lockd: nlm_file_lookup(%08x %08x %08x %08x %08x %08x)\n",
   61                 fhp[0], fhp[1], fhp[2], fhp[3], fhp[4], fhp[5]);
   62 
   63 
   64         hash = file_hash(f);
   65 
   66         /* Lock file table */
   67         down(&nlm_file_sema);
   68 
   69         for (file = nlm_files[hash]; file; file = file->f_next)
   70                 if (!memcmp(&file->f_handle, f, sizeof(*f)))
   71                         goto found;
   72 
   73         dprintk("lockd: creating file for (%08x %08x %08x %08x %08x %08x)\n",
   74                 fhp[0], fhp[1], fhp[2], fhp[3], fhp[4], fhp[5]);
   75 
   76         nfserr = nlm_lck_denied_nolocks;
   77         file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
   78         if (!file)
   79                 goto out_unlock;
   80 
   81         memset(file, 0, sizeof(*file));
   82         memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
   83         file->f_hash = hash;
   84         init_MUTEX(&file->f_sema);
   85 
   86         /* Open the file. Note that this must not sleep for too long, else
   87          * we would lock up lockd:-) So no NFS re-exports, folks.
   88          *
   89          * We have to make sure we have the right credential to open
   90          * the file.
   91          */
   92         if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
   93                 dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
   94                 goto out_free;
   95         }
   96 
   97         file->f_next = nlm_files[hash];
   98         nlm_files[hash] = file;
   99 
  100 found:
  101         dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
  102         *result = file;
  103         file->f_count++;
  104         nfserr = 0;
  105 
  106 out_unlock:
  107         up(&nlm_file_sema);
  108         return nfserr;
  109 
  110 out_free:
  111         kfree(file);
  112 #ifdef CONFIG_LOCKD_V4
  113         if (nfserr == 1)
  114                 nfserr = nlm4_stale_fh;
  115         else
  116 #endif
  117         nfserr = nlm_lck_denied;
  118         goto out_unlock;
  119 }
  120 
  121 /*
  122  * Delete a file after having released all locks, blocks and shares
  123  */
  124 static inline void
  125 nlm_delete_file(struct nlm_file *file)
  126 {
  127         struct inode *inode = file->f_file.f_dentry->d_inode;
  128         struct nlm_file **fp, *f;
  129 
  130         dprintk("lockd: closing file %s/%ld\n",
  131                 kdevname(inode->i_dev), inode->i_ino);
  132         fp = nlm_files + file->f_hash;
  133         while ((f = *fp) != NULL) {
  134                 if (f == file) {
  135                         *fp = file->f_next;
  136                         nlmsvc_ops->fclose(&file->f_file);
  137                         kfree(file);
  138                         return;
  139                 }
  140                 fp = &f->f_next;
  141         }
  142 
  143         printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
  144 }
  145 
  146 /*
  147  * Loop over all locks on the given file and perform the specified
  148  * action.
  149  */
  150 static int
  151 nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
  152 {
  153         struct inode     *inode = nlmsvc_file_inode(file);
  154         struct file_lock *fl;
  155         struct nlm_host  *lockhost;
  156 
  157 again:
  158         file->f_locks = 0;
  159         for (fl = inode->i_flock; fl; fl = fl->fl_next) {
  160                 if (!(fl->fl_flags & FL_LOCKD))
  161                         continue;
  162 
  163                 /* update current lock count */
  164                 file->f_locks++;
  165                 lockhost = (struct nlm_host *) fl->fl_owner;
  166                 if (action == NLM_ACT_MARK)
  167                         lockhost->h_inuse = 1;
  168                 else if (action == NLM_ACT_CHECK)
  169                         return 1;
  170                 else if (action == NLM_ACT_UNLOCK) {
  171                         struct file_lock lock = *fl;
  172 
  173                         if (host && lockhost != host)
  174                                 continue;
  175 
  176                         lock.fl_type  = F_UNLCK;
  177                         lock.fl_start = 0;
  178                         lock.fl_end   = OFFSET_MAX;
  179                         if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
  180                                 printk("lockd: unlock failure in %s:%d\n",
  181                                                 __FILE__, __LINE__);
  182                                 return 1;
  183                         }
  184                         goto again;
  185                 }
  186         }
  187 
  188         return 0;
  189 }
  190 
  191 /*
  192  * Operate on a single file
  193  */
  194 static inline int
  195 nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
  196 {
  197         if (action == NLM_ACT_CHECK) {
  198                 /* Fast path for mark and sweep garbage collection */
  199                 if (file->f_count || file->f_blocks || file->f_shares)
  200                         return 1;
  201         } else {
  202                 if (nlmsvc_traverse_blocks(host, file, action)
  203                  || nlmsvc_traverse_shares(host, file, action))
  204                         return 1;
  205         }
  206         return nlm_traverse_locks(host, file, action);
  207 }
  208 
  209 /*
  210  * Loop over all files in the file table.
  211  */
  212 static int
  213 nlm_traverse_files(struct nlm_host *host, int action)
  214 {
  215         struct nlm_file *file, **fp;
  216         int             i;
  217 
  218         down(&nlm_file_sema);
  219         for (i = 0; i < FILE_NRHASH; i++) {
  220                 fp = nlm_files + i;
  221                 while ((file = *fp) != NULL) {
  222                         /* Traverse locks, blocks and shares of this file
  223                          * and update file->f_locks count */
  224                         if (nlm_inspect_file(host, file, action)) {
  225                                 up(&nlm_file_sema);
  226                                 return 1;
  227                         }
  228 
  229                         /* No more references to this file. Let go of it. */
  230                         if (!file->f_blocks && !file->f_locks
  231                          && !file->f_shares && !file->f_count) {
  232                                 *fp = file->f_next;
  233                                 nlmsvc_ops->fclose(&file->f_file);
  234                                 kfree(file);
  235                         } else {
  236                                 fp = &file->f_next;
  237                         }
  238                 }
  239         }
  240         up(&nlm_file_sema);
  241         return 0;
  242 }
  243 
  244 /*
  245  * Release file. If there are no more remote locks on this file,
  246  * close it and free the handle.
  247  *
  248  * Note that we can't do proper reference counting without major
  249  * contortions because the code in fs/locks.c creates, deletes and
  250  * splits locks without notification. Our only way is to walk the
  251  * entire lock list each time we remove a lock.
  252  */
  253 void
  254 nlm_release_file(struct nlm_file *file)
  255 {
  256         dprintk("lockd: nlm_release_file(%p, ct = %d)\n",
  257                                 file, file->f_count);
  258 
  259         /* Lock file table */
  260         down(&nlm_file_sema);
  261 
  262         /* If there are no more locks etc, delete the file */
  263         if(--file->f_count == 0) {
  264                 if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
  265                         nlm_delete_file(file);
  266         }
  267 
  268         up(&nlm_file_sema);
  269 }
  270 
  271 /*
  272  * Mark all hosts that still hold resources
  273  */
  274 void
  275 nlmsvc_mark_resources(void)
  276 {
  277         dprintk("lockd: nlmsvc_mark_resources\n");
  278 
  279         nlm_traverse_files(NULL, NLM_ACT_MARK);
  280 }
  281 
  282 /*
  283  * Release all resources held by the given client
  284  */
  285 void
  286 nlmsvc_free_host_resources(struct nlm_host *host)
  287 {
  288         dprintk("lockd: nlmsvc_free_host_resources\n");
  289 
  290         if (nlm_traverse_files(host, NLM_ACT_UNLOCK))
  291                 printk(KERN_WARNING
  292                         "lockd: couldn't remove all locks held by %s",
  293                         host->h_name);
  294 }
  295 
  296 /*
  297  * Delete a client when the nfsd entry is removed.
  298  */
  299 void
  300 nlmsvc_invalidate_client(struct svc_client *clnt)
  301 {
  302         struct nlm_host *host;
  303 
  304         if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
  305                 dprintk("lockd: invalidating client for %s\n", host->h_name);
  306                 nlmsvc_free_host_resources(host);
  307                 host->h_expires = 0;
  308                 host->h_killed = 1;
  309                 nlm_release_host(host);
  310         }
  311 }

Cache object: dfedeef141d3607413dba2dff22fe430


[ 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.