Whamcloud - gitweb
Don't assert bitmap exists - it won't for error-during-setup self-export destroy
[fs/lustre-release.git] / lustre / kernel_patches / patches / linux-2.4.20-tmpfs-xattr.patch
1 diff -rupN --exclude='ide*' linux-2.4.20.orig/fs/Config.in linux-2.4.20/fs/Config.in
2 --- linux-2.4.20.orig/fs/Config.in      2002-11-29 01:53:15.000000000 +0200
3 +++ linux-2.4.20/fs/Config.in   2004-02-08 21:37:47.000000000 +0200
4 @@ -48,6 +48,9 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFI
5  fi
6  tristate 'Compressed ROM file system support' CONFIG_CRAMFS
7  bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
8 +if [ "$CONFIG_TMPFS" = "y" ]; then
9 +   bool '  tmpfs Extended Attributes' CONFIG_TMPFS_XATTR
10 +fi
11  define_bool CONFIG_RAMFS y
12  
13  tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS
14 diff -rupN --exclude='ide*' linux-2.4.20.orig/include/linux/mm.h linux-2.4.20/include/linux/mm.h
15 --- linux-2.4.20.orig/include/linux/mm.h        2002-08-03 03:39:45.000000000 +0300
16 +++ linux-2.4.20/include/linux/mm.h     2004-02-10 11:43:10.000000000 +0200
17 @@ -468,6 +468,7 @@ extern void clear_page_tables(struct mm_
18  extern int fail_writepage(struct page *);
19  struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int unused);
20  struct file *shmem_file_setup(char * name, loff_t size);
21 +int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr);
22  extern void shmem_lock(struct file * file, int lock);
23  extern int shmem_zero_setup(struct vm_area_struct *);
24  
25 diff -rupN --exclude='ide*' linux-2.4.20.orig/include/linux/shmem_fs.h linux-2.4.20/include/linux/shmem_fs.h
26 --- linux-2.4.20.orig/include/linux/shmem_fs.h  2001-12-21 19:42:03.000000000 +0200
27 +++ linux-2.4.20/include/linux/shmem_fs.h       2004-02-10 18:39:17.000000000 +0200
28 @@ -3,6 +3,8 @@
29  
30  /* inode in-kernel data */
31  
32 +#include <linux/config.h>
33 +
34  #define SHMEM_NR_DIRECT 16
35  
36  /*
37 @@ -28,6 +30,10 @@ struct shmem_inode_info {
38         unsigned long           swapped;
39         int                     locked;     /* into memory */
40         struct list_head        list;
41 +#ifdef CONFIG_TMPFS_XATTR
42 +       struct list_head        xattrs;
43 +       struct list_head        *xtail;
44 +#endif
45         struct inode           *inode;
46  };
47  
48 @@ -39,6 +45,32 @@ struct shmem_sb_info {
49         spinlock_t    stat_lock;
50  };
51  
52 +#ifdef CONFIG_TMPFS_XATTR
53 +struct shmem_xattr {
54 +       u8 namelen;
55 +       u16 valuelen;
56 +       void *entity;
57 +       struct list_head list;
58 +};
59 +
60 +extern struct shmem_xattr *
61 +shmem_xattr_find(struct inode *inode, const char *name);
62 +
63 +extern ssize_t
64 +shmem_xattr_set(struct inode *inode, const char *name,
65 +               const void *value, u16 valuelen, int flags);
66 +               
67 +extern ssize_t
68 +shmem_xattr_get(struct inode *inode, const char *name,
69 +               void *value, size_t valuelen);
70 +               
71 +extern int
72 +shmem_xattr_delete(struct inode *inode, struct shmem_xattr *xattr);
73 +
74 +extern int
75 +shmem_xattr_remove(struct inode *inode, const char *name);
76 +#endif
77 +
78  #define SHMEM_I(inode)  (&inode->u.shmem_i)
79  
80  #endif
81 diff -rupN --exclude='ide*' linux-2.4.20.orig/mm/shmem.c linux-2.4.20/mm/shmem.c
82 --- linux-2.4.20.orig/mm/shmem.c        2002-11-29 01:53:15.000000000 +0200
83 +++ linux-2.4.20/mm/shmem.c     2004-02-10 18:44:05.000000000 +0200
84 @@ -27,6 +27,8 @@
85  #include <linux/string.h>
86  #include <linux/locks.h>
87  #include <linux/smp_lock.h>
88 +#include <linux/slab.h>
89 +#include <linux/xattr.h>
90  
91  #include <asm/uaccess.h>
92  
93 @@ -58,6 +60,344 @@ atomic_t shmem_nrpages = ATOMIC_INIT(0);
94  
95  static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long);
96  
97 +#ifdef CONFIG_TMPFS
98 +static struct inode_operations shmem_symlink_inode_operations;
99 +static struct inode_operations shmem_symlink_inline_operations;
100 +#endif
101 +
102 +#ifdef CONFIG_TMPFS_XATTR
103 +#define xattr_name(xattr)                      \
104 +       ((char *)xattr->entity)
105 +
106 +#define xattr_value(xattr)                             \
107 +       ((void *)xattr->entity + xattr->namelen + 1)
108 +
109 +/* allocates memory for new xattr with name length of @namelen and value size of
110 + * @valuelen. */
111 +static struct shmem_xattr *
112 +shmem_xattr_alloc(u8 namelen, u16 valuelen)
113 +{
114 +       u16 size;
115 +        struct shmem_xattr *xattr;
116 +                                                                                      
117 +       size = namelen + 1 + valuelen;
118 +
119 +        if (!(xattr = kmalloc(sizeof(*xattr), GFP_KERNEL)))
120 +                return NULL;
121 +
122 +       if (!(xattr->entity = kmalloc(size, GFP_KERNEL))) {
123 +               kfree(xattr);
124 +               return NULL;
125 +       }
126 +                                                                                      
127 +        xattr->namelen = namelen;
128 +        xattr->valuelen = valuelen;
129 +        return xattr;
130 +}
131 +
132 +/* reallocs passed @xattr with new @value. */
133 +static int
134 +shmem_xattr_realloc(struct shmem_xattr *xattr, u16 valuelen)
135 +{
136 +        if (xattr->valuelen != valuelen) {
137 +               u16 new_size;
138 +                void *entity;
139 +
140 +               /* allocating new entity. */
141 +               new_size = xattr->namelen + 1 + valuelen;
142 +                                                                                      
143 +               if (!(entity = kmalloc(new_size, GFP_KERNEL)))
144 +                        return -ENOMEM;
145 +
146 +               /* copying old name to new entity.*/
147 +               memcpy(entity, xattr->entity, xattr->namelen);
148 +               *((char *)(entity + xattr->namelen)) = '\0';
149 +
150 +               /* finishing the change.*/
151 +                kfree(xattr->entity);
152 +               xattr->entity = entity;
153 +                xattr->valuelen = valuelen;
154 +        }
155 +
156 +        return 0;
157 +}
158 +
159 +/* assigns @name and @value to passed @xattr. */
160 +static int
161 +shmem_xattr_assign(struct shmem_xattr *xattr,
162 +                  const char *name, const void *value)
163 +{
164 +       if (name) {
165 +               if (xattr->namelen != strlen(name))
166 +                       return -EINVAL;
167 +               
168 +               memcpy(xattr->entity, name, xattr->namelen);
169 +               *((char *)(xattr->entity + xattr->namelen)) = '\0';
170 +       }
171 +
172 +       if (value) {
173 +               memcpy(xattr_value(xattr),
174 +                      value, xattr->valuelen);
175 +       }
176 +
177 +        return 0;
178 +}
179 +
180 +/* frees passed @xattr. */
181 +static void
182 +shmem_xattr_free(struct shmem_xattr *xattr)
183 +{
184 +        kfree(xattr->entity);
185 +        kfree(xattr);
186 +}
187 +
188 +/* lookups passed @name inside @inode's xattr list. */
189 +struct shmem_xattr *
190 +shmem_xattr_find(struct inode *inode, const char *name)
191 +{
192 +       u8 namelen;
193 +        struct list_head *p;
194 +        struct shmem_xattr *xattr;
195 +        struct shmem_inode_info *info;
196 +
197 +        info = SHMEM_I(inode);
198 +       namelen = strlen(name);
199 +
200 +        list_for_each(p, &info->xattrs) {
201 +                xattr = list_entry(p, struct shmem_xattr, list);
202 +
203 +                if (xattr->namelen == namelen &&
204 +                    !memcmp(xattr->entity, name, namelen))
205 +                {
206 +                        return xattr;
207 +                }
208 +        }
209 +
210 +        return NULL;
211 +}
212 +
213 +/* allocates new xattr and fills it with passed value, name, etc. */
214 +ssize_t
215 +shmem_xattr_set(struct inode *inode, const char *name,
216 +               const void *value, u16 valuelen, int flags)
217 +{
218 +       ssize_t error;
219 +        struct shmem_xattr *xattr;
220 +       struct shmem_inode_info *info;
221 +
222 +        xattr = shmem_xattr_find(inode, name);
223 +
224 +        if (xattr) {
225 +                if (flags & XATTR_CREATE)
226 +                        return -EEXIST;
227 +
228 +                if ((error = shmem_xattr_realloc(xattr, valuelen)))
229 +                        return error;
230 +
231 +               if ((error = shmem_xattr_assign(xattr, NULL, value)))
232 +                       return error;
233 +        } else {
234 +                info = SHMEM_I(inode);
235 +
236 +               if (flags & XATTR_REPLACE)
237 +                        return -ENODATA;
238 +
239 +               if (!(xattr = shmem_xattr_alloc(strlen(name), valuelen)))
240 +                       return -ENOMEM;
241 +
242 +               if ((error = shmem_xattr_assign(xattr, name, value)))
243 +                       return error;
244 +               
245 +                list_add(&xattr->list, info->xtail);
246 +               info->xtail = &xattr->list;
247 +        }
248 +       
249 +        return 0;
250 +}
251 +
252 +/* fills passed @value by attribute value found by @name. */
253 +ssize_t
254 +shmem_xattr_get(struct inode *inode, const char *name,
255 +               void *value, size_t valuelen)
256 +{
257 +        struct shmem_xattr *xattr;
258 +
259 +        if (!(xattr = shmem_xattr_find(inode, name)))
260 +                return -ENODATA;
261 +
262 +        /* handling value size guess request */
263 +        if (valuelen == 0 || value == NULL)
264 +                return xattr->valuelen;
265 +
266 +        if (xattr->valuelen > valuelen)
267 +                return -ERANGE;
268 +
269 +        memcpy(value, xattr_value(xattr),
270 +              xattr->valuelen);
271 +       
272 +        return xattr->valuelen;
273 +}
274 +
275 +/* deletes passed @xattr from inode xattr list and frees it. */
276 +int
277 +shmem_xattr_delete(struct inode *inode, struct shmem_xattr *xattr)
278 +{
279 +       struct shmem_inode_info *info;
280 +
281 +       info = SHMEM_I(inode);
282 +       
283 +       if (&xattr->list == info->xtail)
284 +               info->xtail = xattr->list.prev;
285 +       
286 +       list_del(&xattr->list);
287 +       shmem_xattr_free(xattr);
288 +
289 +       return 0;
290 +}
291 +
292 +/* removes attribute found by passed @name. */
293 +int
294 +shmem_xattr_remove(struct inode *inode, const char *name)
295 +{
296 +        struct shmem_xattr *xattr;
297 +
298 +        if (!(xattr = shmem_xattr_find(inode, name)))
299 +                return -ENODATA;
300 +
301 +       return shmem_xattr_delete(inode, xattr);
302 +}
303 +
304 +static int
305 +shmem_xattr_can_read(struct inode *inode, const char *name)
306 +{
307 +       /* check for inlined symlinks. They store path inside inode info and
308 +        * thus, cannot be used for access xattrs. */
309 +       if (S_ISLNK(inode->i_mode) &&
310 +           inode->i_op == &shmem_symlink_inline_operations)
311 +       {
312 +                return -EPERM;
313 +       }
314 +       
315 +       return permission(inode, MAY_READ);
316 +}
317 +                                                                                      
318 +static int
319 +shmem_xattr_can_write(struct inode *inode, const char *name)
320 +{
321 +        if (IS_RDONLY(inode))
322 +                return -EROFS;
323 +                                                                                      
324 +        if (IS_IMMUTABLE(inode) || IS_APPEND(inode) ||
325 +           S_ISLNK(inode->i_mode))
326 +       {
327 +                return -EPERM;
328 +       }
329 +                                                                                      
330 +        if ((!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) ||
331 +           inode->i_mode & S_ISVTX)
332 +       {
333 +                return -EPERM;
334 +       }
335 +                                                                                      
336 +        return permission(inode, MAY_WRITE);
337 +}
338 +
339 +/* fills passed @value with data of attribute @name from @dentry->d_inode
340 + * attribute list. */
341 +static ssize_t
342 +shmem_getxattr(struct dentry *dentry, const char *name,
343 +               void *value, size_t valuelen)
344 +{
345 +        int error;
346 +        struct inode *inode = dentry->d_inode;
347 +
348 +       if (name == NULL)
349 +               return -EINVAL;
350 +                                                                                      
351 +        if ((error = shmem_xattr_can_read(inode, name)))
352 +                return error;
353 +
354 +       return shmem_xattr_get(inode, name,
355 +                              value, valuelen);
356 +                                                                                      
357 +}
358 +
359 +/* updates attribute with @name inside @dentry->d_inode attributes list (if
360 + * any), or creates new attribute with name @name and value @value and put it to
361 + * inode attributes list.*/
362 +static int
363 +shmem_setxattr(struct dentry *dentry, const char *name,
364 +               void *value, size_t valuelen, int flags)
365 +{
366 +        int error;
367 +        struct inode *inode = dentry->d_inode;
368 +                                                                                      
369 +       if (name == NULL)
370 +               return -EINVAL;
371 +       
372 +        if ((error = shmem_xattr_can_write(inode, name)))
373 +                return error;
374 +                                                                                      
375 +        if (value == NULL) {
376 +                value = "";
377 +                valuelen = 0;
378 +        }
379 +                                                                                      
380 +        return shmem_xattr_set(inode, name, value,
381 +                              valuelen, flags);
382 +}
383 +
384 +/* removes attribute with passed @name from @dentry->d_inode attributes list. */
385 +static int
386 +shmem_removexattr(struct dentry *dentry, const char *name)
387 +{
388 +        int error;
389 +        struct inode *inode = dentry->d_inode;
390 +                                                                                      
391 +       if (name == NULL)
392 +               return -EINVAL;
393 +
394 +        if ((error = shmem_xattr_can_write(inode, name)))
395 +                return error;
396 +                                                                                      
397 +        return shmem_xattr_remove(inode, name);
398 +}
399 +
400 +/* fills passed @data with list of @dentry->d_inode attributes. Returns size of
401 + * actuall data put to @data. */
402 +static ssize_t
403 +shmem_listxattr(struct dentry *dentry, char *data, size_t buf_size)
404 +{
405 +        ssize_t size = 0;
406 +        struct list_head *p;
407 +        struct shmem_xattr *xattr;
408 +        struct shmem_inode_info *info;
409 +        struct inode *inode = dentry->d_inode;
410 +
411 +        info = SHMEM_I(inode);
412 +
413 +        list_for_each(p, &info->xattrs) {
414 +                xattr = list_entry(p, struct shmem_xattr, list);
415 +                size += xattr->namelen + 1;
416 +        }
417 +
418 +        /* handling data size guess request. */
419 +        if (buf_size == 0 || data == NULL)
420 +                return size;
421 +
422 +        if (size > buf_size)
423 +                return -ERANGE;
424 +
425 +        list_for_each(p, &info->xattrs) {
426 +                xattr = list_entry(p, struct shmem_xattr, list);
427 +                memcpy(data, xattr->entity, xattr->namelen + 1);
428 +                data += xattr->namelen + 1;
429 +        }
430 +
431 +        return size;
432 +}
433 +#endif
434 +
435  /*
436   * shmem_recalc_inode - recalculate the size of an inode
437   *
438 @@ -359,6 +699,11 @@ static void shmem_truncate (struct inode
439  
440  static void shmem_delete_inode(struct inode * inode)
441  {
442 +#ifdef CONFIG_TMPFS_XATTR
443 +       struct list_head *tmp, *p;
444 +       struct shmem_xattr *xattr;
445 +       struct shmem_inode_info * info = SHMEM_I(inode);
446 +#endif
447         struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
448  
449         if (inode->i_op->truncate == shmem_truncate) {
450 @@ -371,6 +716,12 @@ static void shmem_delete_inode(struct in
451         spin_lock (&sbinfo->stat_lock);
452         sbinfo->free_inodes++;
453         spin_unlock (&sbinfo->stat_lock);
454 +#ifdef CONFIG_TMPFS_XATTR
455 +        list_for_each_safe(p, tmp, &info->xattrs) {
456 +                xattr = list_entry(p, struct shmem_xattr, list);
457 +               shmem_xattr_delete(inode, xattr);
458 +        }
459 +#endif
460         clear_inode(inode);
461  }
462  
463 @@ -634,7 +985,7 @@ wait_retry:
464         goto repeat;
465  }
466  
467 -static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
468 +int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
469  {
470         struct shmem_inode_info *info = SHMEM_I(inode);
471         int error;
472 @@ -727,6 +1078,11 @@ struct inode *shmem_get_inode(struct sup
473                 info->inode = inode;
474                 spin_lock_init (&info->lock);
475                 sema_init (&info->sem, 1);
476 +
477 +#ifdef CONFIG_TMPFS_XATTR
478 +               INIT_LIST_HEAD(&info->xattrs);
479 +               info->xtail = &info->xattrs;
480 +#endif
481                 switch (mode & S_IFMT) {
482                 default:
483                         init_special_inode(inode, mode, dev);
484 @@ -777,10 +1133,6 @@ out:
485  }
486  
487  #ifdef CONFIG_TMPFS
488 -
489 -static struct inode_operations shmem_symlink_inode_operations;
490 -static struct inode_operations shmem_symlink_inline_operations;
491 -
492  static ssize_t
493  shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
494  {
495 @@ -1250,6 +1602,12 @@ static struct inode_operations shmem_sym
496         truncate:       shmem_truncate,
497         readlink:       shmem_readlink,
498         follow_link:    shmem_follow_link,
499 +#ifdef CONFIG_TMPFS_XATTR
500 +       setxattr:       shmem_setxattr,
501 +       getxattr:       shmem_getxattr,
502 +       listxattr:      shmem_listxattr,
503 +       removexattr:    shmem_removexattr,
504 +#endif
505  };
506  
507  static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long * blocks, unsigned long *inodes)
508 @@ -1398,6 +1756,12 @@ static struct file_operations shmem_file
509  
510  static struct inode_operations shmem_inode_operations = {
511         truncate:       shmem_truncate,
512 +#ifdef CONFIG_TMPFS_XATTR
513 +       setxattr:       shmem_setxattr,
514 +       getxattr:       shmem_getxattr,
515 +       listxattr:      shmem_listxattr,
516 +       removexattr:    shmem_removexattr,
517 +#endif
518  };
519  
520  static struct inode_operations shmem_dir_inode_operations = {
521 @@ -1411,6 +1775,12 @@ static struct inode_operations shmem_dir
522         rmdir:          shmem_rmdir,
523         mknod:          shmem_mknod,
524         rename:         shmem_rename,
525 +#ifdef CONFIG_TMPFS_XATTR
526 +       setxattr:       shmem_setxattr,
527 +       getxattr:       shmem_getxattr,
528 +       listxattr:      shmem_listxattr,
529 +       removexattr:    shmem_removexattr,
530 +#endif
531  #endif
532  };
533  
534 @@ -1557,3 +1927,9 @@ int shmem_zero_setup(struct vm_area_stru
535  }
536  
537  EXPORT_SYMBOL(shmem_file_setup);
538 +EXPORT_SYMBOL(shmem_getpage);
539 +EXPORT_SYMBOL(shmem_xattr_find);
540 +EXPORT_SYMBOL(shmem_xattr_set);
541 +EXPORT_SYMBOL(shmem_xattr_get);
542 +EXPORT_SYMBOL(shmem_xattr_delete);
543 +EXPORT_SYMBOL(shmem_xattr_remove);