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