]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/ocfs2/xattr.c
udp: introduce struct udp_table and multiple spinlocks
[mv-sheeva.git] / fs / ocfs2 / xattr.c
index e21a1a8b42578959a459ac071ca4d38ac31c1858..802c41492214ca928cd30448deb972bbbbe6a05f 100644 (file)
@@ -37,6 +37,9 @@
 #include <linux/writeback.h>
 #include <linux/falloc.h>
 #include <linux/sort.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
 
 #define MLOG_MASK_PREFIX ML_XATTR
 #include <cluster/masklog.h>
@@ -134,32 +137,24 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
 static int ocfs2_delete_xattr_index_block(struct inode *inode,
                                          struct buffer_head *xb_bh);
 
-static inline struct xattr_handler *ocfs2_xattr_handler(int name_index)
+static inline const char *ocfs2_xattr_prefix(int name_index)
 {
        struct xattr_handler *handler = NULL;
 
        if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
                handler = ocfs2_xattr_handler_map[name_index];
 
-       return handler;
+       return handler ? handler->prefix : NULL;
 }
 
 static u32 ocfs2_xattr_name_hash(struct inode *inode,
-                                char *prefix,
-                                int prefix_len,
-                                char *name,
+                                const char *name,
                                 int name_len)
 {
        /* Get hash value of uuid from super block */
        u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
        int i;
 
-       /* hash extended attribute prefix */
-       for (i = 0; i < prefix_len; i++) {
-               hash = (hash << OCFS2_HASH_SHIFT) ^
-                      (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
-                      *prefix++;
-       }
        /* hash extended attribute name */
        for (i = 0; i < name_len; i++) {
                hash = (hash << OCFS2_HASH_SHIFT) ^
@@ -180,14 +175,9 @@ static void ocfs2_xattr_hash_entry(struct inode *inode,
                                   struct ocfs2_xattr_entry *entry)
 {
        u32 hash = 0;
-       struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
-       char *prefix = handler->prefix;
        char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
-       int prefix_len = strlen(handler->prefix);
 
-       hash = ocfs2_xattr_name_hash(inode, prefix, prefix_len, name,
-                                    entry->xe_name_len);
+       hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len);
        entry->xe_name_hash = cpu_to_le32(hash);
 
        return;
@@ -462,33 +452,56 @@ static int ocfs2_xattr_value_truncate(struct inode *inode,
        return ret;
 }
 
+static int ocfs2_xattr_list_entry(char *buffer, size_t size,
+                                 size_t *result, const char *prefix,
+                                 const char *name, int name_len)
+{
+       char *p = buffer + *result;
+       int prefix_len = strlen(prefix);
+       int total_len = prefix_len + name_len + 1;
+
+       *result += total_len;
+
+       /* we are just looking for how big our buffer needs to be */
+       if (!size)
+               return 0;
+
+       if (*result > size)
+               return -ERANGE;
+
+       memcpy(p, prefix, prefix_len);
+       memcpy(p + prefix_len, name, name_len);
+       p[prefix_len + name_len] = '\0';
+
+       return 0;
+}
+
 static int ocfs2_xattr_list_entries(struct inode *inode,
                                    struct ocfs2_xattr_header *header,
                                    char *buffer, size_t buffer_size)
 {
-       size_t rest = buffer_size;
-       int i;
+       size_t result = 0;
+       int i, type, ret;
+       const char *prefix, *name;
 
        for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
-               struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
-
-               if (handler) {
-                       size_t size = handler->list(inode, buffer, rest,
-                                       ((char *)header +
-                                       le16_to_cpu(entry->xe_name_offset)),
-                                       entry->xe_name_len);
-                       if (buffer) {
-                               if (size > rest)
-                                       return -ERANGE;
-                               buffer += size;
-                       }
-                       rest -= size;
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
+
+               if (prefix) {
+                       name = (const char *)header +
+                               le16_to_cpu(entry->xe_name_offset);
+
+                       ret = ocfs2_xattr_list_entry(buffer, buffer_size,
+                                                    &result, prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               return ret;
                }
        }
 
-       return buffer_size - rest;
+       return result;
 }
 
 static int ocfs2_xattr_ibody_list(struct inode *inode,
@@ -524,9 +537,7 @@ static int ocfs2_xattr_block_list(struct inode *inode,
        if (!di->i_xattr_loc)
                return ret;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -659,8 +670,7 @@ static int ocfs2_xattr_get_value_outside(struct inode *inode,
                blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
                /* Copy ocfs2_xattr_value */
                for (i = 0; i < num_clusters * bpc; i++, blkno++) {
-                       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                              &bh, OCFS2_BH_CACHED, inode);
+                       ret = ocfs2_read_block(inode, blkno, &bh);
                        if (ret) {
                                mlog_errno(ret);
                                goto out;
@@ -751,9 +761,7 @@ static int ocfs2_xattr_block_get(struct inode *inode,
 
        memset(&xs->bucket, 0, sizeof(xs->bucket));
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -909,8 +917,7 @@ static int __ocfs2_xattr_set_value_outside(struct inode *inode,
                blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
 
                for (i = 0; i < num_clusters * bpc; i++, blkno++) {
-                       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                              &bh, OCFS2_BH_CACHED, inode);
+                       ret = ocfs2_read_block(inode, blkno, &bh);
                        if (ret) {
                                mlog_errno(ret);
                                goto out_commit;
@@ -1501,8 +1508,7 @@ static int ocfs2_xattr_free_block(struct inode *inode,
        u64 blk, bg_blkno;
        u16 bit;
 
-       ret = ocfs2_read_block(osb, block, &blk_bh,
-                              OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, block, &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -1760,9 +1766,7 @@ static int ocfs2_xattr_block_find(struct inode *inode,
        if (!di->i_xattr_loc)
                return ret;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                              le64_to_cpu(di->i_xattr_loc),
-                              &blk_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
        if (ret < 0) {
                mlog_errno(ret);
                return ret;
@@ -2090,18 +2094,6 @@ cleanup:
        return ret;
 }
 
-static inline u32 ocfs2_xattr_hash_by_name(struct inode *inode,
-                                          int name_index,
-                                          const char *suffix_name)
-{
-       struct xattr_handler *handler = ocfs2_xattr_handler(name_index);
-       char *prefix = handler->prefix;
-       int prefix_len = strlen(handler->prefix);
-
-       return ocfs2_xattr_name_hash(inode, prefix, prefix_len,
-                                    (char *)suffix_name, strlen(suffix_name));
-}
-
 /*
  * Find the xattr extent rec which may contains name_hash.
  * e_cpos will be the first name hash of the xattr rec.
@@ -2215,9 +2207,8 @@ static int ocfs2_find_xe_in_bucket(struct inode *inode,
                        break;
                }
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
-                                      header_bh->b_blocknr + block_off,
-                                      &name_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off,
+                                      &name_bh);
                if (ret) {
                        mlog_errno(ret);
                        break;
@@ -2268,8 +2259,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
        u32 last_hash;
        u64 blkno;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno,
-                              &bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, p_blkno, &bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -2285,8 +2275,7 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
 
                blkno = p_blkno + bucket * blk_per_bucket;
 
-               ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
-                                      &bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, blkno, &bh);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2358,10 +2347,9 @@ static int ocfs2_xattr_bucket_find(struct inode *inode,
                 * If we have found the xattr enty, read all the blocks in
                 * this bucket.
                 */
-               ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-                                       xs->bucket.bhs[0]->b_blocknr + 1,
+               ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2392,7 +2380,7 @@ static int ocfs2_xattr_index_block_find(struct inode *inode,
        struct ocfs2_extent_list *el = &xb_root->xt_list;
        u64 p_blkno = 0;
        u32 first_hash, num_clusters = 0;
-       u32 name_hash = ocfs2_xattr_hash_by_name(inode, name_index, name);
+       u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
 
        if (le16_to_cpu(el->l_next_free_rec) == 0)
                return -ENODATA;
@@ -2437,9 +2425,8 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
             clusters, blkno);
 
        for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
-               ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
-                                       blkno, blk_per_bucket,
-                                       bucket.bhs, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket,
+                                       bucket.bhs, 0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -2478,6 +2465,7 @@ out:
 struct ocfs2_xattr_tree_list {
        char *buffer;
        size_t buffer_size;
+       size_t result;
 };
 
 static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
@@ -2503,17 +2491,17 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
                                   struct ocfs2_xattr_bucket *bucket,
                                   void *para)
 {
-       int ret = 0;
+       int ret = 0, type;
        struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
-       size_t size;
        int i, block_off, new_offset;
+       const char *prefix, *name;
 
        for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) {
                struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i];
-               struct xattr_handler *handler =
-                       ocfs2_xattr_handler(ocfs2_xattr_get_type(entry));
+               type = ocfs2_xattr_get_type(entry);
+               prefix = ocfs2_xattr_prefix(type);
 
-               if (handler) {
+               if (prefix) {
                        ret = ocfs2_xattr_bucket_get_name_value(inode,
                                                                bucket->xh,
                                                                i,
@@ -2521,16 +2509,16 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
                                                                &new_offset);
                        if (ret)
                                break;
-                       size = handler->list(inode, xl->buffer, xl->buffer_size,
-                                            bucket->bhs[block_off]->b_data +
-                                            new_offset,
-                                            entry->xe_name_len);
-                       if (xl->buffer) {
-                               if (size > xl->buffer_size)
-                                       return -ERANGE;
-                               xl->buffer += size;
-                       }
-                       xl->buffer_size -= size;
+
+                       name = (const char *)bucket->bhs[block_off]->b_data +
+                               new_offset;
+                       ret = ocfs2_xattr_list_entry(xl->buffer,
+                                                    xl->buffer_size,
+                                                    &xl->result,
+                                                    prefix, name,
+                                                    entry->xe_name_len);
+                       if (ret)
+                               break;
                }
        }
 
@@ -2549,6 +2537,7 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
        struct ocfs2_xattr_tree_list xl = {
                .buffer = buffer,
                .buffer_size = buffer_size,
+               .result = 0,
        };
 
        if (le16_to_cpu(el->l_next_free_rec) == 0)
@@ -2576,7 +2565,7 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
                name_hash = e_cpos - 1;
        }
 
-       ret = buffer_size - xl.buffer_size;
+       ret = xl.result;
 out:
        return ret;
 }
@@ -2702,10 +2691,10 @@ static int ocfs2_xattr_update_xattr_search(struct inode *inode,
 
        if (!xs->not_found) {
                if (OCFS2_XATTR_BUCKET_SIZE != blocksize) {
-                       ret = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
+                       ret = ocfs2_read_blocks(inode,
                                        xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                        if (ret) {
                                mlog_errno(ret);
                                return ret;
@@ -2899,7 +2888,6 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
        u64 blkno = bucket->bhs[0]->b_blocknr;
        u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
        u16 xh_free_start;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        size_t blocksize = inode->i_sb->s_blocksize;
        handle_t *handle;
        struct buffer_head **bhs;
@@ -2910,8 +2898,7 @@ static int ocfs2_defrag_xattr_bucket(struct inode *inode,
        if (!bhs)
                return -ENOMEM;
 
-       ret = ocfs2_read_blocks(osb, blkno, blk_per_bucket, bhs,
-                               OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0);
        if (ret)
                goto out;
 
@@ -3111,8 +3098,7 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
                        goto out;
                }
 
-               ret = ocfs2_read_block(osb, prev_blkno,
-                                      &old_bh, OCFS2_BH_CACHED, inode);
+               ret = ocfs2_read_block(inode, prev_blkno, &old_bh);
                if (ret < 0) {
                        mlog_errno(ret);
                        brelse(new_bh);
@@ -3165,9 +3151,8 @@ static int ocfs2_read_xattr_bucket(struct inode *inode,
        u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
 
        if (!new)
-               return ocfs2_read_blocks(OCFS2_SB(inode->i_sb), blkno,
-                                        blk_per_bucket, bhs,
-                                        OCFS2_BH_CACHED, inode);
+               return ocfs2_read_blocks(inode, blkno,
+                                        blk_per_bucket, bhs, 0);
 
        for (i = 0; i < blk_per_bucket; i++) {
                bhs[i] = sb_getblk(inode->i_sb, blkno + i);
@@ -3482,7 +3467,7 @@ static int ocfs2_cp_xattr_cluster(struct inode *inode,
        ocfs2_journal_dirty(handle, first_bh);
 
        /* update the new bucket header. */
-       ret = ocfs2_read_block(osb, to_blk_start, &bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, to_blk_start, &bh);
        if (ret < 0) {
                mlog_errno(ret);
                goto out;
@@ -3869,8 +3854,7 @@ static int ocfs2_add_new_xattr_bucket(struct inode *inode,
                goto out;
        }
 
-       ret = ocfs2_read_block(osb, p_blkno,
-                              &first_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, p_blkno, &first_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4112,10 +4096,10 @@ static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
             (unsigned long long)xs->bucket.bhs[0]->b_blocknr);
 
        if (!xs->bucket.bhs[1]) {
-               ret = ocfs2_read_blocks(osb,
+               ret = ocfs2_read_blocks(inode,
                                        xs->bucket.bhs[0]->b_blocknr + 1,
                                        blk_per_bucket - 1, &xs->bucket.bhs[1],
-                                       OCFS2_BH_CACHED, inode);
+                                       0);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -4221,8 +4205,7 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
        BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
        value_blk += header_bh->b_blocknr;
 
-       ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), value_blk,
-                              &value_bh, OCFS2_BH_CACHED, inode);
+       ret = ocfs2_read_block(inode, value_blk, &value_bh);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -4432,8 +4415,8 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode,
        size_t value_len;
        char *val = (char *)xi->value;
        struct ocfs2_xattr_entry *xe = xs->here;
-       u32 name_hash = ocfs2_xattr_hash_by_name(inode,
-                                                xi->name_index, xi->name);
+       u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name,
+                                             strlen(xi->name));
 
        if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
                /*
@@ -4740,3 +4723,110 @@ static int ocfs2_delete_xattr_index_block(struct inode *inode,
 out:
        return ret;
 }
+
+/*
+ * 'trusted' attributes support
+ */
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
+                                      size_t list_size, const char *name,
+                                      size_t name_len)
+{
+       const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1;
+       const size_t total_len = prefix_len + name_len + 1;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
+                                  void *buffer, size_t size)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
+                                  const void *value, size_t size, int flags)
+{
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = ocfs2_xattr_trusted_list,
+       .get    = ocfs2_xattr_trusted_get,
+       .set    = ocfs2_xattr_trusted_set,
+};
+
+
+/*
+ * 'user' attributes support
+ */
+
+#define XATTR_USER_PREFIX "user."
+
+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
+                                   size_t list_size, const char *name,
+                                   size_t name_len)
+{
+       const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1;
+       const size_t total_len = prefix_len + name_len + 1;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return 0;
+
+       if (list && total_len <= list_size) {
+               memcpy(list, XATTR_USER_PREFIX, prefix_len);
+               memcpy(list + prefix_len, name, name_len);
+               list[prefix_len + name_len] = '\0';
+       }
+       return total_len;
+}
+
+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
+                               void *buffer, size_t size)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+       return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
+                              buffer, size);
+}
+
+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
+                               const void *value, size_t size, int flags)
+{
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (strcmp(name, "") == 0)
+               return -EINVAL;
+       if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+               return -EOPNOTSUPP;
+
+       return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
+                              size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .list   = ocfs2_xattr_user_list,
+       .get    = ocfs2_xattr_user_get,
+       .set    = ocfs2_xattr_user_set,
+};