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