Whamcloud - gitweb
LU-1347 style: removes obsolete EXPORT_SYMTAB macros
[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  * Modify acl when creating a new object.
209  */
210 int lustre_posix_acl_create_masq(posix_acl_xattr_entry *entry, __u32 *pmode,
211                                  int count)
212 {
213         posix_acl_xattr_entry *group_obj = NULL, *mask_obj = NULL, *pa, *pe;
214         posix_acl_xattr_entry ae;
215         __u32 mode = *pmode;
216         int not_equiv = 0;
217
218         for (pa = &entry[0], pe = &entry[count - 1]; pa <= pe; pa++) {
219                 lustre_posix_acl_le_to_cpu(&ae, pa);
220                 switch (ae.e_tag) {
221                 case ACL_USER_OBJ:
222                         ae.e_perm &= (mode >> 6) | ~S_IRWXO;
223                         pa->e_perm = cpu_to_le16(ae.e_perm);
224                         mode &= (ae.e_perm << 6) | ~S_IRWXU;
225                         break;
226                 case ACL_USER:
227                 case ACL_GROUP:
228                         not_equiv = 1;
229                         break;
230                 case ACL_GROUP_OBJ:
231                         group_obj = pa;
232                         break;
233                 case ACL_OTHER:
234                         ae.e_perm &= mode | ~S_IRWXO;
235                         pa->e_perm = cpu_to_le16(ae.e_perm);
236                         mode &= ae.e_perm | ~S_IRWXO;
237                         break;
238                 case ACL_MASK:
239                         mask_obj = pa;
240                         not_equiv = 1;
241                         break;
242                 default:
243                         return -EIO;
244                 }
245         }
246
247         if (mask_obj) {
248                 ae.e_perm = le16_to_cpu(mask_obj->e_perm) &
249                             ((mode >> 3) | ~S_IRWXO);
250                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
251                 mask_obj->e_perm = cpu_to_le16(ae.e_perm);
252         } else {
253                 if (!group_obj)
254                         return -EIO;
255                 ae.e_perm = le16_to_cpu(group_obj->e_perm) &
256                             ((mode >> 3) | ~S_IRWXO);
257                 mode &= (ae.e_perm << 3) | ~S_IRWXG;
258                 group_obj->e_perm = cpu_to_le16(ae.e_perm);
259         }
260
261         *pmode = (*pmode & ~S_IRWXUGO) | mode;
262         return not_equiv;
263 }
264 EXPORT_SYMBOL(lustre_posix_acl_create_masq);
265
266 /* if "new_count == 0", then "new = {a_version, NULL}", NOT NULL. */
267 static int lustre_posix_acl_xattr_reduce_space(posix_acl_xattr_header **header,
268                                                int old_count, int new_count)
269 {
270         int old_size = CFS_ACL_XATTR_SIZE(old_count, posix_acl_xattr);
271         int new_size = CFS_ACL_XATTR_SIZE(new_count, posix_acl_xattr);
272         posix_acl_xattr_header *new;
273
274         if (unlikely(old_count <= new_count))
275                 return old_size;
276
277         OBD_ALLOC(new, new_size);
278         if (unlikely(new == NULL))
279                 return -ENOMEM;
280
281         memcpy(new, *header, new_size);
282         OBD_FREE(*header, old_size);
283         *header = new;
284         return new_size;
285 }
286
287 /* if "new_count == 0", then "new = {0, NULL}", NOT NULL. */
288 static int lustre_ext_acl_xattr_reduce_space(ext_acl_xattr_header **header,
289                                              int old_count)
290 {
291         int ext_count = le32_to_cpu((*header)->a_count);
292         int ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
293         int old_size = CFS_ACL_XATTR_SIZE(old_count, ext_acl_xattr);
294         ext_acl_xattr_header *new;
295
296         if (unlikely(old_count <= ext_count))
297                 return 0;
298
299         OBD_ALLOC(new, ext_size);
300         if (unlikely(new == NULL))
301                 return -ENOMEM;
302
303         memcpy(new, *header, ext_size);
304         OBD_FREE(*header, old_size);
305         *header = new;
306         return 0;
307 }
308
309 /*
310  * Generate new extended ACL based on the posix ACL.
311  */
312 ext_acl_xattr_header *
313 lustre_posix_acl_xattr_2ext(posix_acl_xattr_header *header, int size)
314 {
315         int count, i, esize;
316         ext_acl_xattr_header *new;
317         ENTRY;
318
319         if (unlikely(size < 0))
320                 RETURN(ERR_PTR(-EINVAL));
321         else if (!size)
322                 count = 0;
323         else
324                 count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
325         esize = CFS_ACL_XATTR_SIZE(count, ext_acl_xattr);
326         OBD_ALLOC(new, esize);
327         if (unlikely(new == NULL))
328                 RETURN(ERR_PTR(-ENOMEM));
329
330         new->a_count = cpu_to_le32(count);
331         for (i = 0; i < count; i++) {
332                 new->a_entries[i].e_tag  = header->a_entries[i].e_tag;
333                 new->a_entries[i].e_perm = header->a_entries[i].e_perm;
334                 new->a_entries[i].e_id   = header->a_entries[i].e_id;
335                 new->a_entries[i].e_stat = cpu_to_le32(ES_UNK);
336         }
337
338         RETURN(new);
339 }
340 EXPORT_SYMBOL(lustre_posix_acl_xattr_2ext);
341
342 /*
343  * Filter out the "nobody" entries in the posix ACL.
344  */
345 int lustre_posix_acl_xattr_filter(posix_acl_xattr_header *header, int size,
346                                   posix_acl_xattr_header **out)
347 {
348         int count, i, j, rc = 0;
349         __u32 id;
350         posix_acl_xattr_header *new;
351         ENTRY;
352
353         if (unlikely(size < 0))
354                 RETURN(-EINVAL);
355         else if (!size)
356                 RETURN(0);
357
358         OBD_ALLOC(new, size);
359         if (unlikely(new == NULL))
360                 RETURN(-ENOMEM);
361
362         new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
363         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
364         for (i = 0, j = 0; i < count; i++) {
365                 id = le32_to_cpu(header->a_entries[i].e_id);
366                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
367                 case ACL_USER_OBJ:
368                 case ACL_GROUP_OBJ:
369                 case ACL_MASK:
370                 case ACL_OTHER:
371                         if (id != ACL_UNDEFINED_ID)
372                                 GOTO(_out, rc = -EIO);
373
374                         memcpy(&new->a_entries[j++], &header->a_entries[i],
375                                sizeof(posix_acl_xattr_entry));
376                         break;
377                 case ACL_USER:
378                         if (id != NOBODY_UID)
379                                 memcpy(&new->a_entries[j++],
380                                        &header->a_entries[i],
381                                        sizeof(posix_acl_xattr_entry));
382                         break;
383                 case ACL_GROUP:
384                         if (id != NOBODY_GID)
385                                 memcpy(&new->a_entries[j++],
386                                        &header->a_entries[i],
387                                        sizeof(posix_acl_xattr_entry));
388                         break;
389                 default:
390                         GOTO(_out, rc = -EIO);
391                 }
392         }
393
394         /* free unused space. */
395         rc = lustre_posix_acl_xattr_reduce_space(&new, count, j);
396         if (rc >= 0) {
397                 size = rc;
398                 *out = new;
399                 rc = 0;
400         }
401         EXIT;
402
403 _out:
404         if (rc) {
405                 OBD_FREE(new, size);
406                 size = rc;
407         }
408         return size;
409 }
410 EXPORT_SYMBOL(lustre_posix_acl_xattr_filter);
411
412 /*
413  * Convert server-side uid/gid in the posix ACL items to the client-side ones.
414  * convert rule:
415  * @CFS_IC_NOTHING
416  *  nothing to be converted.
417  * @CFS_IC_ALL
418  *  mapped ids are converted to client-side ones,
419  *  unmapped ones are converted to "nobody".
420  * @CFS_IC_MAPPED
421  *  only mapped ids are converted to "nobody".
422  * @CFS_IC_UNMAPPED
423  *  only unmapped ids are converted to "nobody".
424  */
425 int lustre_posix_acl_xattr_id2client(struct md_ucred *mu,
426                                      struct lustre_idmap_table *t,
427                                      posix_acl_xattr_header *header,
428                                      int size, int flags)
429 {
430         int count, i;
431         __u32 id;
432         ENTRY;
433
434         if (unlikely(size < 0))
435                 RETURN(-EINVAL);
436         else if (!size)
437                 RETURN(0);
438
439         if (unlikely(flags == CFS_IC_NOTHING))
440                 RETURN(0);
441
442         count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
443         for (i = 0; i < count; i++) {
444                 id = le32_to_cpu(header->a_entries[i].e_id);
445                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
446                 case ACL_USER_OBJ:
447                 case ACL_GROUP_OBJ:
448                 case ACL_MASK:
449                 case ACL_OTHER:
450                         if (id != ACL_UNDEFINED_ID)
451                                 RETURN(-EIO);
452                         break;
453                 case ACL_USER:
454                         id = lustre_idmap_lookup_uid(mu, t, 1, id);
455                         if (flags == CFS_IC_ALL) {
456                                 if (id == CFS_IDMAP_NOTFOUND)
457                                         id = NOBODY_UID;
458                                 header->a_entries[i].e_id = cpu_to_le32(id);
459                         } else if (flags == CFS_IC_MAPPED) {
460                                 if (id != CFS_IDMAP_NOTFOUND)
461                                         header->a_entries[i].e_id =
462                                                         cpu_to_le32(NOBODY_UID);
463                         } else if (flags == CFS_IC_UNMAPPED) {
464                                 if (id == CFS_IDMAP_NOTFOUND)
465                                         header->a_entries[i].e_id =
466                                                         cpu_to_le32(NOBODY_UID);
467                         }
468                         break;
469                 case ACL_GROUP:
470                         id = lustre_idmap_lookup_gid(mu, t, 1, id);
471                         if (flags == CFS_IC_ALL) {
472                                 if (id == CFS_IDMAP_NOTFOUND)
473                                         id = NOBODY_GID;
474                                 header->a_entries[i].e_id = cpu_to_le32(id);
475                         } else if (flags == CFS_IC_MAPPED) {
476                                 if (id != CFS_IDMAP_NOTFOUND)
477                                         header->a_entries[i].e_id =
478                                                         cpu_to_le32(NOBODY_GID);
479                         } else if (flags == CFS_IC_UNMAPPED) {
480                                 if (id == CFS_IDMAP_NOTFOUND)
481                                         header->a_entries[i].e_id =
482                                                         cpu_to_le32(NOBODY_GID);
483                         }
484                         break;
485                  default:
486                         RETURN(-EIO);
487                 }
488         }
489     RETURN(0);
490 }
491 EXPORT_SYMBOL(lustre_posix_acl_xattr_id2client);
492
493 /*
494  * Release the posix ACL space.
495  */
496 void lustre_posix_acl_xattr_free(posix_acl_xattr_header *header, int size)
497 {
498         OBD_FREE(header, size);
499 }
500 EXPORT_SYMBOL(lustre_posix_acl_xattr_free);
501
502 /*
503  * Converts client-side uid/gid in the extended ACL items to server-side ones.
504  * convert rule:
505  *  mapped ids are converted to server-side ones,
506  *  unmapped ones cause "EPERM" error.
507  */
508 int lustre_ext_acl_xattr_id2server(struct md_ucred *mu,
509                                    struct lustre_idmap_table *t,
510                                    ext_acl_xattr_header *header)
511
512 {
513         int i, count = le32_to_cpu(header->a_count);
514         __u32 id;
515         ENTRY;
516
517         for (i = 0; i < count; i++) {
518                 id = le32_to_cpu(header->a_entries[i].e_id);
519                 switch (le16_to_cpu(header->a_entries[i].e_tag)) {
520                 case ACL_USER_OBJ:
521                 case ACL_GROUP_OBJ:
522                 case ACL_MASK:
523                 case ACL_OTHER:
524                         if (id != ACL_UNDEFINED_ID)
525                                 RETURN(-EIO);
526                         break;
527                 case ACL_USER:
528                         id = lustre_idmap_lookup_uid(mu, t, 0, id);
529                         if (id == CFS_IDMAP_NOTFOUND)
530                                 RETURN(-EPERM);
531                         else
532                                 header->a_entries[i].e_id = cpu_to_le32(id);
533                         break;
534                 case ACL_GROUP:
535                         id = lustre_idmap_lookup_gid(mu, t, 0, id);
536                         if (id == CFS_IDMAP_NOTFOUND)
537                                 RETURN(-EPERM);
538                         else
539                                 header->a_entries[i].e_id = cpu_to_le32(id);
540                         break;
541                 default:
542                         RETURN(-EIO);
543                 }
544         }
545         RETURN(0);
546 }
547 EXPORT_SYMBOL(lustre_ext_acl_xattr_id2server);
548
549 /*
550  * Release the extended ACL space.
551  */
552 void lustre_ext_acl_xattr_free(ext_acl_xattr_header *header)
553 {
554         OBD_FREE(header, CFS_ACL_XATTR_SIZE(le32_to_cpu(header->a_count), \
555                                             ext_acl_xattr));
556 }
557 EXPORT_SYMBOL(lustre_ext_acl_xattr_free);
558
559 static ext_acl_xattr_entry *
560 lustre_ext_acl_xattr_search(ext_acl_xattr_header *header,
561                             posix_acl_xattr_entry *entry, int *pos)
562 {
563         int once, start, end, i, j, count = le32_to_cpu(header->a_count);
564
565         once = 0;
566         start = *pos;
567         end = count;
568
569 again:
570         for (i = start; i < end; i++) {
571                 if (header->a_entries[i].e_tag == entry->e_tag &&
572                     header->a_entries[i].e_id == entry->e_id) {
573                         j = i;
574                         if (++i >= count)
575                                 i = 0;
576                         *pos = i;
577                         return &header->a_entries[j];
578                 }
579         }
580
581         if (!once) {
582                 once = 1;
583                 start = 0;
584                 end = *pos;
585                 goto again;
586         }
587
588         return NULL;
589 }
590
591 /*
592  * Merge the posix ACL and the extended ACL into new posix ACL.
593  */
594 int lustre_acl_xattr_merge2posix(posix_acl_xattr_header *posix_header, int size,
595                                  ext_acl_xattr_header *ext_header,
596                                  posix_acl_xattr_header **out)
597 {
598         int posix_count, posix_size, i, j;
599         int ext_count = le32_to_cpu(ext_header->a_count), pos = 0, rc = 0;
600         posix_acl_xattr_entry pe = {ACL_MASK, 0, ACL_UNDEFINED_ID};
601         posix_acl_xattr_header *new;
602         ext_acl_xattr_entry *ee, ae;
603         ENTRY;
604
605         lustre_posix_acl_cpu_to_le(&pe, &pe);
606         ee = lustre_ext_acl_xattr_search(ext_header, &pe, &pos);
607         if (ee == NULL || le32_to_cpu(ee->e_stat) == ES_DEL) {
608                 /* there are only base ACL entries at most. */
609                 posix_count = 3;
610                 posix_size = CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
611                 OBD_ALLOC(new, posix_size);
612                 if (unlikely(new == NULL))
613                         RETURN(-ENOMEM);
614
615                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
616                 for (i = 0, j = 0; i < ext_count; i++) {
617                         lustre_ext_acl_le_to_cpu(&ae,
618                                                  &ext_header->a_entries[i]);
619                         switch (ae.e_tag) {
620                         case ACL_USER_OBJ:
621                         case ACL_GROUP_OBJ:
622                         case ACL_OTHER:
623                                 if (ae.e_id != ACL_UNDEFINED_ID)
624                                         GOTO(_out, rc = -EIO);
625
626                                 if (ae.e_stat != ES_DEL) {
627                                         new->a_entries[j].e_tag =
628                                                 ext_header->a_entries[i].e_tag;
629                                         new->a_entries[j].e_perm =
630                                                 ext_header->a_entries[i].e_perm;
631                                         new->a_entries[j++].e_id =
632                                                 ext_header->a_entries[i].e_id;
633                                 }
634                                 break;
635                         case ACL_MASK:
636                         case ACL_USER:
637                         case ACL_GROUP:
638                                 if (ae.e_stat == ES_DEL)
639                                         break;
640                         default:
641                                 GOTO(_out, rc = -EIO);
642                         }
643                 }
644         } else {
645                 /* maybe there are valid ACL_USER or ACL_GROUP entries in the
646                  * original server-side ACL, they are regarded as ES_UNC stat.*/
647                 int ori_posix_count;
648
649                 if (unlikely(size < 0))
650                         RETURN(-EINVAL);
651                 else if (!size)
652                         ori_posix_count = 0;
653                 else
654                         ori_posix_count =
655                                 CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
656                 posix_count = ori_posix_count + ext_count;
657                 posix_size =
658                         CFS_ACL_XATTR_SIZE(posix_count, posix_acl_xattr);
659                 OBD_ALLOC(new, posix_size);
660                 if (unlikely(new == NULL))
661                         RETURN(-ENOMEM);
662
663                 new->a_version = cpu_to_le32(CFS_ACL_XATTR_VERSION);
664                 /* 1. process the unchanged ACL entries
665                  *    in the original server-side ACL. */
666                 pos = 0;
667                 for (i = 0, j = 0; i < ori_posix_count; i++) {
668                         ee = lustre_ext_acl_xattr_search(ext_header,
669                                         &posix_header->a_entries[i], &pos);
670                         if (ee == NULL)
671                                 memcpy(&new->a_entries[j++],
672                                        &posix_header->a_entries[i],
673                                        sizeof(posix_acl_xattr_entry));
674                 }
675
676                 /* 2. process the non-deleted entries
677                  *    from client-side extended ACL. */
678                 for (i = 0; i < ext_count; i++) {
679                         if (le16_to_cpu(ext_header->a_entries[i].e_stat) !=
680                             ES_DEL) {
681                                 new->a_entries[j].e_tag =
682                                                 ext_header->a_entries[i].e_tag;
683                                 new->a_entries[j].e_perm =
684                                                 ext_header->a_entries[i].e_perm;
685                                 new->a_entries[j++].e_id =
686                                                 ext_header->a_entries[i].e_id;
687                         }
688                 }
689         }
690
691         /* free unused space. */
692         rc = lustre_posix_acl_xattr_reduce_space(&new, posix_count, j);
693         if (rc >= 0) {
694                 posix_size = rc;
695                 *out = new;
696                 rc = 0;
697         }
698         EXIT;
699
700 _out:
701         if (rc) {
702                 OBD_FREE(new, posix_size);
703                 posix_size = rc;
704         }
705         return posix_size;
706 }
707 EXPORT_SYMBOL(lustre_acl_xattr_merge2posix);
708
709 /*
710  * Merge the posix ACL and the extended ACL into new extended ACL.
711  */
712 ext_acl_xattr_header *
713 lustre_acl_xattr_merge2ext(posix_acl_xattr_header *posix_header, int size,
714                            ext_acl_xattr_header *ext_header)
715 {
716         int ori_ext_count, posix_count, ext_count, ext_size;
717         int i, j, pos = 0, rc = 0;
718         posix_acl_xattr_entry pae;
719         ext_acl_xattr_header *new;
720         ext_acl_xattr_entry *ee, eae;
721         ENTRY;
722
723         if (unlikely(size < 0))
724                 RETURN(ERR_PTR(-EINVAL));
725         else if (!size)
726                 posix_count = 0;
727         else
728                 posix_count = CFS_ACL_XATTR_COUNT(size, posix_acl_xattr);
729         ori_ext_count = le32_to_cpu(ext_header->a_count);
730         ext_count = posix_count + ori_ext_count;
731         ext_size = CFS_ACL_XATTR_SIZE(ext_count, ext_acl_xattr);
732
733         OBD_ALLOC(new, ext_size);
734         if (unlikely(new == NULL))
735                 RETURN(ERR_PTR(-ENOMEM));
736
737         for (i = 0, j = 0; i < posix_count; i++) {
738                 lustre_posix_acl_le_to_cpu(&pae, &posix_header->a_entries[i]);
739                 switch (pae.e_tag) {
740                 case ACL_USER_OBJ:
741                 case ACL_GROUP_OBJ:
742                 case ACL_MASK:
743                 case ACL_OTHER:
744                         if (pae.e_id != ACL_UNDEFINED_ID)
745                                 GOTO(out, rc = -EIO);
746                 case ACL_USER:
747                         /* ignore "nobody" entry. */
748                         if (pae.e_id == NOBODY_UID)
749                                 break;
750
751                         new->a_entries[j].e_tag =
752                                         posix_header->a_entries[i].e_tag;
753                         new->a_entries[j].e_perm =
754                                         posix_header->a_entries[i].e_perm;
755                         new->a_entries[j].e_id =
756                                         posix_header->a_entries[i].e_id;
757                         ee = lustre_ext_acl_xattr_search(ext_header,
758                                         &posix_header->a_entries[i], &pos);
759                         if (ee) {
760                                 if (posix_header->a_entries[i].e_perm !=
761                                                                 ee->e_perm)
762                                         /* entry modified. */
763                                         ee->e_stat =
764                                         new->a_entries[j++].e_stat =
765                                                         cpu_to_le32(ES_MOD);
766                                 else
767                                         /* entry unchanged. */
768                                         ee->e_stat =
769                                         new->a_entries[j++].e_stat =
770                                                         cpu_to_le32(ES_UNC);
771                         } else {
772                                 /* new entry. */
773                                 new->a_entries[j++].e_stat =
774                                                         cpu_to_le32(ES_ADD);
775                         }
776                         break;
777                 case ACL_GROUP:
778                         /* ignore "nobody" entry. */
779                         if (pae.e_id == NOBODY_GID)
780                                 break;
781                         new->a_entries[j].e_tag =
782                                         posix_header->a_entries[i].e_tag;
783                         new->a_entries[j].e_perm =
784                                         posix_header->a_entries[i].e_perm;
785                         new->a_entries[j].e_id =
786                                         posix_header->a_entries[i].e_id;
787                         ee = lustre_ext_acl_xattr_search(ext_header,
788                                         &posix_header->a_entries[i], &pos);
789                         if (ee) {
790                                 if (posix_header->a_entries[i].e_perm !=
791                                                                 ee->e_perm)
792                                         /* entry modified. */
793                                         ee->e_stat =
794                                         new->a_entries[j++].e_stat =
795                                                         cpu_to_le32(ES_MOD);
796                                 else
797                                         /* entry unchanged. */
798                                         ee->e_stat =
799                                         new->a_entries[j++].e_stat =
800                                                         cpu_to_le32(ES_UNC);
801                         } else {
802                                 /* new entry. */
803                                 new->a_entries[j++].e_stat =
804                                                         cpu_to_le32(ES_ADD);
805                         }
806                         break;
807                 default:
808                         GOTO(out, rc = -EIO);
809                 }
810         }
811
812         /* process deleted entries. */
813         for (i = 0; i < ori_ext_count; i++) {
814                 lustre_ext_acl_le_to_cpu(&eae, &ext_header->a_entries[i]);
815                 if (eae.e_stat == ES_UNK) {
816                         /* ignore "nobody" entry. */
817                         if ((eae.e_tag == ACL_USER && eae.e_id == NOBODY_UID) ||
818                             (eae.e_tag == ACL_GROUP && eae.e_id == NOBODY_GID))
819                                 continue;
820
821                         new->a_entries[j].e_tag =
822                                                 ext_header->a_entries[i].e_tag;
823                         new->a_entries[j].e_perm =
824                                                 ext_header->a_entries[i].e_perm;
825                         new->a_entries[j].e_id = ext_header->a_entries[i].e_id;
826                         new->a_entries[j++].e_stat = cpu_to_le32(ES_DEL);
827                 }
828         }
829
830         new->a_count = cpu_to_le32(j);
831         /* free unused space. */
832         rc = lustre_ext_acl_xattr_reduce_space(&new, ext_count);
833         EXIT;
834
835 out:
836         if (rc) {
837                 OBD_FREE(new, ext_size);
838                 new = ERR_PTR(rc);
839         }
840         return new;
841 }
842 EXPORT_SYMBOL(lustre_acl_xattr_merge2ext);
843
844 #endif