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