NFSv4.1: pnfs: full mount/umount infrastructure
[firefly-linux-kernel-4.4.55.git] / fs / nfs / pnfs.c
1 /*
2  *  pNFS functions to call and manage layout drivers.
3  *
4  *  Copyright (c) 2002 [year of first publication]
5  *  The Regents of the University of Michigan
6  *  All Rights Reserved
7  *
8  *  Dean Hildebrand <dhildebz@umich.edu>
9  *
10  *  Permission is granted to use, copy, create derivative works, and
11  *  redistribute this software and such derivative works for any purpose,
12  *  so long as the name of the University of Michigan is not used in
13  *  any advertising or publicity pertaining to the use or distribution
14  *  of this software without specific, written prior authorization. If
15  *  the above copyright notice or any other identification of the
16  *  University of Michigan is included in any copy of any portion of
17  *  this software, then the disclaimer below must also be included.
18  *
19  *  This software is provided as is, without representation or warranty
20  *  of any kind either express or implied, including without limitation
21  *  the implied warranties of merchantability, fitness for a particular
22  *  purpose, or noninfringement.  The Regents of the University of
23  *  Michigan shall not be liable for any damages, including special,
24  *  indirect, incidental, or consequential damages, with respect to any
25  *  claim arising out of or in connection with the use of the software,
26  *  even if it has been or is hereafter advised of the possibility of
27  *  such damages.
28  */
29
30 #include <linux/nfs_fs.h>
31 #include "pnfs.h"
32
33 #define NFSDBG_FACILITY         NFSDBG_PNFS
34
35 /* Locking:
36  *
37  * pnfs_spinlock:
38  *      protects pnfs_modules_tbl.
39  */
40 static DEFINE_SPINLOCK(pnfs_spinlock);
41
42 /*
43  * pnfs_modules_tbl holds all pnfs modules
44  */
45 static LIST_HEAD(pnfs_modules_tbl);
46
47 /* Return the registered pnfs layout driver module matching given id */
48 static struct pnfs_layoutdriver_type *
49 find_pnfs_driver_locked(u32 id)
50 {
51         struct pnfs_layoutdriver_type *local;
52
53         list_for_each_entry(local, &pnfs_modules_tbl, pnfs_tblid)
54                 if (local->id == id)
55                         goto out;
56         local = NULL;
57 out:
58         dprintk("%s: Searching for id %u, found %p\n", __func__, id, local);
59         return local;
60 }
61
62 static struct pnfs_layoutdriver_type *
63 find_pnfs_driver(u32 id)
64 {
65         struct pnfs_layoutdriver_type *local;
66
67         spin_lock(&pnfs_spinlock);
68         local = find_pnfs_driver_locked(id);
69         spin_unlock(&pnfs_spinlock);
70         return local;
71 }
72
73 void
74 unset_pnfs_layoutdriver(struct nfs_server *nfss)
75 {
76         if (nfss->pnfs_curr_ld) {
77                 nfss->pnfs_curr_ld->uninitialize_mountpoint(nfss);
78                 module_put(nfss->pnfs_curr_ld->owner);
79         }
80         nfss->pnfs_curr_ld = NULL;
81 }
82
83 /*
84  * Try to set the server's pnfs module to the pnfs layout type specified by id.
85  * Currently only one pNFS layout driver per filesystem is supported.
86  *
87  * @id layout type. Zero (illegal layout type) indicates pNFS not in use.
88  */
89 void
90 set_pnfs_layoutdriver(struct nfs_server *server, u32 id)
91 {
92         struct pnfs_layoutdriver_type *ld_type = NULL;
93
94         if (id == 0)
95                 goto out_no_driver;
96         if (!(server->nfs_client->cl_exchange_flags &
97                  (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
98                 printk(KERN_ERR "%s: id %u cl_exchange_flags 0x%x\n", __func__,
99                        id, server->nfs_client->cl_exchange_flags);
100                 goto out_no_driver;
101         }
102         ld_type = find_pnfs_driver(id);
103         if (!ld_type) {
104                 request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
105                 ld_type = find_pnfs_driver(id);
106                 if (!ld_type) {
107                         dprintk("%s: No pNFS module found for %u.\n",
108                                 __func__, id);
109                         goto out_no_driver;
110                 }
111         }
112         if (!try_module_get(ld_type->owner)) {
113                 dprintk("%s: Could not grab reference on module\n", __func__);
114                 goto out_no_driver;
115         }
116         server->pnfs_curr_ld = ld_type;
117         if (ld_type->initialize_mountpoint(server)) {
118                 printk(KERN_ERR
119                        "%s: Error initializing mount point for layout driver %u.\n",
120                        __func__, id);
121                 module_put(ld_type->owner);
122                 goto out_no_driver;
123         }
124         dprintk("%s: pNFS module for %u set\n", __func__, id);
125         return;
126
127 out_no_driver:
128         dprintk("%s: Using NFSv4 I/O\n", __func__);
129         server->pnfs_curr_ld = NULL;
130 }
131
132 int
133 pnfs_register_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
134 {
135         int status = -EINVAL;
136         struct pnfs_layoutdriver_type *tmp;
137
138         if (ld_type->id == 0) {
139                 printk(KERN_ERR "%s id 0 is reserved\n", __func__);
140                 return status;
141         }
142
143         spin_lock(&pnfs_spinlock);
144         tmp = find_pnfs_driver_locked(ld_type->id);
145         if (!tmp) {
146                 list_add(&ld_type->pnfs_tblid, &pnfs_modules_tbl);
147                 status = 0;
148                 dprintk("%s Registering id:%u name:%s\n", __func__, ld_type->id,
149                         ld_type->name);
150         } else {
151                 printk(KERN_ERR "%s Module with id %d already loaded!\n",
152                         __func__, ld_type->id);
153         }
154         spin_unlock(&pnfs_spinlock);
155
156         return status;
157 }
158 EXPORT_SYMBOL_GPL(pnfs_register_layoutdriver);
159
160 void
161 pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *ld_type)
162 {
163         dprintk("%s Deregistering id:%u\n", __func__, ld_type->id);
164         spin_lock(&pnfs_spinlock);
165         list_del(&ld_type->pnfs_tblid);
166         spin_unlock(&pnfs_spinlock);
167 }
168 EXPORT_SYMBOL_GPL(pnfs_unregister_layoutdriver);