Whamcloud - gitweb
land b_groups onto HEAD:
[fs/lustre-release.git] / lustre / mds / mds_lib.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2003 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #define DEBUG_SUBSYSTEM S_MDS
23
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/mm.h>
28 #include <linux/string.h>
29 #include <linux/stat.h>
30 #include <linux/errno.h>
31 #include <linux/version.h>
32 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
33 # include <linux/locks.h>   // for wait_on_buffer
34 #else
35 # include <linux/buffer_head.h>   // for wait_on_buffer
36 #endif
37 #include <linux/unistd.h>
38
39 #include <asm/system.h>
40 #include <asm/uaccess.h>
41
42 #include <linux/fs.h>
43 #include <linux/stat.h>
44 #include <asm/uaccess.h>
45 #include <linux/slab.h>
46 #include <asm/segment.h>
47
48 #include <linux/obd_support.h>
49 #include <linux/lustre_lib.h>
50 #include <linux/lustre_mds.h>
51
52 #include <linux/lustre_smfs.h>
53 #include <linux/lustre_snap.h>
54
55 #include "mds_internal.h"
56
57 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)
58 struct group_info *groups_alloc(int ngroups)
59 {
60         struct group_info *ginfo;
61
62         LASSERT(ngroups <= NGROUPS_SMALL);
63
64         OBD_ALLOC(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
65         if (!ginfo)
66                 return NULL;
67         ginfo->ngroups = ngroups;
68         ginfo->nblocks = 1;
69         ginfo->blocks[0] = ginfo->small_block;
70         atomic_set(&ginfo->usage, 1);
71
72         return ginfo;
73 }
74
75 void groups_free(struct group_info *ginfo)
76 {
77         LASSERT(ginfo->ngroups <= NGROUPS_SMALL);
78         LASSERT(ginfo->nblocks == 1);
79         LASSERT(ginfo->blocks[0] == ginfo->small_block);
80
81         OBD_FREE(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
82 }
83
84 /* for 2.4 the group number is small, so simply search the
85  * whole array.
86  */
87 int groups_search(struct group_info *ginfo, gid_t grp)
88 {
89         int i;
90
91         if (!ginfo)
92                 return 0;
93
94         for (i = 0; i < ginfo->ngroups; i++)
95                 if (GROUP_AT(ginfo, i) == grp)
96                         return 1;
97         return 0;
98 }
99
100 #else /* >= 2.6.4 */
101
102 void groups_sort(struct group_info *ginfo)
103 {
104         int base, max, stride;
105         int gidsetsize = ginfo->ngroups;
106
107         for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
108                 ; /* nothing */
109         stride /= 3;
110
111         while (stride) {
112                 max = gidsetsize - stride;
113                 for (base = 0; base < max; base++) {
114                         int left = base;
115                         int right = left + stride;
116                         gid_t tmp = GROUP_AT(ginfo, right);
117                                                                                                     
118                         while (left >= 0 && GROUP_AT(ginfo, left) > tmp) {
119                                 GROUP_AT(ginfo, right) =
120                                     GROUP_AT(ginfo, left);
121                                 right = left;
122                                 left -= stride;
123                         }
124                         GROUP_AT(ginfo, right) = tmp;
125                 }
126                 stride /= 3;
127         }
128 }
129
130 int groups_search(struct group_info *ginfo, gid_t grp)
131 {
132         int left, right;
133
134         if (!ginfo)
135                 return 0;
136
137         left = 0;
138         right = ginfo->ngroups;
139         while (left < right) {
140                 int mid = (left + right) / 2;
141                 int cmp = grp - GROUP_AT(ginfo, mid);
142                 if (cmp > 0)
143                         left = mid + 1;
144                 else if (cmp < 0)
145                         right = mid;
146                 else
147                         return 1;
148         }
149         return 0;
150 }
151
152 #endif
153
154 void groups_from_buffer(struct group_info *ginfo, __u32 *gids)
155 {
156         int i, ngroups = ginfo->ngroups;
157
158         for (i = 0; i < ginfo->nblocks; i++) {
159                 int count = min(NGROUPS_PER_BLOCK, ngroups);
160
161                 memcpy(ginfo->blocks[i], gids, count * sizeof(__u32));
162                 gids += NGROUPS_PER_BLOCK;
163                 ngroups -= count;
164         }
165 }
166
167 void mds_pack_dentry2fid(struct ll_fid *fid, struct dentry *dentry)
168 {
169         fid->id = dentry->d_inum;
170         fid->generation = dentry->d_generation;
171         fid->mds = dentry->d_mdsnum;
172 }
173
174 void mds_pack_dentry2body(struct mds_body *b, struct dentry *dentry)
175 {
176         b->valid |= OBD_MD_FLID | OBD_MD_FLGENER;
177         b->ino = dentry->d_inum;
178         b->generation = dentry->d_generation;
179         b->mds = dentry->d_mdsnum;
180 }
181
182 void mds_pack_inode2fid(struct obd_device *obd, struct ll_fid *fid,
183                                 struct inode *inode)
184 {
185         if (!obd || !fid || !inode) {
186                 printk("obd %p, fid %p, inode %p\n", obd, fid, inode);
187                 LBUG();
188         }
189         fid->id = inode->i_ino;
190         fid->generation = inode->i_generation;
191         fid->f_type = (S_IFMT & inode->i_mode);
192         fid->mds = obd->u.mds.mds_num;
193 }
194
195 /* Note that we can copy all of the fields, just some will not be "valid" */
196 void mds_pack_inode2body(struct obd_device *obd, struct mds_body *b,
197                                 struct inode *inode)
198 {
199         b->valid |= OBD_MD_FLID | OBD_MD_FLCTIME | OBD_MD_FLUID |
200                     OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLTYPE |
201                     OBD_MD_FLMODE | OBD_MD_FLNLINK | OBD_MD_FLGENER |
202                     OBD_MD_FLATIME | OBD_MD_FLMTIME; /* bug 2020 */
203
204         if (!S_ISREG(inode->i_mode))
205                 b->valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS | OBD_MD_FLATIME |
206                             OBD_MD_FLMTIME | OBD_MD_FLRDEV;
207
208         b->ino = inode->i_ino;
209         b->atime = LTIME_S(inode->i_atime);
210         b->mtime = LTIME_S(inode->i_mtime);
211         b->ctime = LTIME_S(inode->i_ctime);
212         b->mode = inode->i_mode;
213         b->size = inode->i_size;
214         b->blocks = inode->i_blocks;
215         b->uid = inode->i_uid;
216         b->gid = inode->i_gid;
217         b->flags = inode->i_flags;
218         b->rdev = inode->i_rdev;
219         /* Return the correct link count for orphan inodes */
220         if (mds_inode_is_orphan(inode)) {
221                 b->nlink = 0;
222         } else if (S_ISDIR(inode->i_mode)) {
223                 b->nlink = 1;
224         } else {
225                 b->nlink = inode->i_nlink;
226         }
227         b->generation = inode->i_generation;
228         b->mds = obd->u.mds.mds_num;
229 }
230
231 /* unpacking */
232 static int mds_setattr_unpack(struct ptlrpc_request *req, int offset,
233                               struct mds_update_record *r)
234 {
235         struct iattr *attr = &r->ur_iattr;
236         struct mds_rec_setattr *rec;
237         ENTRY;
238
239         rec = lustre_swab_reqbuf(req, offset, sizeof(*rec),
240                                  lustre_swab_mds_rec_setattr);
241         if (rec == NULL)
242                 RETURN (-EFAULT);
243
244         r->ur_fid1 = &rec->sa_fid;
245         attr->ia_valid = rec->sa_valid;
246         attr->ia_mode = rec->sa_mode;
247         attr->ia_uid = rec->sa_uid;
248         attr->ia_gid = rec->sa_gid;
249         attr->ia_size = rec->sa_size;
250         LTIME_S(attr->ia_atime) = rec->sa_atime;
251         LTIME_S(attr->ia_mtime) = rec->sa_mtime;
252         LTIME_S(attr->ia_ctime) = rec->sa_ctime;
253         attr->ia_attr_flags = rec->sa_attr_flags;
254
255         LASSERT_REQSWAB (req, offset + 1);
256         if (req->rq_reqmsg->bufcount > offset + 1) {
257                 r->ur_eadata = lustre_msg_buf (req->rq_reqmsg,
258                                                offset + 1, 0);
259                 if (r->ur_eadata == NULL)
260                         RETURN (-EFAULT);
261                 r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 1];
262         }
263
264         if (req->rq_reqmsg->bufcount > offset + 2) {
265                 r->ur_logcookies = lustre_msg_buf(req->rq_reqmsg, offset + 2,0);
266                 if (r->ur_eadata == NULL)
267                         RETURN (-EFAULT);
268
269                 r->ur_cookielen = req->rq_reqmsg->buflens[offset + 2];
270         }
271
272         RETURN(0);
273 }
274
275 static int mds_create_unpack(struct ptlrpc_request *req, int offset,
276                              struct mds_update_record *r)
277 {
278         struct mds_rec_create *rec;
279         ENTRY;
280
281         rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
282                                   lustre_swab_mds_rec_create);
283         if (rec == NULL)
284                 RETURN (-EFAULT);
285
286         r->ur_fid1 = &rec->cr_fid;
287         r->ur_fid2 = &rec->cr_replayfid;
288         r->ur_mode = rec->cr_mode;
289         r->ur_rdev = rec->cr_rdev;
290         r->ur_time = rec->cr_time;
291         r->ur_flags = rec->cr_flags;
292
293         LASSERT_REQSWAB (req, offset + 1);
294         r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
295         if (r->ur_name == NULL)
296                 RETURN (-EFAULT);
297         r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
298
299         LASSERT_REQSWAB (req, offset + 2);
300         if (req->rq_reqmsg->bufcount > offset + 2) {
301                 if (S_ISLNK(r->ur_mode)) {
302                         r->ur_tgt = lustre_msg_string(req->rq_reqmsg,
303                                                       offset + 2, 0);
304                         if (r->ur_tgt == NULL)
305                                 RETURN (-EFAULT);
306                         r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
307                 } else if (S_ISDIR(r->ur_mode)) {
308                         /* Stripe info for mkdir - just a 16bit integer */
309                         if (req->rq_reqmsg->buflens[offset + 2] != 2) {
310                                 CERROR("mkdir stripe info does not match "
311                                        "expected size %d vs 2\n",
312                                        req->rq_reqmsg->buflens[offset + 2]);
313                                 RETURN (-EINVAL);
314                         }
315                         r->ur_eadata = lustre_swab_buf (req->rq_reqmsg,
316                                                offset + 2, 2, __swab16s);
317                         r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 2];
318                 } else {
319                         /* Hm, no other users so far? */
320                         LBUG();
321                 }
322         }
323         RETURN(0);
324 }
325
326 static int mds_link_unpack(struct ptlrpc_request *req, int offset,
327                            struct mds_update_record *r)
328 {
329         struct mds_rec_link *rec;
330         ENTRY;
331
332         rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
333                                   lustre_swab_mds_rec_link);
334         if (rec == NULL)
335                 RETURN (-EFAULT);
336
337         r->ur_fid1 = &rec->lk_fid1;
338         r->ur_fid2 = &rec->lk_fid2;
339         r->ur_time = rec->lk_time;
340
341         LASSERT_REQSWAB (req, offset + 1);
342         r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
343         if (r->ur_name == NULL)
344                 RETURN (-EFAULT);
345         r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
346         RETURN(0);
347 }
348
349 static int mds_unlink_unpack(struct ptlrpc_request *req, int offset,
350                              struct mds_update_record *r)
351 {
352         struct mds_rec_unlink *rec;
353         ENTRY;
354
355         rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
356                                   lustre_swab_mds_rec_unlink);
357         if (rec == NULL)
358                 RETURN(-EFAULT);
359
360         r->ur_mode = rec->ul_mode;
361         r->ur_fid1 = &rec->ul_fid1;
362         r->ur_fid2 = &rec->ul_fid2;
363         r->ur_time = rec->ul_time;
364
365         LASSERT_REQSWAB (req, offset + 1);
366         r->ur_name = lustre_msg_string(req->rq_reqmsg, offset + 1, 0);
367         if (r->ur_name == NULL)
368                 RETURN(-EFAULT);
369         r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
370         RETURN(0);
371 }
372
373 static int mds_rename_unpack(struct ptlrpc_request *req, int offset,
374                              struct mds_update_record *r)
375 {
376         struct mds_rec_rename *rec;
377         ENTRY;
378
379         rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
380                                   lustre_swab_mds_rec_rename);
381         if (rec == NULL)
382                 RETURN(-EFAULT);
383
384         r->ur_fid1 = &rec->rn_fid1;
385         r->ur_fid2 = &rec->rn_fid2;
386         r->ur_time = rec->rn_time;
387
388         LASSERT_REQSWAB (req, offset + 1);
389         r->ur_name = lustre_msg_string(req->rq_reqmsg, offset + 1, 0);
390         if (r->ur_name == NULL)
391                 RETURN(-EFAULT);
392         r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
393
394         LASSERT_REQSWAB (req, offset + 2);
395         r->ur_tgt = lustre_msg_string(req->rq_reqmsg, offset + 2, 0);
396         if (r->ur_tgt == NULL)
397                 RETURN(-EFAULT);
398         r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
399         RETURN(0);
400 }
401
402 static int mds_open_unpack(struct ptlrpc_request *req, int offset,
403                            struct mds_update_record *r)
404 {
405         struct mds_rec_create *rec;
406         ENTRY;
407
408         rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
409                                   lustre_swab_mds_rec_create);
410         if (rec == NULL)
411                 RETURN (-EFAULT);
412
413         r->ur_fid1 = &rec->cr_fid;
414         r->ur_fid2 = &rec->cr_replayfid;
415         r->ur_mode = rec->cr_mode;
416         r->ur_rdev = rec->cr_rdev;
417         r->ur_time = rec->cr_time;
418         r->ur_flags = rec->cr_flags;
419
420         LASSERT_REQSWAB (req, offset + 1);
421         r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
422         if (r->ur_name == NULL)
423                 RETURN (-EFAULT);
424         r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
425
426         LASSERT_REQSWAB (req, offset + 2);
427         if (req->rq_reqmsg->bufcount > offset + 2) {
428                 r->ur_eadata = lustre_msg_buf(req->rq_reqmsg, offset + 2, 0);
429                 if (r->ur_eadata == NULL)
430                         RETURN (-EFAULT);
431                 r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 2];
432         }
433         RETURN(0);
434 }
435
436 typedef int (*update_unpacker)(struct ptlrpc_request *req, int offset,
437                                struct mds_update_record *r);
438
439 static update_unpacker mds_unpackers[REINT_MAX + 1] = {
440         [REINT_SETATTR] mds_setattr_unpack,
441         [REINT_CREATE] mds_create_unpack,
442         [REINT_LINK] mds_link_unpack,
443         [REINT_UNLINK] mds_unlink_unpack,
444         [REINT_RENAME] mds_rename_unpack,
445         [REINT_OPEN] mds_open_unpack,
446 };
447
448 int mds_update_unpack(struct ptlrpc_request *req, int offset,
449                       struct mds_update_record *rec)
450 {
451         __u32 *opcodep;
452         __u32  opcode;
453         int rc;
454         ENTRY;
455
456         /* NB don't lustre_swab_reqbuf() here.  We're just taking a peek
457          * and we want to leave it to the specific unpacker once we've
458          * identified the message type */
459         opcodep = lustre_msg_buf (req->rq_reqmsg, offset, sizeof (*opcodep));
460         if (opcodep == NULL)
461                 RETURN(-EFAULT);
462
463         opcode = *opcodep;
464         if (lustre_msg_swabbed (req->rq_reqmsg))
465                 __swab32s (&opcode);
466
467         if (opcode > REINT_MAX ||
468             mds_unpackers[opcode] == NULL) {
469                 CERROR ("Unexpected opcode %d\n", opcode);
470                 RETURN(-EFAULT);
471         }
472
473         rec->ur_opcode = opcode;
474         rc = mds_unpackers[opcode](req, offset, rec);
475         RETURN(rc);
476 }
477
478 static inline void drop_ucred_ginfo(struct lvfs_ucred *ucred)
479 {
480         if (ucred->luc_ginfo) {
481                 put_group_info(ucred->luc_ginfo);
482                 ucred->luc_ginfo = NULL;
483         }
484 }
485
486 /*
487  * root could set any group_info if we allowed setgroups, while
488  * normal user only could 'reduce' their group members -- which
489  * is somewhat expensive.
490  */
491 int mds_init_ucred(struct lvfs_ucred *ucred, struct mds_req_sec_desc *rsd)
492 {
493         struct group_info *gnew;
494
495         ENTRY;
496         LASSERT(ucred);
497         LASSERT(rsd);
498
499         ucred->luc_fsuid = rsd->rsd_fsuid;
500         ucred->luc_fsgid = rsd->rsd_fsgid;
501         ucred->luc_cap = rsd->rsd_cap;
502         ucred->luc_uid = rsd->rsd_uid;
503         ucred->luc_ghash = mds_get_group_entry(NULL, rsd->rsd_uid);
504         ucred->luc_ginfo = NULL;
505
506         if (ucred->luc_ghash && ucred->luc_ghash->ge_group_info) {
507                 ucred->luc_ginfo = ucred->luc_ghash->ge_group_info;
508                 get_group_info(ucred->luc_ginfo);
509         }
510
511         /* everything is done if we don't allow setgroups */
512         if (!mds_allow_setgroups())
513                 RETURN(0);
514
515         if (rsd->rsd_ngroups > LUSTRE_MAX_GROUPS) {
516                 CERROR("client provide too many groups: %d\n",
517                 rsd->rsd_ngroups);
518                 drop_ucred_ginfo(ucred);
519                 mds_put_group_entry(NULL, ucred->luc_ghash);
520                 RETURN(-EFAULT);
521         }
522
523         if (ucred->luc_uid == 0) {
524                 if (rsd->rsd_ngroups == 0) {
525                         drop_ucred_ginfo(ucred);
526                         RETURN(0);
527                 }
528
529                 gnew = groups_alloc(rsd->rsd_ngroups);
530                 if (!gnew) {
531                         CERROR("out of memory\n");
532                         drop_ucred_ginfo(ucred);
533                         mds_put_group_entry(NULL, ucred->luc_ghash);
534                         RETURN(-ENOMEM);
535                 }
536                 groups_from_buffer(gnew, rsd->rsd_groups);
537                 /* can't rely on client to sort them */
538                 groups_sort(gnew);
539
540                 drop_ucred_ginfo(ucred);
541                 ucred->luc_ginfo = gnew;
542         } else {
543                 struct group_info *ginfo;
544                 __u32 set = 0, cur = 0;
545
546                 /* if no group info in hash, we don't
547                  * bother createing new
548                  */
549                 if (!ucred->luc_ginfo)
550                         RETURN(0);
551
552                 /* Note: freeing a group_info count on 'nblocks' instead of
553                  * 'ngroups', thus we can safely alloc enough buffer and reduce
554                  * and ngroups number later.
555                  */
556                 gnew = groups_alloc(rsd->rsd_ngroups);
557                 if (!gnew) {
558                         CERROR("out of memory\n");
559                         drop_ucred_ginfo(ucred);
560                         mds_put_group_entry(NULL, ucred->luc_ghash);
561                         RETURN(-ENOMEM);
562                 }
563
564                 ginfo = ucred->luc_ginfo;
565                 while (cur < rsd->rsd_ngroups) {
566                         if (groups_search(ginfo, rsd->rsd_groups[cur]))
567                                 GROUP_AT(gnew, set++) = rsd->rsd_groups[cur];
568                         cur++;
569                 }
570                 gnew->ngroups = set;
571
572                 put_group_info(ucred->luc_ginfo);
573                 ucred->luc_ginfo = gnew;
574         }
575         RETURN(0);
576 }
577
578 void mds_exit_ucred(struct lvfs_ucred *ucred)
579 {
580         ENTRY;
581
582         if (ucred->luc_ginfo)
583                 put_group_info(ucred->luc_ginfo);
584         if (ucred->luc_ghash)
585                 mds_put_group_entry(NULL, ucred->luc_ghash);
586
587         EXIT;
588 }