Merge branch 'fixes' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux-2.6-microblaze.git] / fs / f2fs / xattr.c
index 7c65540..ec8961e 100644 (file)
@@ -217,12 +217,12 @@ static struct f2fs_xattr_entry *__find_xattr(void *base_addr, int index,
        return entry;
 }
 
-static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr,
-                                       void **last_addr, int index,
-                                       size_t len, const char *name)
+static struct f2fs_xattr_entry *__find_inline_xattr(struct inode *inode,
+                               void *base_addr, void **last_addr, int index,
+                               size_t len, const char *name)
 {
        struct f2fs_xattr_entry *entry;
-       unsigned int inline_size = F2FS_INLINE_XATTR_ADDRS << 2;
+       unsigned int inline_size = inline_xattr_size(inode);
 
        list_for_each_xattr(entry, base_addr) {
                if ((void *)entry + sizeof(__u32) > base_addr + inline_size ||
@@ -241,12 +241,54 @@ static struct f2fs_xattr_entry *__find_inline_xattr(void *base_addr,
        return entry;
 }
 
+static int read_inline_xattr(struct inode *inode, struct page *ipage,
+                                                       void *txattr_addr)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       unsigned int inline_size = inline_xattr_size(inode);
+       struct page *page = NULL;
+       void *inline_addr;
+
+       if (ipage) {
+               inline_addr = inline_xattr_addr(inode, ipage);
+       } else {
+               page = get_node_page(sbi, inode->i_ino);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
+               inline_addr = inline_xattr_addr(inode, page);
+       }
+       memcpy(txattr_addr, inline_addr, inline_size);
+       f2fs_put_page(page, 1);
+
+       return 0;
+}
+
+static int read_xattr_block(struct inode *inode, void *txattr_addr)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       nid_t xnid = F2FS_I(inode)->i_xattr_nid;
+       unsigned int inline_size = inline_xattr_size(inode);
+       struct page *xpage;
+       void *xattr_addr;
+
+       /* The inode already has an extended attribute block. */
+       xpage = get_node_page(sbi, xnid);
+       if (IS_ERR(xpage))
+               return PTR_ERR(xpage);
+
+       xattr_addr = page_address(xpage);
+       memcpy(txattr_addr + inline_size, xattr_addr, VALID_XATTR_BLOCK_SIZE);
+       f2fs_put_page(xpage, 1);
+
+       return 0;
+}
+
 static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
                                unsigned int index, unsigned int len,
                                const char *name, struct f2fs_xattr_entry **xe,
                                void **base_addr)
 {
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        void *cur_addr, *txattr_addr, *last_addr = NULL;
        nid_t xnid = F2FS_I(inode)->i_xattr_nid;
        unsigned int size = xnid ? VALID_XATTR_BLOCK_SIZE : 0;
@@ -263,23 +305,11 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
 
        /* read from inline xattr */
        if (inline_size) {
-               struct page *page = NULL;
-               void *inline_addr;
-
-               if (ipage) {
-                       inline_addr = inline_xattr_addr(ipage);
-               } else {
-                       page = get_node_page(sbi, inode->i_ino);
-                       if (IS_ERR(page)) {
-                               err = PTR_ERR(page);
-                               goto out;
-                       }
-                       inline_addr = inline_xattr_addr(page);
-               }
-               memcpy(txattr_addr, inline_addr, inline_size);
-               f2fs_put_page(page, 1);
+               err = read_inline_xattr(inode, ipage, txattr_addr);
+               if (err)
+                       goto out;
 
-               *xe = __find_inline_xattr(txattr_addr, &last_addr,
+               *xe = __find_inline_xattr(inode, txattr_addr, &last_addr,
                                                index, len, name);
                if (*xe)
                        goto check;
@@ -287,19 +317,9 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
 
        /* read from xattr node block */
        if (xnid) {
-               struct page *xpage;
-               void *xattr_addr;
-
-               /* The inode already has an extended attribute block. */
-               xpage = get_node_page(sbi, xnid);
-               if (IS_ERR(xpage)) {
-                       err = PTR_ERR(xpage);
+               err = read_xattr_block(inode, txattr_addr);
+               if (err)
                        goto out;
-               }
-
-               xattr_addr = page_address(xpage);
-               memcpy(txattr_addr + inline_size, xattr_addr, size);
-               f2fs_put_page(xpage, 1);
        }
 
        if (last_addr)
@@ -324,7 +344,6 @@ out:
 static int read_all_xattrs(struct inode *inode, struct page *ipage,
                                                        void **base_addr)
 {
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct f2fs_xattr_header *header;
        nid_t xnid = F2FS_I(inode)->i_xattr_nid;
        unsigned int size = VALID_XATTR_BLOCK_SIZE;
@@ -339,38 +358,16 @@ static int read_all_xattrs(struct inode *inode, struct page *ipage,
 
        /* read from inline xattr */
        if (inline_size) {
-               struct page *page = NULL;
-               void *inline_addr;
-
-               if (ipage) {
-                       inline_addr = inline_xattr_addr(ipage);
-               } else {
-                       page = get_node_page(sbi, inode->i_ino);
-                       if (IS_ERR(page)) {
-                               err = PTR_ERR(page);
-                               goto fail;
-                       }
-                       inline_addr = inline_xattr_addr(page);
-               }
-               memcpy(txattr_addr, inline_addr, inline_size);
-               f2fs_put_page(page, 1);
+               err = read_inline_xattr(inode, ipage, txattr_addr);
+               if (err)
+                       goto fail;
        }
 
        /* read from xattr node block */
        if (xnid) {
-               struct page *xpage;
-               void *xattr_addr;
-
-               /* The inode already has an extended attribute block. */
-               xpage = get_node_page(sbi, xnid);
-               if (IS_ERR(xpage)) {
-                       err = PTR_ERR(xpage);
+               err = read_xattr_block(inode, txattr_addr);
+               if (err)
                        goto fail;
-               }
-
-               xattr_addr = page_address(xpage);
-               memcpy(txattr_addr + inline_size, xattr_addr, size);
-               f2fs_put_page(xpage, 1);
        }
 
        header = XATTR_HDR(txattr_addr);
@@ -392,10 +389,12 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        size_t inline_size = inline_xattr_size(inode);
+       struct page *in_page = NULL;
        void *xattr_addr;
+       void *inline_addr = NULL;
        struct page *xpage;
        nid_t new_nid = 0;
-       int err;
+       int err = 0;
 
        if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
                if (!alloc_nid(sbi, &new_nid))
@@ -403,30 +402,30 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
 
        /* write to inline xattr */
        if (inline_size) {
-               struct page *page = NULL;
-               void *inline_addr;
-
                if (ipage) {
-                       inline_addr = inline_xattr_addr(ipage);
-                       f2fs_wait_on_page_writeback(ipage, NODE, true);
-                       set_page_dirty(ipage);
+                       inline_addr = inline_xattr_addr(inode, ipage);
                } else {
-                       page = get_node_page(sbi, inode->i_ino);
-                       if (IS_ERR(page)) {
+                       in_page = get_node_page(sbi, inode->i_ino);
+                       if (IS_ERR(in_page)) {
                                alloc_nid_failed(sbi, new_nid);
-                               return PTR_ERR(page);
+                               return PTR_ERR(in_page);
                        }
-                       inline_addr = inline_xattr_addr(page);
-                       f2fs_wait_on_page_writeback(page, NODE, true);
+                       inline_addr = inline_xattr_addr(inode, in_page);
                }
-               memcpy(inline_addr, txattr_addr, inline_size);
-               f2fs_put_page(page, 1);
 
+               f2fs_wait_on_page_writeback(ipage ? ipage : in_page,
+                                                       NODE, true);
                /* no need to use xattr node block */
                if (hsize <= inline_size) {
-                       err = truncate_xattr_node(inode, ipage);
+                       err = truncate_xattr_node(inode);
                        alloc_nid_failed(sbi, new_nid);
-                       return err;
+                       if (err) {
+                               f2fs_put_page(in_page, 1);
+                               return err;
+                       }
+                       memcpy(inline_addr, txattr_addr, inline_size);
+                       set_page_dirty(ipage ? ipage : in_page);
+                       goto in_page_out;
                }
        }
 
@@ -435,7 +434,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
                if (IS_ERR(xpage)) {
                        alloc_nid_failed(sbi, new_nid);
-                       return PTR_ERR(xpage);
+                       goto in_page_out;
                }
                f2fs_bug_on(sbi, new_nid);
                f2fs_wait_on_page_writeback(xpage, NODE, true);
@@ -445,17 +444,24 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
                xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
                if (IS_ERR(xpage)) {
                        alloc_nid_failed(sbi, new_nid);
-                       return PTR_ERR(xpage);
+                       goto in_page_out;
                }
                alloc_nid_done(sbi, new_nid);
        }
-
        xattr_addr = page_address(xpage);
+
+       if (inline_size)
+               memcpy(inline_addr, txattr_addr, inline_size);
        memcpy(xattr_addr, txattr_addr + inline_size, VALID_XATTR_BLOCK_SIZE);
+
+       if (inline_size)
+               set_page_dirty(ipage ? ipage : in_page);
        set_page_dirty(xpage);
-       f2fs_put_page(xpage, 1);
 
-       return 0;
+       f2fs_put_page(xpage, 1);
+in_page_out:
+       f2fs_put_page(in_page, 1);
+       return err;
 }
 
 int f2fs_getxattr(struct inode *inode, int index, const char *name,
@@ -681,6 +687,10 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        int err;
 
+       err = dquot_initialize(inode);
+       if (err)
+               return err;
+
        /* this case is only from init_inode_metadata */
        if (ipage)
                return __f2fs_setxattr(inode, index, name, value,