Whamcloud - gitweb
LU-4788 lfsck: replace cfs_list_t with list_head
[fs/lustre-release.git] / lustre / obdclass / acl.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/acl.c
37  *
38  * Lustre Access Control List.
39  *
40  * Author: Fan Yong <fanyong@clusterfs.com>
41  */
42
43 #define DEBUG_SUBSYSTEM S_SEC
44 #include <lu_object.h>
45 #include <lustre_acl.h>
46 #include <lustre_eacl.h>
47 #include <obd_support.h>
48 #ifdef HAVE_SERVER_SUPPORT
49 # include <lustre_idmap.h>
50 # include <md_object.h>
51 #endif /* HAVE_SERVER_SUPPORT */
52
53 #ifdef CONFIG_FS_POSIX_ACL
54
55 #define CFS_ACL_XATTR_VERSION POSIX_ACL_XATTR_VERSION
56
57 enum {
58         ES_UNK  = 0,    /* unknown stat */
59         ES_UNC  = 1,    /* ACL entry is not changed */
60         ES_MOD  = 2,    /* ACL entry is modified */
61         ES_ADD  = 3,    /* ACL entry is added */
62         ES_DEL  = 4     /* ACL entry is deleted */
63 };
64
65 static inline void lustre_ext_acl_le_to_cpu(ext_acl_xattr_entry *d,
66                                             ext_acl_xattr_entry *s)
67 {
68         d->e_tag        = le16_to_cpu(s->e_tag);
69         d->e_perm       = le16_to_cpu(s->e_perm);
70         d->e_id         = le32_to_cpu(s->e_id);
71         d->e_stat       = le32_to_cpu(s->e_stat);
72 }
73
74 static inline void lustre_ext_acl_cpu_to_le(ext_acl_xattr_entry *d,
75                                             ext_acl_xattr_entry *s)
76 {
77         d->e_tag        = cpu_to_le16(s->e_tag);
78         d->e_perm       = cpu_to_le16(s->e_perm);
79         d->e_id         = cpu_to_le32(s->e_id);
80         d->e_stat       = cpu_to_le32(s->e_stat);
81 }
82
83 static inline void lustre_posix_acl_le_to_cpu(posix_acl_xattr_entry *d,
84                                               posix_acl_xattr_entry *s)
85 {
86         d->e_tag        = le16_to_cpu(s->e_tag);
87         d->e_perm       = le16_to_cpu(s->e_perm);
88         d->e_id         = le32_to_cpu(s->e_id);
89 }
90
91 static inline void lustre_posix_acl_cpu_to_le(posix_acl_xattr_entry *d,
92                                               posix_acl_xattr_entry *s)
93 {
94         d->e_tag        = cpu_to_le16(s->e_tag);
95         d->e_perm       = cpu_to_le16(s->e_perm);
96         d->e_id         = cpu_to_le32(s->e_id);
97 }
98
99 #ifdef HAVE_SERVER_SUPPORT
100 /*
101  * Check permission based on POSIX ACL.
102  */
103 int lustre_posix_acl_permission(struct lu_ucred *mu, const struct lu_attr *la,
104                                 int want, posix_acl_xattr_entry *entry,
105                                 int count)
106 {
107         posix_acl_xattr_entry *pa, *pe, *mask_obj;
108         posix_acl_xattr_entry ae, me;
109         int found = 0;
110
111         if (count <= 0)
112                 return -EACCES;
113
114         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
115                 lustre_posix_acl_le_to_cpu(&ae, pa);
116                 switch (ae.e_tag) {
117                 case ACL_USER_OBJ:
118                         /* (May have been checked already) */
119                         if (la->la_uid == mu->uc_fsuid)
120                                 goto check_perm;
121                         break;
122                 case ACL_USER:
123                         if (ae.e_id == mu->uc_fsuid)
124                                 goto mask;
125                         break;
126                 case ACL_GROUP_OBJ:
127                         if (lustre_in_group_p(mu, la->la_gid)) {
128                                 found = 1;
129                                 if ((ae.e_perm & want) == want)
130                                         goto mask;
131                         }
132                         break;
133                 case ACL_GROUP:
134                         if (lustre_in_group_p(mu, ae.e_id)) {
135                                 found = 1;
136                                 if ((ae.e_perm & want) == want)
137                                         goto mask;
138                         }
139                         break;
140                 case ACL_MASK:
141                         break;
142                 case ACL_OTHER:
143                         if (found)
144                                 return -EACCES;
145                         else
146                                 goto check_perm;
147                 default:
148                         return -EIO;
149                 }
150         }
151         return -EIO;
152
153 mask:
154         for (mask_obj = pa + 1; mask_obj <= pe; mask_obj++) {
155                 lustre_posix_acl_le_to_cpu(&me, mask_obj);
156                 if (me.e_tag == ACL_MASK) {
157                         if ((ae.e_perm & me.e_perm & want) == want)
158                                 return 0;
159
160                         return -EACCES;
161                 }
162         }
163
164 check_perm:
165         if ((ae.e_perm & want) == want)
166                 return 0;
167
168         return -EACCES;
169 }
170 EXPORT_SYMBOL(lustre_posix_acl_permission);
171
172 /*
173  * Modify the ACL for the chmod.
174  */
175 int lustre_posix_acl_chmod_masq(posix_acl_xattr_entry *entry, __u32 mode,
176                                 int count)
177 {
178         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
179
180         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
181                 switch (le16_to_cpu(pa->e_tag)) {
182                 case ACL_USER_OBJ:
183                         pa->e_perm = cpu_to_le16((mode & S_IRWXU) >> 6);
184                         break;
185                 case ACL_USER:
186                 case ACL_GROUP:
187                         break;
188                 case ACL_GROUP_OBJ:
189                         group_obj = pa;
190                         break;
191                 case ACL_MASK:
192                         mask_obj = pa;
193                         break;
194                 case ACL_OTHER:
195                         pa->e_perm = cpu_to_le16(mode & S_IRWXO);
196                         break;
197                 default:
198                         return -EIO;
199                 }
200         }
201
202         if (mask_obj) {
203                 mask_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
204         } else {
205                 if (!group_obj)
206                         return -EIO;
207                 group_obj->e_perm = cpu_to_le16((mode & S_IRWXG) >> 3);
208         }
209
210         return 0;
211 }
212 EXPORT_SYMBOL(lustre_posix_acl_chmod_masq);
213
214 /*
215  * Returns 0 if the acl can be exactly represented in the traditional
216  * file mode permission bits, or else 1. Returns -E... on error.
217  */
218         int
219 lustre_posix_acl_equiv_mode(posix_acl_xattr_entry *entry, mode_t *mode_p,
220                 int count)
221 {
222         posix_acl_xattr_entry *pa, *pe;
223         mode_t                 mode = 0;
224         int                    not_equiv = 0;
225
226         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
227                 __u16 perm = le16_to_cpu(pa->e_perm);
228                 switch (le16_to_cpu(pa->e_tag)) {
229                         case ACL_USER_OBJ:
230                                 mode |= (perm & S_IRWXO) << 6;
231                                 break;
232                         case ACL_GROUP_OBJ:
233                                 mode |= (perm & S_IRWXO) << 3;
234                                 break;
235                         case ACL_OTHER:
236                                 mode |= perm & S_IRWXO;
237                                 break;
238                         case ACL_MASK:
239                                 mode = (mode & ~S_IRWXG) |
240                                         ((perm & S_IRWXO) << 3);
241                                 not_equiv = 1;
242                                 break;
243                         case ACL_USER:
244                         case ACL_GROUP:
245                                 not_equiv = 1;
246                                 break;
247                         default:
248                                 return -EINVAL;
249                 }
250         }
251         if (mode_p)
252                 *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
253         return not_equiv;
254 }
255 EXPORT_SYMBOL(lustre_posix_acl_equiv_mode);
256
257 /*
258  * Modify acl when creating a new object.
259  */
260 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
261                                  int count)
262 {
263         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
264         posix_acl_xattr_entry ae;
265         __u32 mode = *pmode;
266         int not_equiv = 0;
267
268         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
269                 lustre_posix_acl_le_to_cpu(&ae, pa);
270                 switch (ae.e_tag) {
271                 case ACL_USER_OBJ:
272                         ae.e_perm &= (mode >> 6) | ~S_IRWXO;
273                         pa->e_perm = cpu_to_le16(ae.e_perm);
274                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
275                         break;
276                 case ACL_USER:
277                 case ACL_GROUP:
278                         not_equiv = 1;
279                         break;
280                 case ACL_GROUP_OBJ:
281                         group_obj = pa;
282                         break;
283                 case ACL_OTHER:
284                         ae.e_perm &= mode | ~S_IRWXO;
285                         pa->e_perm = cpu_to_le16(ae.e_perm);
286                         mode &= ae.e_perm | ~S_IRWXO;
287                         break;
288                 case ACL_MASK:
289                         mask_obj = pa;
290                         not_equiv = 1;
291                         break;
292                 default:
293                         return -EIO;
294                 }
295         }
296
297         if (mask_obj) {
298                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
299                             ((mode >> 3) | ~S_IRWXO);
300                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
301                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
302         } else {
303                 if (!group_obj)
304                         return -EIO;
305                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
306                             ((mode >> 3) | ~S_IRWXO);
307                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
308                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
309         }
310
311         *pmode = (*pmode & ~S_IRWXUGO) | mode;
312         return not_equiv;
313 }
314 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
315
316 /*
317  * Convert server-side uid/gid in the posix ACL items to the client-side ones.
318  * convert rule:
319  * @CFS_IC_NOTHING
320  *  nothing to be converted.
321  * @CFS_IC_ALL
322  *  mapped ids are converted to client-side ones,
323  *  unmapped ones are converted to "nobody".
324  * @CFS_IC_MAPPED
325  *  only mapped ids are converted to "nobody".
326  * @CFS_IC_UNMAPPED
327  *  only unmapped ids are converted to "nobody".
328  */
329 int lustre_posix_acl_xattr_id2client(struct lu_ucred *mu,
330                                      struct lustre_idmap_table *t,
331                                      posix_acl_xattr_header *header,
332                                      int size, int flags)
333 {
334         int count, i;
335         __u32 id;
336         ENTRY;
337
338         if (unlikely(size < 0))
339                 RETURN(-EINVAL);
340         else if (!size)
341                 RETURN(0);
342
343         if (unlikely(flags == CFS_IC_NOTHING))
344                 RETURN(0);
345
346         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
347         for (i = 0; i < count; i++) {
348                 id = le32_to_cpu(header->a_entries[i].e_id);
349                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
350                 case ACL_USER_OBJ:
351                 case ACL_GROUP_OBJ:
352                 case ACL_MASK:
353                 case ACL_OTHER:
354                         if (id != ACL_UNDEFINED_ID)
355                                 RETURN(-EIO);
356                         break;
357                 case ACL_USER:
358                         id = lustre_idmap_lookup_uid(mu, t, 1, id);
359                         if (flags == CFS_IC_ALL) {
360                                 if (id == CFS_IDMAP_NOTFOUND)
361                                         id = NOBODY_UID;
362                                 header->a_entries[i].e_id = cpu_to_le32(id);
363                         } else if (flags == CFS_IC_MAPPED) {
364                                 if (id != CFS_IDMAP_NOTFOUND)
365                                         header->a_entries[i].e_id =
366                                                 cpu_to_le32(NOBODY_UID);
367                         } else if (flags == CFS_IC_UNMAPPED) {
368                                 if (id == CFS_IDMAP_NOTFOUND)
369                                         header->a_entries[i].e_id =
370                                                 cpu_to_le32(NOBODY_UID);
371                         }
372                         break;
373                 case ACL_GROUP:
374                         id = lustre_idmap_lookup_gid(mu, t, 1, id);
375                         if (flags == CFS_IC_ALL) {
376                                 if (id == CFS_IDMAP_NOTFOUND)
377                                         id = NOBODY_GID;
378                                 header->a_entries[i].e_id = cpu_to_le32(id);
379                         } else if (flags == CFS_IC_MAPPED) {
380                                 if (id != CFS_IDMAP_NOTFOUND)
381                                         header->a_entries[i].e_id =
382                                                 cpu_to_le32(NOBODY_GID);
383                         } else if (flags == CFS_IC_UNMAPPED) {
384                                 if (id == CFS_IDMAP_NOTFOUND)
385                                         header->a_entries[i].e_id =
386                                                 cpu_to_le32(NOBODY_GID);
387                         }
388                         break;
389                 default:
390                         RETURN(-EIO);
391                 }
392         }
393
394         RETURN(0);
395 }
396 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
397
398 /*
399  * Converts client-side uid/gid in the extended ACL items to server-side ones.
400  * convert rule:
401  *  mapped ids are converted to server-side ones,
402  *  unmapped ones cause "EPERM" error.
403  */
404 int lustre_ext_acl_xattr_id2server(struct lu_ucred *mu,
405                                    struct lustre_idmap_table *t,
406                                    ext_acl_xattr_header *header)
407 {
408         int i, count = le32_to_cpu(header->a_count);
409         __u32 id;
410         ENTRY;
411
412         for (i = 0; i < count; i++) {
413                 id = le32_to_cpu(header->a_entries[i].e_id);
414                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
415                 case ACL_USER_OBJ:
416                 case ACL_GROUP_OBJ:
417                 case ACL_MASK:
418                 case ACL_OTHER:
419                         if (id != ACL_UNDEFINED_ID)
420                                 RETURN(-EIO);
421                         break;
422                 case ACL_USER:
423                         id = lustre_idmap_lookup_uid(mu, t, 0, id);
424                         if (id == CFS_IDMAP_NOTFOUND)
425                                 RETURN(-EPERM);
426                         else
427                                 header->a_entries[i].e_id = cpu_to_le32(id);
428                         break;
429                 case ACL_GROUP:
430                         id = lustre_idmap_lookup_gid(mu, t, 0, id);
431                         if (id == CFS_IDMAP_NOTFOUND)
432                                 RETURN(-EPERM);
433                         else
434                                 header->a_entries[i].e_id = cpu_to_le32(id);
435                         break;
436                 default:
437                         RETURN(-EIO);
438                 }
439         }
440
441         RETURN(0);
442 }
443 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
444 #endif /* HAVE_SERVER_SUPPORT */
445
446 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
447 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
448                                                int old_count, int new_count)
449 {
450         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
451         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
452         posix_acl_xattr_header *new;
453
454         if (unlikely(old_count <= new_count))
455                 return old_size;
456
457         OBD_ALLOC(new, new_size);
458         if (unlikely(new == NULL))
459                 return -ENOMEM;
460
461         memcpy(new, *header, new_size);
462         OBD_FREE(*header, old_size);
463         *header = new;
464         return new_size;
465 }
466
467 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
468 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
469                                              int old_count)
470 {
471         int ext_count = le32_to_cpu((*header)->a_count);
472         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
473         int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
474         ext_acl_xattr_header *new;
475
476         if (unlikely(old_count <= ext_count))
477                 return 0;
478
479         OBD_ALLOC(new, ext_size);
480         if (unlikely(new == NULL))
481                 return -ENOMEM;
482
483         memcpy(new, *header, ext_size);
484         OBD_FREE(*header, old_size);
485         *header = new;
486         return 0;
487 }
488
489 /*
490  * Generate new extended ACL based on the posix ACL.
491  */
492 ext_acl_xattr_header *
493 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
494 {
495         int count, i, esize;
496         ext_acl_xattr_header *new;
497         ENTRY;
498
499         if (unlikely(size < 0))
500                 RETURN(ERR_PTR(-EINVAL));
501         else if (!size)
502                 count = 0;
503         else
504                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
505         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
506         OBD_ALLOC(new, esize);
507         if (unlikely(new == NULL))
508                 RETURN(ERR_PTR(-ENOMEM));
509
510         new->a_count = cpu_to_le32(count);
511         for (i = 0; i < count; i++) {
512                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
513                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
514                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
515                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
516         }
517
518         RETURN(new);
519 }
520 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
521
522 /*
523  * Filter out the "nobody" entries in the posix ACL.
524  */
525 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
526                                   posix_acl_xattr_header **out)
527 {
528         int count, i, j, rc = 0;
529         __u32 id;
530         posix_acl_xattr_header *new;
531         ENTRY;
532
533         if (unlikely(size < 0))
534                 RETURN(-EINVAL);
535         else if (!size)
536                 RETURN(0);
537
538         OBD_ALLOC(new, size);
539         if (unlikely(new == NULL))
540                 RETURN(-ENOMEM);
541
542         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
543         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
544         for (i = 0, j = 0; i < count; i++) {
545                 id = le32_to_cpu(header->a_entries[i].e_id);
546                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
547                 case ACL_USER_OBJ:
548                 case ACL_GROUP_OBJ:
549                 case ACL_MASK:
550                 case ACL_OTHER:
551                         if (id != ACL_UNDEFINED_ID)
552                                 GOTO(_out, rc = -EIO);
553
554                         memcpy(&new->a_entries[j++], &header->a_entries[i],
555                                sizeof(posix_acl_xattr_entry));
556                         break;
557                 case ACL_USER:
558                         if (id != NOBODY_UID)
559                                 memcpy(&new->a_entries[j++],
560                                        &header->a_entries[i],
561                                        sizeof(posix_acl_xattr_entry));
562                         break;
563                 case ACL_GROUP:
564                         if (id != NOBODY_GID)
565                                 memcpy(&new->a_entries[j++],
566                                        &header->a_entries[i],
567                                        sizeof(posix_acl_xattr_entry));
568                         break;
569                 default:
570                         GOTO(_out, rc = -EIO);
571                 }
572         }
573
574         /* free unused space. */
575         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
576         if (rc >= 0) {
577                 size = rc;
578                 *out = new;
579                 rc = 0;
580         }
581         EXIT;
582
583 _out:
584         if (rc) {
585                 OBD_FREE(new, size);
586                 size = rc;
587         }
588         return size;
589 }
590 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
591
592 /*
593  * Release the posix ACL space.
594  */
595 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
596 {
597         OBD_FREE(header, size);
598 }
599 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
600
601 /*
602  * Release the extended ACL space.
603  */
604 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
605 {
606         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
607                                             ext_acl_xattr));
608 }
609 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
610
611 static ext_acl_xattr_entry *
612 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
613                             posix_acl_xattr_entry *entry, int *pos)
614 {
615         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
616
617         once = 0;
618         start = *pos;
619         end = count;
620
621 again:
622         for (i = start; i < end; i++) {
623                 if (header->a_entries[i].e_tag == entry->e_tag &&
624                     header->a_entries[i].e_id == entry->e_id) {
625                         j = i;
626                         if (++i >= count)
627                                 i = 0;
628                         *pos = i;
629                         return &header->a_entries[j];
630                 }
631         }
632
633         if (!once) {
634                 once = 1;
635                 start = 0;
636                 end = *pos;
637                 goto again;
638         }
639
640         return NULL;
641 }
642
643 /*
644  * Merge the posix ACL and the extended ACL into new posix ACL.
645  */
646 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
647                                  ext_acl_xattr_header *ext_header,
648                                  posix_acl_xattr_header **out)
649 {
650         int posix_count, posix_size, i, j;
651         int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
652         posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
653         posix_acl_xattr_header *new;
654         ext_acl_xattr_entry *ee, ae;
655         ENTRY;
656
657         lustre_posix_acl_cpu_to_le(&pe, &pe);
658         ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
659         if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
660                 /* there are only base ACL entries at most. */
661                 posix_count = 3;
662                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
663                 OBD_ALLOC(new, posix_size);
664                 if (unlikely(new == NULL))
665                         RETURN(-ENOMEM);
666
667                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
668                 for (i = 0, j = 0; i < ext_count; i++) {
669                         lustre_ext_acl_le_to_cpu(&ae,
670                                                  &ext_header->a_entries[i]);
671                         switch (ae.e_tag) {
672                         case ACL_USER_OBJ:
673                         case ACL_GROUP_OBJ:
674                         case ACL_OTHER:
675                                 if (ae.e_id != ACL_UNDEFINED_ID)
676                                         GOTO(_out, rc = -EIO);
677
678                                 if (ae.e_stat != ES_DEL) {
679                                         new->a_entries[j].e_tag =
680                                                 ext_header->a_entries[i].e_tag;
681                                         new->a_entries[j].e_perm =
682                                                 ext_header->a_entries[i].e_perm;
683                                         new->a_entries[j++].e_id =
684                                                 ext_header->a_entries[i].e_id;
685                                 }
686                                 break;
687                         case ACL_MASK:
688                         case ACL_USER:
689                         case ACL_GROUP:
690                                 if (ae.e_stat == ES_DEL)
691                                         break;
692                         default:
693                                 GOTO(_out, rc = -EIO);
694                         }
695                 }
696         } else {
697                 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
698                  * original server-side ACL, they are regarded as ES_UNC stat.*/
699                 int ori_posix_count;
700
701                 if (unlikely(size < 0))
702                         RETURN(-EINVAL);
703                 else if (!size)
704                         ori_posix_count = 0;
705                 else
706                         ori_posix_count =
707                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
708                 posix_count = ori_posix_count + ext_count;
709                 posix_size =
710                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
711                 OBD_ALLOC(new, posix_size);
712                 if (unlikely(new == NULL))
713                         RETURN(-ENOMEM);
714
715                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
716                 /* 1. process the unchanged ACL entries
717                  *    in the original server-side ACL. */
718                 pos = 0;
719                 for (i = 0, j = 0; i < ori_posix_count; i++) {
720                         ee = lustre_ext_acl_xattr_search(ext_header,
721                                         &posix_header->a_entries[i], &pos);
722                         if (ee == NULL)
723                                 memcpy(&new->a_entries[j++],
724                                        &posix_header->a_entries[i],
725                                        sizeof(posix_acl_xattr_entry));
726                 }
727
728                 /* 2. process the non-deleted entries
729                  *    from client-side extended ACL. */
730                 for (i = 0; i < ext_count; i++) {
731                         if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
732                             ES_DEL) {
733                                 new->a_entries[j].e_tag =
734                                                 ext_header->a_entries[i].e_tag;
735                                 new->a_entries[j].e_perm =
736                                                 ext_header->a_entries[i].e_perm;
737                                 new->a_entries[j++].e_id =
738                                                 ext_header->a_entries[i].e_id;
739                         }
740                 }
741         }
742
743         /* free unused space. */
744         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
745         if (rc >= 0) {
746                 posix_size = rc;
747                 *out = new;
748                 rc = 0;
749         }
750         EXIT;
751
752 _out:
753         if (rc) {
754                 OBD_FREE(new, posix_size);
755                 posix_size = rc;
756         }
757         return posix_size;
758 }
759 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
760
761 /*
762  * Merge the posix ACL and the extended ACL into new extended ACL.
763  */
764 ext_acl_xattr_header *
765 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
766                            ext_acl_xattr_header *ext_header)
767 {
768         int ori_ext_count, posix_count, ext_count, ext_size;
769         int i, j, pos = 0, rc = 0;
770         posix_acl_xattr_entry pae;
771         ext_acl_xattr_header *new;
772         ext_acl_xattr_entry *ee, eae;
773         ENTRY;
774
775         if (unlikely(size < 0))
776                 RETURN(ERR_PTR(-EINVAL));
777         else if (!size)
778                 posix_count = 0;
779         else
780                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
781         ori_ext_count = le32_to_cpu(ext_header->a_count);
782         ext_count = posix_count + ori_ext_count;
783         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
784
785         OBD_ALLOC(new, ext_size);
786         if (unlikely(new == NULL))
787                 RETURN(ERR_PTR(-ENOMEM));
788
789         for (i = 0, j = 0; i < posix_count; i++) {
790                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
791                 switch (pae.e_tag) {
792                 case ACL_USER_OBJ:
793                 case ACL_GROUP_OBJ:
794                 case ACL_MASK:
795                 case ACL_OTHER:
796                         if (pae.e_id != ACL_UNDEFINED_ID)
797                                 GOTO(out, rc = -EIO);
798                 case ACL_USER:
799                         /* ignore "nobody" entry. */
800                         if (pae.e_id == NOBODY_UID)
801                                 break;
802
803                         new->a_entries[j].e_tag =
804                                         posix_header->a_entries[i].e_tag;
805                         new->a_entries[j].e_perm =
806                                         posix_header->a_entries[i].e_perm;
807                         new->a_entries[j].e_id =
808                                         posix_header->a_entries[i].e_id;
809                         ee = lustre_ext_acl_xattr_search(ext_header,
810                                         &posix_header->a_entries[i], &pos);
811                         if (ee) {
812                                 if (posix_header->a_entries[i].e_perm !=
813                                                                 ee->e_perm)
814                                         /* entry modified. */
815                                         ee->e_stat =
816                                         new->a_entries[j++].e_stat =
817                                                         cpu_to_le32(ES_MOD);
818                                 else
819                                         /* entry unchanged. */
820                                         ee->e_stat =
821                                         new->a_entries[j++].e_stat =
822                                                         cpu_to_le32(ES_UNC);
823                         } else {
824                                 /* new entry. */
825                                 new->a_entries[j++].e_stat =
826                                                         cpu_to_le32(ES_ADD);
827                         }
828                         break;
829                 case ACL_GROUP:
830                         /* ignore "nobody" entry. */
831                         if (pae.e_id == NOBODY_GID)
832                                 break;
833                         new->a_entries[j].e_tag =
834                                         posix_header->a_entries[i].e_tag;
835                         new->a_entries[j].e_perm =
836                                         posix_header->a_entries[i].e_perm;
837                         new->a_entries[j].e_id =
838                                         posix_header->a_entries[i].e_id;
839                         ee = lustre_ext_acl_xattr_search(ext_header,
840                                         &posix_header->a_entries[i], &pos);
841                         if (ee) {
842                                 if (posix_header->a_entries[i].e_perm !=
843                                                                 ee->e_perm)
844                                         /* entry modified. */
845                                         ee->e_stat =
846                                         new->a_entries[j++].e_stat =
847                                                         cpu_to_le32(ES_MOD);
848                                 else
849                                         /* entry unchanged. */
850                                         ee->e_stat =
851                                         new->a_entries[j++].e_stat =
852                                                         cpu_to_le32(ES_UNC);
853                         } else {
854                                 /* new entry. */
855                                 new->a_entries[j++].e_stat =
856                                                         cpu_to_le32(ES_ADD);
857                         }
858                         break;
859                 default:
860                         GOTO(out, rc = -EIO);
861                 }
862         }
863
864         /* process deleted entries. */
865         for (i = 0; i < ori_ext_count; i++) {
866                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
867                 if (eae.e_stat == ES_UNK) {
868                         /* ignore "nobody" entry. */
869                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
870                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
871                                 continue;
872
873                         new->a_entries[j].e_tag =
874                                                 ext_header->a_entries[i].e_tag;
875                         new->a_entries[j].e_perm =
876                                                 ext_header->a_entries[i].e_perm;
877                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
878                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
879                 }
880         }
881
882         new->a_count = cpu_to_le32(j);
883         /* free unused space. */
884         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
885         EXIT;
886
887 out:
888         if (rc) {
889                 OBD_FREE(new, ext_size);
890                 new = ERR_PTR(rc);
891         }
892         return new;
893 }
894 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
895
896 #endif