OSDN Git Service

NFS: create and destroy inode's layout cache
[sagit-ice-cold/kernel_xiaomi_msm8998.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);
169
170 static void
171 get_layout_hdr_locked(struct pnfs_layout_hdr *lo)
172 {
173         assert_spin_locked(&lo->inode->i_lock);
174         lo->refcount++;
175 }
176
177 static void
178 put_layout_hdr_locked(struct pnfs_layout_hdr *lo)
179 {
180         assert_spin_locked(&lo->inode->i_lock);
181         BUG_ON(lo->refcount == 0);
182
183         lo->refcount--;
184         if (!lo->refcount) {
185                 dprintk("%s: freeing layout cache %p\n", __func__, lo);
186                 NFS_I(lo->inode)->layout = NULL;
187                 kfree(lo);
188         }
189 }
190
191 void
192 pnfs_destroy_layout(struct nfs_inode *nfsi)
193 {
194         struct pnfs_layout_hdr *lo;
195
196         spin_lock(&nfsi->vfs_inode.i_lock);
197         lo = nfsi->layout;
198         if (lo) {
199                 /* Matched by refcount set to 1 in alloc_init_layout_hdr */
200                 put_layout_hdr_locked(lo);
201         }
202         spin_unlock(&nfsi->vfs_inode.i_lock);
203 }
204
205 /* STUB - pretend LAYOUTGET to server failed */
206 static struct pnfs_layout_segment *
207 send_layoutget(struct pnfs_layout_hdr *lo,
208            struct nfs_open_context *ctx,
209            u32 iomode)
210 {
211         struct inode *ino = lo->inode;
212
213         set_bit(lo_fail_bit(iomode), &lo->state);
214         spin_lock(&ino->i_lock);
215         put_layout_hdr_locked(lo);
216         spin_unlock(&ino->i_lock);
217         return NULL;
218 }
219
220 static struct pnfs_layout_hdr *
221 alloc_init_layout_hdr(struct inode *ino)
222 {
223         struct pnfs_layout_hdr *lo;
224
225         lo = kzalloc(sizeof(struct pnfs_layout_hdr), GFP_KERNEL);
226         if (!lo)
227                 return NULL;
228         lo->refcount = 1;
229         lo->inode = ino;
230         return lo;
231 }
232
233 static struct pnfs_layout_hdr *
234 pnfs_find_alloc_layout(struct inode *ino)
235 {
236         struct nfs_inode *nfsi = NFS_I(ino);
237         struct pnfs_layout_hdr *new = NULL;
238
239         dprintk("%s Begin ino=%p layout=%p\n", __func__, ino, nfsi->layout);
240
241         assert_spin_locked(&ino->i_lock);
242         if (nfsi->layout)
243                 return nfsi->layout;
244
245         spin_unlock(&ino->i_lock);
246         new = alloc_init_layout_hdr(ino);
247         spin_lock(&ino->i_lock);
248
249         if (likely(nfsi->layout == NULL))       /* Won the race? */
250                 nfsi->layout = new;
251         else
252                 kfree(new);
253         return nfsi->layout;
254 }
255
256 /* STUB - LAYOUTGET never succeeds, so cache is empty */
257 static struct pnfs_layout_segment *
258 pnfs_has_layout(struct pnfs_layout_hdr *lo, u32 iomode)
259 {
260         return NULL;
261 }
262
263 /*
264  * Layout segment is retreived from the server if not cached.
265  * The appropriate layout segment is referenced and returned to the caller.
266  */
267 struct pnfs_layout_segment *
268 pnfs_update_layout(struct inode *ino,
269                    struct nfs_open_context *ctx,
270                    enum pnfs_iomode iomode)
271 {
272         struct nfs_inode *nfsi = NFS_I(ino);
273         struct pnfs_layout_hdr *lo;
274         struct pnfs_layout_segment *lseg = NULL;
275
276         if (!pnfs_enabled_sb(NFS_SERVER(ino)))
277                 return NULL;
278         spin_lock(&ino->i_lock);
279         lo = pnfs_find_alloc_layout(ino);
280         if (lo == NULL) {
281                 dprintk("%s ERROR: can't get pnfs_layout_hdr\n", __func__);
282                 goto out_unlock;
283         }
284
285         /* Check to see if the layout for the given range already exists */
286         lseg = pnfs_has_layout(lo, iomode);
287         if (lseg) {
288                 dprintk("%s: Using cached lseg %p for iomode %d)\n",
289                         __func__, lseg, iomode);
290                 goto out_unlock;
291         }
292
293         /* if LAYOUTGET already failed once we don't try again */
294         if (test_bit(lo_fail_bit(iomode), &nfsi->layout->state))
295                 goto out_unlock;
296
297         get_layout_hdr_locked(lo);
298         spin_unlock(&ino->i_lock);
299
300         lseg = send_layoutget(lo, ctx, iomode);
301 out:
302         dprintk("%s end, state 0x%lx lseg %p\n", __func__,
303                 nfsi->layout->state, lseg);
304         return lseg;
305 out_unlock:
306         spin_unlock(&ino->i_lock);
307         goto out;
308 }