diff options
Diffstat (limited to 'ANDROID_3.4.5/fs/ext2')
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/Kconfig | 55 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/Makefile | 13 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/acl.c | 406 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/acl.h | 77 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/balloc.c | 1555 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/dir.c | 733 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/ext2.h | 814 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/file.c | 107 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/ialloc.c | 677 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/inode.c | 1549 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/ioctl.c | 188 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/namei.c | 412 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/super.c | 1527 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/symlink.c | 54 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xattr.c | 1030 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xattr.h | 127 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xattr_security.c | 74 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xattr_trusted.c | 54 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xattr_user.c | 61 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xip.c | 90 | ||||
-rw-r--r-- | ANDROID_3.4.5/fs/ext2/xip.h | 26 |
21 files changed, 0 insertions, 9629 deletions
diff --git a/ANDROID_3.4.5/fs/ext2/Kconfig b/ANDROID_3.4.5/fs/ext2/Kconfig deleted file mode 100644 index 14a6780f..00000000 --- a/ANDROID_3.4.5/fs/ext2/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -config EXT2_FS - tristate "Second extended fs support" - help - Ext2 is a standard Linux file system for hard disks. - - To compile this file system support as a module, choose M here: the - module will be called ext2. - - If unsure, say Y. - -config EXT2_FS_XATTR - bool "Ext2 extended attributes" - depends on EXT2_FS - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - <http://acl.bestbits.at/> for details). - - If unsure, say N. - -config EXT2_FS_POSIX_ACL - bool "Ext2 POSIX Access Control Lists" - depends on EXT2_FS_XATTR - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website <http://acl.bestbits.at/>. - - If you don't know what Access Control Lists are, say N - -config EXT2_FS_SECURITY - bool "Ext2 Security Labels" - depends on EXT2_FS_XATTR - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the ext2 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. - -config EXT2_FS_XIP - bool "Ext2 execute in place support" - depends on EXT2_FS && MMU - help - Execute in place can be used on memory-backed block devices. If you - enable this option, you can select to mount block devices which are - capable of this feature without using the page cache. - - If you do not use a block device that is capable of using this, - or if unsure, say N. diff --git a/ANDROID_3.4.5/fs/ext2/Makefile b/ANDROID_3.4.5/fs/ext2/Makefile deleted file mode 100644 index f42af45c..00000000 --- a/ANDROID_3.4.5/fs/ext2/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for the linux ext2-filesystem routines. -# - -obj-$(CONFIG_EXT2_FS) += ext2.o - -ext2-y := balloc.o dir.o file.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o - -ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o -ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o -ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o -ext2-$(CONFIG_EXT2_FS_XIP) += xip.o diff --git a/ANDROID_3.4.5/fs/ext2/acl.c b/ANDROID_3.4.5/fs/ext2/acl.c deleted file mode 100644 index 35d6a3cf..00000000 --- a/ANDROID_3.4.5/fs/ext2/acl.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * linux/fs/ext2/acl.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> - */ - -#include <linux/capability.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" - -/* - * Convert from filesystem to in-memory representation. - */ -static struct posix_acl * -ext2_acl_from_disk(const void *value, size_t size) -{ - const char *end = (char *)value + size; - int n, count; - struct posix_acl *acl; - - if (!value) - return NULL; - if (size < sizeof(ext2_acl_header)) - return ERR_PTR(-EINVAL); - if (((ext2_acl_header *)value)->a_version != - cpu_to_le32(EXT2_ACL_VERSION)) - return ERR_PTR(-EINVAL); - value = (char *)value + sizeof(ext2_acl_header); - count = ext2_acl_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - acl = posix_acl_alloc(count, GFP_KERNEL); - if (!acl) - return ERR_PTR(-ENOMEM); - for (n=0; n < count; n++) { - ext2_acl_entry *entry = - (ext2_acl_entry *)value; - if ((char *)value + sizeof(ext2_acl_entry_short) > end) - goto fail; - acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); - acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); - switch(acl->a_entries[n].e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - value = (char *)value + - sizeof(ext2_acl_entry_short); - acl->a_entries[n].e_id = ACL_UNDEFINED_ID; - break; - - case ACL_USER: - case ACL_GROUP: - value = (char *)value + sizeof(ext2_acl_entry); - if ((char *)value > end) - goto fail; - acl->a_entries[n].e_id = - le32_to_cpu(entry->e_id); - break; - - default: - goto fail; - } - } - if (value != end) - goto fail; - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} - -/* - * Convert from in-memory to filesystem representation. - */ -static void * -ext2_acl_to_disk(const struct posix_acl *acl, size_t *size) -{ - ext2_acl_header *ext_acl; - char *e; - size_t n; - - *size = ext2_acl_size(acl->a_count); - ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count * - sizeof(ext2_acl_entry), GFP_KERNEL); - if (!ext_acl) - return ERR_PTR(-ENOMEM); - ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION); - e = (char *)ext_acl + sizeof(ext2_acl_header); - for (n=0; n < acl->a_count; n++) { - ext2_acl_entry *entry = (ext2_acl_entry *)e; - entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); - entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); - switch(acl->a_entries[n].e_tag) { - case ACL_USER: - case ACL_GROUP: - entry->e_id = - cpu_to_le32(acl->a_entries[n].e_id); - e += sizeof(ext2_acl_entry); - break; - - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - e += sizeof(ext2_acl_entry_short); - break; - - default: - goto fail; - } - } - return (char *)ext_acl; - -fail: - kfree(ext_acl); - return ERR_PTR(-EINVAL); -} - -/* - * inode->i_mutex: don't care - */ -struct posix_acl * -ext2_get_acl(struct inode *inode, int type) -{ - int name_index; - char *value = NULL; - struct posix_acl *acl; - int retval; - - if (!test_opt(inode->i_sb, POSIX_ACL)) - return NULL; - - acl = get_cached_acl(inode, type); - if (acl != ACL_NOT_CACHED) - return acl; - - switch (type) { - case ACL_TYPE_ACCESS: - name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; - break; - default: - BUG(); - } - retval = ext2_xattr_get(inode, name_index, "", NULL, 0); - if (retval > 0) { - value = kmalloc(retval, GFP_KERNEL); - if (!value) - return ERR_PTR(-ENOMEM); - retval = ext2_xattr_get(inode, name_index, "", value, retval); - } - if (retval > 0) - acl = ext2_acl_from_disk(value, retval); - else if (retval == -ENODATA || retval == -ENOSYS) - acl = NULL; - else - acl = ERR_PTR(retval); - kfree(value); - - if (!IS_ERR(acl)) - set_cached_acl(inode, type, acl); - - return acl; -} - -/* - * inode->i_mutex: down - */ -static int -ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) -{ - int name_index; - void *value = NULL; - size_t size = 0; - int error; - - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - - switch(type) { - case ACL_TYPE_ACCESS: - name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; - if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) - return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); - if (error == 0) - acl = NULL; - } - } - break; - - case ACL_TYPE_DEFAULT: - name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - break; - - default: - return -EINVAL; - } - if (acl) { - value = ext2_acl_to_disk(acl, &size); - if (IS_ERR(value)) - return (int)PTR_ERR(value); - } - - error = ext2_xattr_set(inode, name_index, "", value, size, 0); - - kfree(value); - if (!error) - set_cached_acl(inode, type, acl); - return error; -} - -/* - * Initialize the ACLs of a new inode. Called from ext2_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ -int -ext2_init_acl(struct inode *inode, struct inode *dir) -{ - struct posix_acl *acl = NULL; - int error = 0; - - if (!S_ISLNK(inode->i_mode)) { - if (test_opt(dir->i_sb, POSIX_ACL)) { - acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - if (!acl) - inode->i_mode &= ~current_umask(); - } - if (test_opt(inode->i_sb, POSIX_ACL) && acl) { - if (S_ISDIR(inode->i_mode)) { - error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl); - if (error) - goto cleanup; - } - error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode); - if (error < 0) - return error; - if (error > 0) { - /* This is an extended ACL */ - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - } - } -cleanup: - posix_acl_release(acl); - return error; -} - -/* - * Does chmod for an inode that may have an Access Control List. The - * inode->i_mode field must be updated to the desired value by the caller - * before calling this function. - * Returns 0 on success, or a negative error number. - * - * We change the ACL rather than storing some ACL entries in the file - * mode permission bits (which would be more efficient), because that - * would break once additional permissions (like ACL_APPEND, ACL_DELETE - * for directories) are added. There are no more bits available in the - * file mode. - * - * inode->i_mutex: down - */ -int -ext2_acl_chmod(struct inode *inode) -{ - struct posix_acl *acl; - int error; - - if (!test_opt(inode->i_sb, POSIX_ACL)) - return 0; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl) || !acl) - return PTR_ERR(acl); - error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); - if (error) - return error; - error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl); - posix_acl_release(acl); - return error; -} - -/* - * Extended attribut handlers - */ -static size_t -ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_ACCESS, size); - return size; -} - -static size_t -ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT); - - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return 0; - if (list && size <= list_size) - memcpy(list, POSIX_ACL_XATTR_DEFAULT, size); - return size; -} - -static int -ext2_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - - acl = ext2_get_acl(dentry->d_inode, type); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - error = posix_acl_to_xattr(acl, buffer, size); - posix_acl_release(acl); - - return error; -} - -static int -ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags, int type) -{ - struct posix_acl *acl; - int error; - - if (strcmp(name, "") != 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, POSIX_ACL)) - return -EOPNOTSUPP; - if (!inode_owner_or_capable(dentry->d_inode)) - return -EPERM; - - if (value) { - acl = posix_acl_from_xattr(value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - else if (acl) { - error = posix_acl_valid(acl); - if (error) - goto release_and_out; - } - } else - acl = NULL; - - error = ext2_set_acl(dentry->d_inode, type, acl); - -release_and_out: - posix_acl_release(acl); - return error; -} - -const struct xattr_handler ext2_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = ext2_xattr_list_acl_access, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; - -const struct xattr_handler ext2_xattr_acl_default_handler = { - .prefix = POSIX_ACL_XATTR_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = ext2_xattr_list_acl_default, - .get = ext2_xattr_get_acl, - .set = ext2_xattr_set_acl, -}; diff --git a/ANDROID_3.4.5/fs/ext2/acl.h b/ANDROID_3.4.5/fs/ext2/acl.h deleted file mode 100644 index 503bfb0e..00000000 --- a/ANDROID_3.4.5/fs/ext2/acl.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - File: fs/ext2/acl.h - - (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> -*/ - -#include <linux/posix_acl_xattr.h> - -#define EXT2_ACL_VERSION 0x0001 - -typedef struct { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -} ext2_acl_entry; - -typedef struct { - __le16 e_tag; - __le16 e_perm; -} ext2_acl_entry_short; - -typedef struct { - __le32 a_version; -} ext2_acl_header; - -static inline size_t ext2_acl_size(int count) -{ - if (count <= 4) { - return sizeof(ext2_acl_header) + - count * sizeof(ext2_acl_entry_short); - } else { - return sizeof(ext2_acl_header) + - 4 * sizeof(ext2_acl_entry_short) + - (count - 4) * sizeof(ext2_acl_entry); - } -} - -static inline int ext2_acl_count(size_t size) -{ - ssize_t s; - size -= sizeof(ext2_acl_header); - s = size - 4 * sizeof(ext2_acl_entry_short); - if (s < 0) { - if (size % sizeof(ext2_acl_entry_short)) - return -1; - return size / sizeof(ext2_acl_entry_short); - } else { - if (s % sizeof(ext2_acl_entry)) - return -1; - return s / sizeof(ext2_acl_entry) + 4; - } -} - -#ifdef CONFIG_EXT2_FS_POSIX_ACL - -/* acl.c */ -extern struct posix_acl *ext2_get_acl(struct inode *inode, int type); -extern int ext2_acl_chmod (struct inode *); -extern int ext2_init_acl (struct inode *, struct inode *); - -#else -#include <linux/sched.h> -#define ext2_get_acl NULL -#define ext2_set_acl NULL - -static inline int -ext2_acl_chmod (struct inode *inode) -{ - return 0; -} - -static inline int ext2_init_acl (struct inode *inode, struct inode *dir) -{ - return 0; -} -#endif - diff --git a/ANDROID_3.4.5/fs/ext2/balloc.c b/ANDROID_3.4.5/fs/ext2/balloc.c deleted file mode 100644 index a8cbe1bc..00000000 --- a/ANDROID_3.4.5/fs/ext2/balloc.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* - * linux/fs/ext2/balloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include "ext2.h" -#include <linux/quotaops.h> -#include <linux/slab.h> -#include <linux/sched.h> -#include <linux/buffer_head.h> -#include <linux/capability.h> - -/* - * balloc.c contains the blocks allocation and deallocation routines - */ - -/* - * The free blocks are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. The descriptors are loaded in memory - * when a file system is mounted (see ext2_fill_super). - */ - - -#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) - -struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, - unsigned int block_group, - struct buffer_head ** bh) -{ - unsigned long group_desc; - unsigned long offset; - struct ext2_group_desc * desc; - struct ext2_sb_info *sbi = EXT2_SB(sb); - - if (block_group >= sbi->s_groups_count) { - ext2_error (sb, "ext2_get_group_desc", - "block_group >= groups_count - " - "block_group = %d, groups_count = %lu", - block_group, sbi->s_groups_count); - - return NULL; - } - - group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(sb); - offset = block_group & (EXT2_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_group_desc[group_desc]) { - ext2_error (sb, "ext2_get_group_desc", - "Group descriptor not loaded - " - "block_group = %d, group_desc = %lu, desc = %lu", - block_group, group_desc, offset); - return NULL; - } - - desc = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data; - if (bh) - *bh = sbi->s_group_desc[group_desc]; - return desc + offset; -} - -static int ext2_valid_block_bitmap(struct super_block *sb, - struct ext2_group_desc *desc, - unsigned int block_group, - struct buffer_head *bh) -{ - ext2_grpblk_t offset; - ext2_grpblk_t next_zero_bit; - ext2_fsblk_t bitmap_blk; - ext2_fsblk_t group_first_block; - - group_first_block = ext2_group_first_block_no(sb, block_group); - - /* check whether block bitmap block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); - offset = bitmap_blk - group_first_block; - if (!ext2_test_bit(offset, bh->b_data)) - /* bad block bitmap */ - goto err_out; - - /* check whether the inode bitmap block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); - offset = bitmap_blk - group_first_block; - if (!ext2_test_bit(offset, bh->b_data)) - /* bad block bitmap */ - goto err_out; - - /* check whether the inode table block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_inode_table); - offset = bitmap_blk - group_first_block; - next_zero_bit = ext2_find_next_zero_bit(bh->b_data, - offset + EXT2_SB(sb)->s_itb_per_group, - offset); - if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group) - /* good bitmap for inode tables */ - return 1; - -err_out: - ext2_error(sb, __func__, - "Invalid block bitmap - " - "block_group = %d, block = %lu", - block_group, bitmap_blk); - return 0; -} - -/* - * Read the bitmap for a given block_group,and validate the - * bits for block/inode/inode tables are set in the bitmaps - * - * Return buffer_head on success or NULL in case of failure. - */ -static struct buffer_head * -read_block_bitmap(struct super_block *sb, unsigned int block_group) -{ - struct ext2_group_desc * desc; - struct buffer_head * bh = NULL; - ext2_fsblk_t bitmap_blk; - - desc = ext2_get_group_desc(sb, block_group, NULL); - if (!desc) - return NULL; - bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); - bh = sb_getblk(sb, bitmap_blk); - if (unlikely(!bh)) { - ext2_error(sb, __func__, - "Cannot read block bitmap - " - "block_group = %d, block_bitmap = %u", - block_group, le32_to_cpu(desc->bg_block_bitmap)); - return NULL; - } - if (likely(bh_uptodate_or_lock(bh))) - return bh; - - if (bh_submit_read(bh) < 0) { - brelse(bh); - ext2_error(sb, __func__, - "Cannot read block bitmap - " - "block_group = %d, block_bitmap = %u", - block_group, le32_to_cpu(desc->bg_block_bitmap)); - return NULL; - } - - ext2_valid_block_bitmap(sb, desc, block_group, bh); - /* - * file system mounted not to panic on error, continue with corrupt - * bitmap - */ - return bh; -} - -static void release_blocks(struct super_block *sb, int count) -{ - if (count) { - struct ext2_sb_info *sbi = EXT2_SB(sb); - - percpu_counter_add(&sbi->s_freeblocks_counter, count); - sb->s_dirt = 1; - } -} - -static void group_adjust_blocks(struct super_block *sb, int group_no, - struct ext2_group_desc *desc, struct buffer_head *bh, int count) -{ - if (count) { - struct ext2_sb_info *sbi = EXT2_SB(sb); - unsigned free_blocks; - - spin_lock(sb_bgl_lock(sbi, group_no)); - free_blocks = le16_to_cpu(desc->bg_free_blocks_count); - desc->bg_free_blocks_count = cpu_to_le16(free_blocks + count); - spin_unlock(sb_bgl_lock(sbi, group_no)); - sb->s_dirt = 1; - mark_buffer_dirty(bh); - } -} - -/* - * The reservation window structure operations - * -------------------------------------------- - * Operations include: - * dump, find, add, remove, is_empty, find_next_reservable_window, etc. - * - * We use a red-black tree to represent per-filesystem reservation - * windows. - * - */ - -/** - * __rsv_window_dump() -- Dump the filesystem block allocation reservation map - * @rb_root: root of per-filesystem reservation rb tree - * @verbose: verbose mode - * @fn: function which wishes to dump the reservation map - * - * If verbose is turned on, it will print the whole block reservation - * windows(start, end). Otherwise, it will only print out the "bad" windows, - * those windows that overlap with their immediate neighbors. - */ -#if 1 -static void __rsv_window_dump(struct rb_root *root, int verbose, - const char *fn) -{ - struct rb_node *n; - struct ext2_reserve_window_node *rsv, *prev; - int bad; - -restart: - n = rb_first(root); - bad = 0; - prev = NULL; - - printk("Block Allocation Reservation Windows Map (%s):\n", fn); - while (n) { - rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); - if (verbose) - printk("reservation window 0x%p " - "start: %lu, end: %lu\n", - rsv, rsv->rsv_start, rsv->rsv_end); - if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { - printk("Bad reservation %p (start >= end)\n", - rsv); - bad = 1; - } - if (prev && prev->rsv_end >= rsv->rsv_start) { - printk("Bad reservation %p (prev->end >= start)\n", - rsv); - bad = 1; - } - if (bad) { - if (!verbose) { - printk("Restarting reservation walk in verbose mode\n"); - verbose = 1; - goto restart; - } - } - n = rb_next(n); - prev = rsv; - } - printk("Window map complete.\n"); - BUG_ON(bad); -} -#define rsv_window_dump(root, verbose) \ - __rsv_window_dump((root), (verbose), __func__) -#else -#define rsv_window_dump(root, verbose) do {} while (0) -#endif - -/** - * goal_in_my_reservation() - * @rsv: inode's reservation window - * @grp_goal: given goal block relative to the allocation block group - * @group: the current allocation block group - * @sb: filesystem super block - * - * Test if the given goal block (group relative) is within the file's - * own block reservation window range. - * - * If the reservation window is outside the goal allocation group, return 0; - * grp_goal (given goal block) could be -1, which means no specific - * goal block. In this case, always return 1. - * If the goal block is within the reservation window, return 1; - * otherwise, return 0; - */ -static int -goal_in_my_reservation(struct ext2_reserve_window *rsv, ext2_grpblk_t grp_goal, - unsigned int group, struct super_block * sb) -{ - ext2_fsblk_t group_first_block, group_last_block; - - group_first_block = ext2_group_first_block_no(sb, group); - group_last_block = group_first_block + EXT2_BLOCKS_PER_GROUP(sb) - 1; - - if ((rsv->_rsv_start > group_last_block) || - (rsv->_rsv_end < group_first_block)) - return 0; - if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) - || (grp_goal + group_first_block > rsv->_rsv_end))) - return 0; - return 1; -} - -/** - * search_reserve_window() - * @rb_root: root of reservation tree - * @goal: target allocation block - * - * Find the reserved window which includes the goal, or the previous one - * if the goal is not in any window. - * Returns NULL if there are no windows or if all windows start after the goal. - */ -static struct ext2_reserve_window_node * -search_reserve_window(struct rb_root *root, ext2_fsblk_t goal) -{ - struct rb_node *n = root->rb_node; - struct ext2_reserve_window_node *rsv; - - if (!n) - return NULL; - - do { - rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); - - if (goal < rsv->rsv_start) - n = n->rb_left; - else if (goal > rsv->rsv_end) - n = n->rb_right; - else - return rsv; - } while (n); - /* - * We've fallen off the end of the tree: the goal wasn't inside - * any particular node. OK, the previous node must be to one - * side of the interval containing the goal. If it's the RHS, - * we need to back up one. - */ - if (rsv->rsv_start > goal) { - n = rb_prev(&rsv->rsv_node); - rsv = rb_entry(n, struct ext2_reserve_window_node, rsv_node); - } - return rsv; -} - -/* - * ext2_rsv_window_add() -- Insert a window to the block reservation rb tree. - * @sb: super block - * @rsv: reservation window to add - * - * Must be called with rsv_lock held. - */ -void ext2_rsv_window_add(struct super_block *sb, - struct ext2_reserve_window_node *rsv) -{ - struct rb_root *root = &EXT2_SB(sb)->s_rsv_window_root; - struct rb_node *node = &rsv->rsv_node; - ext2_fsblk_t start = rsv->rsv_start; - - struct rb_node ** p = &root->rb_node; - struct rb_node * parent = NULL; - struct ext2_reserve_window_node *this; - - while (*p) - { - parent = *p; - this = rb_entry(parent, struct ext2_reserve_window_node, rsv_node); - - if (start < this->rsv_start) - p = &(*p)->rb_left; - else if (start > this->rsv_end) - p = &(*p)->rb_right; - else { - rsv_window_dump(root, 1); - BUG(); - } - } - - rb_link_node(node, parent, p); - rb_insert_color(node, root); -} - -/** - * rsv_window_remove() -- unlink a window from the reservation rb tree - * @sb: super block - * @rsv: reservation window to remove - * - * Mark the block reservation window as not allocated, and unlink it - * from the filesystem reservation window rb tree. Must be called with - * rsv_lock held. - */ -static void rsv_window_remove(struct super_block *sb, - struct ext2_reserve_window_node *rsv) -{ - rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_alloc_hit = 0; - rb_erase(&rsv->rsv_node, &EXT2_SB(sb)->s_rsv_window_root); -} - -/* - * rsv_is_empty() -- Check if the reservation window is allocated. - * @rsv: given reservation window to check - * - * returns 1 if the end block is EXT2_RESERVE_WINDOW_NOT_ALLOCATED. - */ -static inline int rsv_is_empty(struct ext2_reserve_window *rsv) -{ - /* a valid reservation end block could not be 0 */ - return (rsv->_rsv_end == EXT2_RESERVE_WINDOW_NOT_ALLOCATED); -} - -/** - * ext2_init_block_alloc_info() - * @inode: file inode structure - * - * Allocate and initialize the reservation window structure, and - * link the window to the ext2 inode structure at last - * - * The reservation window structure is only dynamically allocated - * and linked to ext2 inode the first time the open file - * needs a new block. So, before every ext2_new_block(s) call, for - * regular files, we should check whether the reservation window - * structure exists or not. In the latter case, this function is called. - * Fail to do so will result in block reservation being turned off for that - * open file. - * - * This function is called from ext2_get_blocks_handle(), also called - * when setting the reservation window size through ioctl before the file - * is open for write (needs block allocation). - * - * Needs truncate_mutex protection prior to calling this function. - */ -void ext2_init_block_alloc_info(struct inode *inode) -{ - struct ext2_inode_info *ei = EXT2_I(inode); - struct ext2_block_alloc_info *block_i; - struct super_block *sb = inode->i_sb; - - block_i = kmalloc(sizeof(*block_i), GFP_NOFS); - if (block_i) { - struct ext2_reserve_window_node *rsv = &block_i->rsv_window_node; - - rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - - /* - * if filesystem is mounted with NORESERVATION, the goal - * reservation window size is set to zero to indicate - * block reservation is off - */ - if (!test_opt(sb, RESERVATION)) - rsv->rsv_goal_size = 0; - else - rsv->rsv_goal_size = EXT2_DEFAULT_RESERVE_BLOCKS; - rsv->rsv_alloc_hit = 0; - block_i->last_alloc_logical_block = 0; - block_i->last_alloc_physical_block = 0; - } - ei->i_block_alloc_info = block_i; -} - -/** - * ext2_discard_reservation() - * @inode: inode - * - * Discard(free) block reservation window on last file close, or truncate - * or at last iput(). - * - * It is being called in three cases: - * ext2_release_file(): last writer closes the file - * ext2_clear_inode(): last iput(), when nobody links to this file. - * ext2_truncate(): when the block indirect map is about to change. - */ -void ext2_discard_reservation(struct inode *inode) -{ - struct ext2_inode_info *ei = EXT2_I(inode); - struct ext2_block_alloc_info *block_i = ei->i_block_alloc_info; - struct ext2_reserve_window_node *rsv; - spinlock_t *rsv_lock = &EXT2_SB(inode->i_sb)->s_rsv_window_lock; - - if (!block_i) - return; - - rsv = &block_i->rsv_window_node; - if (!rsv_is_empty(&rsv->rsv_window)) { - spin_lock(rsv_lock); - if (!rsv_is_empty(&rsv->rsv_window)) - rsv_window_remove(inode->i_sb, rsv); - spin_unlock(rsv_lock); - } -} - -/** - * ext2_free_blocks_sb() -- Free given blocks and update quota and i_blocks - * @inode: inode - * @block: start physcial block to free - * @count: number of blocks to free - */ -void ext2_free_blocks (struct inode * inode, unsigned long block, - unsigned long count) -{ - struct buffer_head *bitmap_bh = NULL; - struct buffer_head * bh2; - unsigned long block_group; - unsigned long bit; - unsigned long i; - unsigned long overflow; - struct super_block * sb = inode->i_sb; - struct ext2_sb_info * sbi = EXT2_SB(sb); - struct ext2_group_desc * desc; - struct ext2_super_block * es = sbi->s_es; - unsigned freed = 0, group_freed; - - if (block < le32_to_cpu(es->s_first_data_block) || - block + count < block || - block + count > le32_to_cpu(es->s_blocks_count)) { - ext2_error (sb, "ext2_free_blocks", - "Freeing blocks not in datazone - " - "block = %lu, count = %lu", block, count); - goto error_return; - } - - ext2_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); - -do_more: - overflow = 0; - block_group = (block - le32_to_cpu(es->s_first_data_block)) / - EXT2_BLOCKS_PER_GROUP(sb); - bit = (block - le32_to_cpu(es->s_first_data_block)) % - EXT2_BLOCKS_PER_GROUP(sb); - /* - * Check to see if we are freeing blocks across a group - * boundary. - */ - if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) { - overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb); - count -= overflow; - } - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, block_group); - if (!bitmap_bh) - goto error_return; - - desc = ext2_get_group_desc (sb, block_group, &bh2); - if (!desc) - goto error_return; - - if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) { - ext2_error (sb, "ext2_free_blocks", - "Freeing blocks in system zones - " - "Block = %lu, count = %lu", - block, count); - goto error_return; - } - - for (i = 0, group_freed = 0; i < count; i++) { - if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group), - bit + i, bitmap_bh->b_data)) { - ext2_error(sb, __func__, - "bit already cleared for block %lu", block + i); - } else { - group_freed++; - } - } - - mark_buffer_dirty(bitmap_bh); - if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); - - group_adjust_blocks(sb, block_group, desc, bh2, group_freed); - freed += group_freed; - - if (overflow) { - block += count; - count = overflow; - goto do_more; - } -error_return: - brelse(bitmap_bh); - release_blocks(sb, freed); - dquot_free_block_nodirty(inode, freed); -} - -/** - * bitmap_search_next_usable_block() - * @start: the starting block (group relative) of the search - * @bh: bufferhead contains the block group bitmap - * @maxblocks: the ending block (group relative) of the reservation - * - * The bitmap search --- search forward through the actual bitmap on disk until - * we find a bit free. - */ -static ext2_grpblk_t -bitmap_search_next_usable_block(ext2_grpblk_t start, struct buffer_head *bh, - ext2_grpblk_t maxblocks) -{ - ext2_grpblk_t next; - - next = ext2_find_next_zero_bit(bh->b_data, maxblocks, start); - if (next >= maxblocks) - return -1; - return next; -} - -/** - * find_next_usable_block() - * @start: the starting block (group relative) to find next - * allocatable block in bitmap. - * @bh: bufferhead contains the block group bitmap - * @maxblocks: the ending block (group relative) for the search - * - * Find an allocatable block in a bitmap. We perform the "most - * appropriate allocation" algorithm of looking for a free block near - * the initial goal; then for a free byte somewhere in the bitmap; - * then for any free bit in the bitmap. - */ -static ext2_grpblk_t -find_next_usable_block(int start, struct buffer_head *bh, int maxblocks) -{ - ext2_grpblk_t here, next; - char *p, *r; - - if (start > 0) { - /* - * The goal was occupied; search forward for a free - * block within the next XX blocks. - * - * end_goal is more or less random, but it has to be - * less than EXT2_BLOCKS_PER_GROUP. Aligning up to the - * next 64-bit boundary is simple.. - */ - ext2_grpblk_t end_goal = (start + 63) & ~63; - if (end_goal > maxblocks) - end_goal = maxblocks; - here = ext2_find_next_zero_bit(bh->b_data, end_goal, start); - if (here < end_goal) - return here; - ext2_debug("Bit not found near goal\n"); - } - - here = start; - if (here < 0) - here = 0; - - p = ((char *)bh->b_data) + (here >> 3); - r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3)); - next = (r - ((char *)bh->b_data)) << 3; - - if (next < maxblocks && next >= here) - return next; - - here = bitmap_search_next_usable_block(here, bh, maxblocks); - return here; -} - -/** - * ext2_try_to_allocate() - * @sb: superblock - * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap - * @grp_goal: given target block within the group - * @count: target number of blocks to allocate - * @my_rsv: reservation window - * - * Attempt to allocate blocks within a give range. Set the range of allocation - * first, then find the first free bit(s) from the bitmap (within the range), - * and at last, allocate the blocks by claiming the found free bit as allocated. - * - * To set the range of this allocation: - * if there is a reservation window, only try to allocate block(s) - * from the file's own reservation window; - * Otherwise, the allocation range starts from the give goal block, - * ends at the block group's last block. - * - * If we failed to allocate the desired block then we may end up crossing to a - * new bitmap. - */ -static int -ext2_try_to_allocate(struct super_block *sb, int group, - struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, - unsigned long *count, - struct ext2_reserve_window *my_rsv) -{ - ext2_fsblk_t group_first_block; - ext2_grpblk_t start, end; - unsigned long num = 0; - - /* we do allocation within the reservation window if we have a window */ - if (my_rsv) { - group_first_block = ext2_group_first_block_no(sb, group); - if (my_rsv->_rsv_start >= group_first_block) - start = my_rsv->_rsv_start - group_first_block; - else - /* reservation window cross group boundary */ - start = 0; - end = my_rsv->_rsv_end - group_first_block + 1; - if (end > EXT2_BLOCKS_PER_GROUP(sb)) - /* reservation window crosses group boundary */ - end = EXT2_BLOCKS_PER_GROUP(sb); - if ((start <= grp_goal) && (grp_goal < end)) - start = grp_goal; - else - grp_goal = -1; - } else { - if (grp_goal > 0) - start = grp_goal; - else - start = 0; - end = EXT2_BLOCKS_PER_GROUP(sb); - } - - BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); - -repeat: - if (grp_goal < 0) { - grp_goal = find_next_usable_block(start, bitmap_bh, end); - if (grp_goal < 0) - goto fail_access; - if (!my_rsv) { - int i; - - for (i = 0; i < 7 && grp_goal > start && - !ext2_test_bit(grp_goal - 1, - bitmap_bh->b_data); - i++, grp_goal--) - ; - } - } - start = grp_goal; - - if (ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), grp_goal, - bitmap_bh->b_data)) { - /* - * The block was allocated by another thread, or it was - * allocated and then freed by another thread - */ - start++; - grp_goal++; - if (start >= end) - goto fail_access; - goto repeat; - } - num++; - grp_goal++; - while (num < *count && grp_goal < end - && !ext2_set_bit_atomic(sb_bgl_lock(EXT2_SB(sb), group), - grp_goal, bitmap_bh->b_data)) { - num++; - grp_goal++; - } - *count = num; - return grp_goal - num; -fail_access: - *count = num; - return -1; -} - -/** - * find_next_reservable_window(): - * find a reservable space within the given range. - * It does not allocate the reservation window for now: - * alloc_new_reservation() will do the work later. - * - * @search_head: the head of the searching list; - * This is not necessarily the list head of the whole filesystem - * - * We have both head and start_block to assist the search - * for the reservable space. The list starts from head, - * but we will shift to the place where start_block is, - * then start from there, when looking for a reservable space. - * - * @size: the target new reservation window size - * - * @group_first_block: the first block we consider to start - * the real search from - * - * @last_block: - * the maximum block number that our goal reservable space - * could start from. This is normally the last block in this - * group. The search will end when we found the start of next - * possible reservable space is out of this boundary. - * This could handle the cross boundary reservation window - * request. - * - * basically we search from the given range, rather than the whole - * reservation double linked list, (start_block, last_block) - * to find a free region that is of my size and has not - * been reserved. - * - */ -static int find_next_reservable_window( - struct ext2_reserve_window_node *search_head, - struct ext2_reserve_window_node *my_rsv, - struct super_block * sb, - ext2_fsblk_t start_block, - ext2_fsblk_t last_block) -{ - struct rb_node *next; - struct ext2_reserve_window_node *rsv, *prev; - ext2_fsblk_t cur; - int size = my_rsv->rsv_goal_size; - - /* TODO: make the start of the reservation window byte-aligned */ - /* cur = *start_block & ~7;*/ - cur = start_block; - rsv = search_head; - if (!rsv) - return -1; - - while (1) { - if (cur <= rsv->rsv_end) - cur = rsv->rsv_end + 1; - - /* TODO? - * in the case we could not find a reservable space - * that is what is expected, during the re-search, we could - * remember what's the largest reservable space we could have - * and return that one. - * - * For now it will fail if we could not find the reservable - * space with expected-size (or more)... - */ - if (cur > last_block) - return -1; /* fail */ - - prev = rsv; - next = rb_next(&rsv->rsv_node); - rsv = rb_entry(next,struct ext2_reserve_window_node,rsv_node); - - /* - * Reached the last reservation, we can just append to the - * previous one. - */ - if (!next) - break; - - if (cur + size <= rsv->rsv_start) { - /* - * Found a reserveable space big enough. We could - * have a reservation across the group boundary here - */ - break; - } - } - /* - * we come here either : - * when we reach the end of the whole list, - * and there is empty reservable space after last entry in the list. - * append it to the end of the list. - * - * or we found one reservable space in the middle of the list, - * return the reservation window that we could append to. - * succeed. - */ - - if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) - rsv_window_remove(sb, my_rsv); - - /* - * Let's book the whole available window for now. We will check the - * disk bitmap later and then, if there are free blocks then we adjust - * the window size if it's larger than requested. - * Otherwise, we will remove this node from the tree next time - * call find_next_reservable_window. - */ - my_rsv->rsv_start = cur; - my_rsv->rsv_end = cur + size - 1; - my_rsv->rsv_alloc_hit = 0; - - if (prev != my_rsv) - ext2_rsv_window_add(sb, my_rsv); - - return 0; -} - -/** - * alloc_new_reservation()--allocate a new reservation window - * - * To make a new reservation, we search part of the filesystem - * reservation list (the list that inside the group). We try to - * allocate a new reservation window near the allocation goal, - * or the beginning of the group, if there is no goal. - * - * We first find a reservable space after the goal, then from - * there, we check the bitmap for the first free block after - * it. If there is no free block until the end of group, then the - * whole group is full, we failed. Otherwise, check if the free - * block is inside the expected reservable space, if so, we - * succeed. - * If the first free block is outside the reservable space, then - * start from the first free block, we search for next available - * space, and go on. - * - * on succeed, a new reservation will be found and inserted into the list - * It contains at least one free block, and it does not overlap with other - * reservation windows. - * - * failed: we failed to find a reservation window in this group - * - * @rsv: the reservation - * - * @grp_goal: The goal (group-relative). It is where the search for a - * free reservable space should start from. - * if we have a goal(goal >0 ), then start from there, - * no goal(goal = -1), we start from the first block - * of the group. - * - * @sb: the super block - * @group: the group we are trying to allocate in - * @bitmap_bh: the block group block bitmap - * - */ -static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv, - ext2_grpblk_t grp_goal, struct super_block *sb, - unsigned int group, struct buffer_head *bitmap_bh) -{ - struct ext2_reserve_window_node *search_head; - ext2_fsblk_t group_first_block, group_end_block, start_block; - ext2_grpblk_t first_free_block; - struct rb_root *fs_rsv_root = &EXT2_SB(sb)->s_rsv_window_root; - unsigned long size; - int ret; - spinlock_t *rsv_lock = &EXT2_SB(sb)->s_rsv_window_lock; - - group_first_block = ext2_group_first_block_no(sb, group); - group_end_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); - - if (grp_goal < 0) - start_block = group_first_block; - else - start_block = grp_goal + group_first_block; - - size = my_rsv->rsv_goal_size; - - if (!rsv_is_empty(&my_rsv->rsv_window)) { - /* - * if the old reservation is cross group boundary - * and if the goal is inside the old reservation window, - * we will come here when we just failed to allocate from - * the first part of the window. We still have another part - * that belongs to the next group. In this case, there is no - * point to discard our window and try to allocate a new one - * in this group(which will fail). we should - * keep the reservation window, just simply move on. - * - * Maybe we could shift the start block of the reservation - * window to the first block of next group. - */ - - if ((my_rsv->rsv_start <= group_end_block) && - (my_rsv->rsv_end > group_end_block) && - (start_block >= my_rsv->rsv_start)) - return -1; - - if ((my_rsv->rsv_alloc_hit > - (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { - /* - * if the previously allocation hit ratio is - * greater than 1/2, then we double the size of - * the reservation window the next time, - * otherwise we keep the same size window - */ - size = size * 2; - if (size > EXT2_MAX_RESERVE_BLOCKS) - size = EXT2_MAX_RESERVE_BLOCKS; - my_rsv->rsv_goal_size= size; - } - } - - spin_lock(rsv_lock); - /* - * shift the search start to the window near the goal block - */ - search_head = search_reserve_window(fs_rsv_root, start_block); - - /* - * find_next_reservable_window() simply finds a reservable window - * inside the given range(start_block, group_end_block). - * - * To make sure the reservation window has a free bit inside it, we - * need to check the bitmap after we found a reservable window. - */ -retry: - ret = find_next_reservable_window(search_head, my_rsv, sb, - start_block, group_end_block); - - if (ret == -1) { - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - spin_unlock(rsv_lock); - return -1; - } - - /* - * On success, find_next_reservable_window() returns the - * reservation window where there is a reservable space after it. - * Before we reserve this reservable space, we need - * to make sure there is at least a free block inside this region. - * - * Search the first free bit on the block bitmap. Search starts from - * the start block of the reservable space we just found. - */ - spin_unlock(rsv_lock); - first_free_block = bitmap_search_next_usable_block( - my_rsv->rsv_start - group_first_block, - bitmap_bh, group_end_block - group_first_block + 1); - - if (first_free_block < 0) { - /* - * no free block left on the bitmap, no point - * to reserve the space. return failed. - */ - spin_lock(rsv_lock); - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - spin_unlock(rsv_lock); - return -1; /* failed */ - } - - start_block = first_free_block + group_first_block; - /* - * check if the first free block is within the - * free space we just reserved - */ - if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end) - return 0; /* success */ - /* - * if the first free bit we found is out of the reservable space - * continue search for next reservable space, - * start from where the free block is, - * we also shift the list head to where we stopped last time - */ - search_head = my_rsv; - spin_lock(rsv_lock); - goto retry; -} - -/** - * try_to_extend_reservation() - * @my_rsv: given reservation window - * @sb: super block - * @size: the delta to extend - * - * Attempt to expand the reservation window large enough to have - * required number of free blocks - * - * Since ext2_try_to_allocate() will always allocate blocks within - * the reservation window range, if the window size is too small, - * multiple blocks allocation has to stop at the end of the reservation - * window. To make this more efficient, given the total number of - * blocks needed and the current size of the window, we try to - * expand the reservation window size if necessary on a best-effort - * basis before ext2_new_blocks() tries to allocate blocks. - */ -static void try_to_extend_reservation(struct ext2_reserve_window_node *my_rsv, - struct super_block *sb, int size) -{ - struct ext2_reserve_window_node *next_rsv; - struct rb_node *next; - spinlock_t *rsv_lock = &EXT2_SB(sb)->s_rsv_window_lock; - - if (!spin_trylock(rsv_lock)) - return; - - next = rb_next(&my_rsv->rsv_node); - - if (!next) - my_rsv->rsv_end += size; - else { - next_rsv = rb_entry(next, struct ext2_reserve_window_node, rsv_node); - - if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) - my_rsv->rsv_end += size; - else - my_rsv->rsv_end = next_rsv->rsv_start - 1; - } - spin_unlock(rsv_lock); -} - -/** - * ext2_try_to_allocate_with_rsv() - * @sb: superblock - * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap - * @grp_goal: given target block within the group - * @count: target number of blocks to allocate - * @my_rsv: reservation window - * - * This is the main function used to allocate a new block and its reservation - * window. - * - * Each time when a new block allocation is need, first try to allocate from - * its own reservation. If it does not have a reservation window, instead of - * looking for a free bit on bitmap first, then look up the reservation list to - * see if it is inside somebody else's reservation window, we try to allocate a - * reservation window for it starting from the goal first. Then do the block - * allocation within the reservation window. - * - * This will avoid keeping on searching the reservation list again and - * again when somebody is looking for a free block (without - * reservation), and there are lots of free blocks, but they are all - * being reserved. - * - * We use a red-black tree for the per-filesystem reservation list. - */ -static ext2_grpblk_t -ext2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group, - struct buffer_head *bitmap_bh, ext2_grpblk_t grp_goal, - struct ext2_reserve_window_node * my_rsv, - unsigned long *count) -{ - ext2_fsblk_t group_first_block, group_last_block; - ext2_grpblk_t ret = 0; - unsigned long num = *count; - - /* - * we don't deal with reservation when - * filesystem is mounted without reservation - * or the file is not a regular file - * or last attempt to allocate a block with reservation turned on failed - */ - if (my_rsv == NULL) { - return ext2_try_to_allocate(sb, group, bitmap_bh, - grp_goal, count, NULL); - } - /* - * grp_goal is a group relative block number (if there is a goal) - * 0 <= grp_goal < EXT2_BLOCKS_PER_GROUP(sb) - * first block is a filesystem wide block number - * first block is the block number of the first block in this group - */ - group_first_block = ext2_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); - - /* - * Basically we will allocate a new block from inode's reservation - * window. - * - * We need to allocate a new reservation window, if: - * a) inode does not have a reservation window; or - * b) last attempt to allocate a block from existing reservation - * failed; or - * c) we come here with a goal and with a reservation window - * - * We do not need to allocate a new reservation window if we come here - * at the beginning with a goal and the goal is inside the window, or - * we don't have a goal but already have a reservation window. - * then we could go to allocate from the reservation window directly. - */ - while (1) { - if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || - !goal_in_my_reservation(&my_rsv->rsv_window, - grp_goal, group, sb)) { - if (my_rsv->rsv_goal_size < *count) - my_rsv->rsv_goal_size = *count; - ret = alloc_new_reservation(my_rsv, grp_goal, sb, - group, bitmap_bh); - if (ret < 0) - break; /* failed */ - - if (!goal_in_my_reservation(&my_rsv->rsv_window, - grp_goal, group, sb)) - grp_goal = -1; - } else if (grp_goal >= 0) { - int curr = my_rsv->rsv_end - - (grp_goal + group_first_block) + 1; - - if (curr < *count) - try_to_extend_reservation(my_rsv, sb, - *count - curr); - } - - if ((my_rsv->rsv_start > group_last_block) || - (my_rsv->rsv_end < group_first_block)) { - rsv_window_dump(&EXT2_SB(sb)->s_rsv_window_root, 1); - BUG(); - } - ret = ext2_try_to_allocate(sb, group, bitmap_bh, grp_goal, - &num, &my_rsv->rsv_window); - if (ret >= 0) { - my_rsv->rsv_alloc_hit += num; - *count = num; - break; /* succeed */ - } - num = *count; - } - return ret; -} - -/** - * ext2_has_free_blocks() - * @sbi: in-core super block structure. - * - * Check if filesystem has at least 1 free block available for allocation. - */ -static int ext2_has_free_blocks(struct ext2_sb_info *sbi) -{ - ext2_fsblk_t free_blocks, root_blocks; - - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); - if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && - sbi->s_resuid != current_fsuid() && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { - return 0; - } - return 1; -} - -/* - * ext2_new_blocks() -- core block(s) allocation function - * @inode: file inode - * @goal: given target block(filesystem wide) - * @count: target number of blocks to allocate - * @errp: error code - * - * ext2_new_blocks uses a goal block to assist allocation. If the goal is - * free, or there is a free block within 32 blocks of the goal, that block - * is allocated. Otherwise a forward search is made for a free block; within - * each block group the search first looks for an entire free byte in the block - * bitmap, and then for any free bit if that fails. - * This function also updates quota and i_blocks field. - */ -ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, - unsigned long *count, int *errp) -{ - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gdp_bh; - int group_no; - int goal_group; - ext2_grpblk_t grp_target_blk; /* blockgroup relative goal block */ - ext2_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ - ext2_fsblk_t ret_block; /* filesyetem-wide allocated block */ - int bgi; /* blockgroup iteration index */ - int performed_allocation = 0; - ext2_grpblk_t free_blocks; /* number of free blocks in a group */ - struct super_block *sb; - struct ext2_group_desc *gdp; - struct ext2_super_block *es; - struct ext2_sb_info *sbi; - struct ext2_reserve_window_node *my_rsv = NULL; - struct ext2_block_alloc_info *block_i; - unsigned short windowsz = 0; - unsigned long ngroups; - unsigned long num = *count; - int ret; - - *errp = -ENOSPC; - sb = inode->i_sb; - if (!sb) { - printk("ext2_new_blocks: nonexistent device"); - return 0; - } - - /* - * Check quota for allocation of this block. - */ - ret = dquot_alloc_block(inode, num); - if (ret) { - *errp = ret; - return 0; - } - - sbi = EXT2_SB(sb); - es = EXT2_SB(sb)->s_es; - ext2_debug("goal=%lu.\n", goal); - /* - * Allocate a block from reservation only when - * filesystem is mounted with reservation(default,-o reservation), and - * it's a regular file, and - * the desired window size is greater than 0 (One could use ioctl - * command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn off - * reservation on that particular file) - */ - block_i = EXT2_I(inode)->i_block_alloc_info; - if (block_i) { - windowsz = block_i->rsv_window_node.rsv_goal_size; - if (windowsz > 0) - my_rsv = &block_i->rsv_window_node; - } - - if (!ext2_has_free_blocks(sbi)) { - *errp = -ENOSPC; - goto out; - } - - /* - * First, test whether the goal block is free. - */ - if (goal < le32_to_cpu(es->s_first_data_block) || - goal >= le32_to_cpu(es->s_blocks_count)) - goal = le32_to_cpu(es->s_first_data_block); - group_no = (goal - le32_to_cpu(es->s_first_data_block)) / - EXT2_BLOCKS_PER_GROUP(sb); - goal_group = group_no; -retry_alloc: - gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); - if (!gdp) - goto io_error; - - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); - /* - * if there is not enough free blocks to make a new resevation - * turn off reservation for this allocation - */ - if (my_rsv && (free_blocks < windowsz) - && (free_blocks > 0) - && (rsv_is_empty(&my_rsv->rsv_window))) - my_rsv = NULL; - - if (free_blocks > 0) { - grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % - EXT2_BLOCKS_PER_GROUP(sb)); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, - bitmap_bh, grp_target_blk, - my_rsv, &num); - if (grp_alloc_blk >= 0) - goto allocated; - } - - ngroups = EXT2_SB(sb)->s_groups_count; - smp_rmb(); - - /* - * Now search the rest of the groups. We assume that - * group_no and gdp correctly point to the last group visited. - */ - for (bgi = 0; bgi < ngroups; bgi++) { - group_no++; - if (group_no >= ngroups) - group_no = 0; - gdp = ext2_get_group_desc(sb, group_no, &gdp_bh); - if (!gdp) - goto io_error; - - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); - /* - * skip this group (and avoid loading bitmap) if there - * are no free blocks - */ - if (!free_blocks) - continue; - /* - * skip this group if the number of - * free blocks is less than half of the reservation - * window size. - */ - if (my_rsv && (free_blocks <= (windowsz/2))) - continue; - - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - /* - * try to allocate block(s) from this group, without a goal(-1). - */ - grp_alloc_blk = ext2_try_to_allocate_with_rsv(sb, group_no, - bitmap_bh, -1, my_rsv, &num); - if (grp_alloc_blk >= 0) - goto allocated; - } - /* - * We may end up a bogus earlier ENOSPC error due to - * filesystem is "full" of reservations, but - * there maybe indeed free blocks available on disk - * In this case, we just forget about the reservations - * just do block allocation as without reservations. - */ - if (my_rsv) { - my_rsv = NULL; - windowsz = 0; - group_no = goal_group; - goto retry_alloc; - } - /* No space left on the device */ - *errp = -ENOSPC; - goto out; - -allocated: - - ext2_debug("using block group %d(%d)\n", - group_no, gdp->bg_free_blocks_count); - - ret_block = grp_alloc_blk + ext2_group_first_block_no(sb, group_no); - - if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || - in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || - in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), - EXT2_SB(sb)->s_itb_per_group) || - in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT2_SB(sb)->s_itb_per_group)) { - ext2_error(sb, "ext2_new_blocks", - "Allocating block in system zone - " - "blocks from "E2FSBLK", length %lu", - ret_block, num); - /* - * ext2_try_to_allocate marked the blocks we allocated as in - * use. So we may want to selectively mark some of the blocks - * as free - */ - goto retry_alloc; - } - - performed_allocation = 1; - - if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { - ext2_error(sb, "ext2_new_blocks", - "block("E2FSBLK") >= blocks count(%d) - " - "block_group = %d, es == %p ", ret_block, - le32_to_cpu(es->s_blocks_count), group_no, es); - goto out; - } - - group_adjust_blocks(sb, group_no, gdp, gdp_bh, -num); - percpu_counter_sub(&sbi->s_freeblocks_counter, num); - - mark_buffer_dirty(bitmap_bh); - if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); - - *errp = 0; - brelse(bitmap_bh); - dquot_free_block_nodirty(inode, *count-num); - mark_inode_dirty(inode); - *count = num; - return ret_block; - -io_error: - *errp = -EIO; -out: - /* - * Undo the block allocation - */ - if (!performed_allocation) { - dquot_free_block_nodirty(inode, *count); - mark_inode_dirty(inode); - } - brelse(bitmap_bh); - return 0; -} - -ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp) -{ - unsigned long count = 1; - - return ext2_new_blocks(inode, goal, &count, errp); -} - -#ifdef EXT2FS_DEBUG - -static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; - -unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) -{ - unsigned int i; - unsigned long sum = 0; - - if (!map) - return (0); - for (i = 0; i < numchars; i++) - sum += nibblemap[map->b_data[i] & 0xf] + - nibblemap[(map->b_data[i] >> 4) & 0xf]; - return (sum); -} - -#endif /* EXT2FS_DEBUG */ - -unsigned long ext2_count_free_blocks (struct super_block * sb) -{ - struct ext2_group_desc * desc; - unsigned long desc_count = 0; - int i; -#ifdef EXT2FS_DEBUG - unsigned long bitmap_count, x; - struct ext2_super_block *es; - - es = EXT2_SB(sb)->s_es; - desc_count = 0; - bitmap_count = 0; - desc = NULL; - for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - struct buffer_head *bitmap_bh; - desc = ext2_get_group_desc (sb, i, NULL); - if (!desc) - continue; - desc_count += le16_to_cpu(desc->bg_free_blocks_count); - bitmap_bh = read_block_bitmap(sb, i); - if (!bitmap_bh) - continue; - - x = ext2_count_free(bitmap_bh, sb->s_blocksize); - printk ("group %d: stored = %d, counted = %lu\n", - i, le16_to_cpu(desc->bg_free_blocks_count), x); - bitmap_count += x; - brelse(bitmap_bh); - } - printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", - (long)le32_to_cpu(es->s_free_blocks_count), - desc_count, bitmap_count); - return bitmap_count; -#else - for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - desc = ext2_get_group_desc (sb, i, NULL); - if (!desc) - continue; - desc_count += le16_to_cpu(desc->bg_free_blocks_count); - } - return desc_count; -#endif -} - -static inline int test_root(int a, int b) -{ - int num = b; - - while (a > num) - num *= b; - return num == a; -} - -static int ext2_group_sparse(int group) -{ - if (group <= 1) - return 1; - return (test_root(group, 3) || test_root(group, 5) || - test_root(group, 7)); -} - -/** - * ext2_bg_has_super - number of blocks used by the superblock in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the superblock (primary or backup) - * in this group. Currently this will be only 0 or 1. - */ -int ext2_bg_has_super(struct super_block *sb, int group) -{ - if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&& - !ext2_group_sparse(group)) - return 0; - return 1; -} - -/** - * ext2_bg_num_gdb - number of blocks used by the group table in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the group descriptor table - * (primary or backup) in this group. In the future there may be a - * different number of descriptor blocks in each group. - */ -unsigned long ext2_bg_num_gdb(struct super_block *sb, int group) -{ - return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0; -} - diff --git a/ANDROID_3.4.5/fs/ext2/dir.c b/ANDROID_3.4.5/fs/ext2/dir.c deleted file mode 100644 index 0f4f5c92..00000000 --- a/ANDROID_3.4.5/fs/ext2/dir.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * linux/fs/ext2/dir.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/dir.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext2 directory handling functions - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * All code that works with directory layout had been switched to pagecache - * and moved here. AV - */ - -#include "ext2.h" -#include <linux/buffer_head.h> -#include <linux/pagemap.h> -#include <linux/swap.h> - -typedef struct ext2_dir_entry_2 ext2_dirent; - -/* - * Tests against MAX_REC_LEN etc were put in place for 64k block - * sizes; if that is not possible on this arch, we can skip - * those tests and speed things up. - */ -static inline unsigned ext2_rec_len_from_disk(__le16 dlen) -{ - unsigned len = le16_to_cpu(dlen); - -#if (PAGE_CACHE_SIZE >= 65536) - if (len == EXT2_MAX_REC_LEN) - return 1 << 16; -#endif - return len; -} - -static inline __le16 ext2_rec_len_to_disk(unsigned len) -{ -#if (PAGE_CACHE_SIZE >= 65536) - if (len == (1 << 16)) - return cpu_to_le16(EXT2_MAX_REC_LEN); - else - BUG_ON(len > (1 << 16)); -#endif - return cpu_to_le16(len); -} - -/* - * ext2 uses block-sized chunks. Arguably, sector-sized ones would be - * more robust, but we have what we have - */ -static inline unsigned ext2_chunk_size(struct inode *inode) -{ - return inode->i_sb->s_blocksize; -} - -static inline void ext2_put_page(struct page *page) -{ - kunmap(page); - page_cache_release(page); -} - -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - -/* - * Return the offset into page `page_nr' of the last valid - * byte in that page, plus one. - */ -static unsigned -ext2_last_byte(struct inode *inode, unsigned long page_nr) -{ - unsigned last_byte = inode->i_size; - - last_byte -= page_nr << PAGE_CACHE_SHIFT; - if (last_byte > PAGE_CACHE_SIZE) - last_byte = PAGE_CACHE_SIZE; - return last_byte; -} - -static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len) -{ - struct address_space *mapping = page->mapping; - struct inode *dir = mapping->host; - int err = 0; - - dir->i_version++; - block_write_end(NULL, mapping, pos, len, len, page, NULL); - - if (pos+len > dir->i_size) { - i_size_write(dir, pos+len); - mark_inode_dirty(dir); - } - - if (IS_DIRSYNC(dir)) { - err = write_one_page(page, 1); - if (!err) - err = sync_inode_metadata(dir, 1); - } else { - unlock_page(page); - } - - return err; -} - -static void ext2_check_page(struct page *page, int quiet) -{ - struct inode *dir = page->mapping->host; - struct super_block *sb = dir->i_sb; - unsigned chunk_size = ext2_chunk_size(dir); - char *kaddr = page_address(page); - u32 max_inumber = le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count); - unsigned offs, rec_len; - unsigned limit = PAGE_CACHE_SIZE; - ext2_dirent *p; - char *error; - - if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { - limit = dir->i_size & ~PAGE_CACHE_MASK; - if (limit & (chunk_size - 1)) - goto Ebadsize; - if (!limit) - goto out; - } - for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) { - p = (ext2_dirent *)(kaddr + offs); - rec_len = ext2_rec_len_from_disk(p->rec_len); - - if (unlikely(rec_len < EXT2_DIR_REC_LEN(1))) - goto Eshort; - if (unlikely(rec_len & 3)) - goto Ealign; - if (unlikely(rec_len < EXT2_DIR_REC_LEN(p->name_len))) - goto Enamelen; - if (unlikely(((offs + rec_len - 1) ^ offs) & ~(chunk_size-1))) - goto Espan; - if (unlikely(le32_to_cpu(p->inode) > max_inumber)) - goto Einumber; - } - if (offs != limit) - goto Eend; -out: - SetPageChecked(page); - return; - - /* Too bad, we had an error */ - -Ebadsize: - if (!quiet) - ext2_error(sb, __func__, - "size of directory #%lu is not a multiple " - "of chunk size", dir->i_ino); - goto fail; -Eshort: - error = "rec_len is smaller than minimal"; - goto bad_entry; -Ealign: - error = "unaligned directory entry"; - goto bad_entry; -Enamelen: - error = "rec_len is too small for name_len"; - goto bad_entry; -Espan: - error = "directory entry across blocks"; - goto bad_entry; -Einumber: - error = "inode out of bounds"; -bad_entry: - if (!quiet) - ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - " - "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs, - (unsigned long) le32_to_cpu(p->inode), - rec_len, p->name_len); - goto fail; -Eend: - if (!quiet) { - p = (ext2_dirent *)(kaddr + offs); - ext2_error(sb, "ext2_check_page", - "entry in directory #%lu spans the page boundary" - "offset=%lu, inode=%lu", - dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs, - (unsigned long) le32_to_cpu(p->inode)); - } -fail: - SetPageChecked(page); - SetPageError(page); -} - -static struct page * ext2_get_page(struct inode *dir, unsigned long n, - int quiet) -{ - struct address_space *mapping = dir->i_mapping; - struct page *page = read_mapping_page(mapping, n, NULL); - if (!IS_ERR(page)) { - kmap(page); - if (!PageChecked(page)) - ext2_check_page(page, quiet); - if (PageError(page)) - goto fail; - } - return page; - -fail: - ext2_put_page(page); - return ERR_PTR(-EIO); -} - -/* - * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. - * - * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. - */ -static inline int ext2_match (int len, const char * const name, - struct ext2_dir_entry_2 * de) -{ - if (len != de->name_len) - return 0; - if (!de->inode) - return 0; - return !memcmp(name, de->name, len); -} - -/* - * p is at least 6 bytes before the end of page - */ -static inline ext2_dirent *ext2_next_entry(ext2_dirent *p) -{ - return (ext2_dirent *)((char *)p + - ext2_rec_len_from_disk(p->rec_len)); -} - -static inline unsigned -ext2_validate_entry(char *base, unsigned offset, unsigned mask) -{ - ext2_dirent *de = (ext2_dirent*)(base + offset); - ext2_dirent *p = (ext2_dirent*)(base + (offset&mask)); - while ((char*)p < (char*)de) { - if (p->rec_len == 0) - break; - p = ext2_next_entry(p); - } - return (char *)p - base; -} - -static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { - [EXT2_FT_UNKNOWN] = DT_UNKNOWN, - [EXT2_FT_REG_FILE] = DT_REG, - [EXT2_FT_DIR] = DT_DIR, - [EXT2_FT_CHRDEV] = DT_CHR, - [EXT2_FT_BLKDEV] = DT_BLK, - [EXT2_FT_FIFO] = DT_FIFO, - [EXT2_FT_SOCK] = DT_SOCK, - [EXT2_FT_SYMLINK] = DT_LNK, -}; - -#define S_SHIFT 12 -static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] = EXT2_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = EXT2_FT_DIR, - [S_IFCHR >> S_SHIFT] = EXT2_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = EXT2_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = EXT2_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = EXT2_FT_SOCK, - [S_IFLNK >> S_SHIFT] = EXT2_FT_SYMLINK, -}; - -static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode) -{ - umode_t mode = inode->i_mode; - if (EXT2_HAS_INCOMPAT_FEATURE(inode->i_sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) - de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; - else - de->file_type = 0; -} - -static int -ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) -{ - loff_t pos = filp->f_pos; - struct inode *inode = filp->f_path.dentry->d_inode; - struct super_block *sb = inode->i_sb; - unsigned int offset = pos & ~PAGE_CACHE_MASK; - unsigned long n = pos >> PAGE_CACHE_SHIFT; - unsigned long npages = dir_pages(inode); - unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); - unsigned char *types = NULL; - int need_revalidate = filp->f_version != inode->i_version; - - if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) - return 0; - - if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) - types = ext2_filetype_table; - - for ( ; n < npages; n++, offset = 0) { - char *kaddr, *limit; - ext2_dirent *de; - struct page *page = ext2_get_page(inode, n, 0); - - if (IS_ERR(page)) { - ext2_error(sb, __func__, - "bad page in #%lu", - inode->i_ino); - filp->f_pos += PAGE_CACHE_SIZE - offset; - return PTR_ERR(page); - } - kaddr = page_address(page); - if (unlikely(need_revalidate)) { - if (offset) { - offset = ext2_validate_entry(kaddr, offset, chunk_mask); - filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset; - } - filp->f_version = inode->i_version; - need_revalidate = 0; - } - de = (ext2_dirent *)(kaddr+offset); - limit = kaddr + ext2_last_byte(inode, n) - EXT2_DIR_REC_LEN(1); - for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { - if (de->rec_len == 0) { - ext2_error(sb, __func__, - "zero-length directory entry"); - ext2_put_page(page); - return -EIO; - } - if (de->inode) { - int over; - unsigned char d_type = DT_UNKNOWN; - - if (types && de->file_type < EXT2_FT_MAX) - d_type = types[de->file_type]; - - offset = (char *)de - kaddr; - over = filldir(dirent, de->name, de->name_len, - (n<<PAGE_CACHE_SHIFT) | offset, - le32_to_cpu(de->inode), d_type); - if (over) { - ext2_put_page(page); - return 0; - } - } - filp->f_pos += ext2_rec_len_from_disk(de->rec_len); - } - ext2_put_page(page); - } - return 0; -} - -/* - * ext2_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the page in which the entry was found (as a parameter - res_page), - * and the entry itself. Page is returned mapped and unlocked. - * Entry is guaranteed to be valid. - */ -struct ext2_dir_entry_2 *ext2_find_entry (struct inode * dir, - struct qstr *child, struct page ** res_page) -{ - const char *name = child->name; - int namelen = child->len; - unsigned reclen = EXT2_DIR_REC_LEN(namelen); - unsigned long start, n; - unsigned long npages = dir_pages(dir); - struct page *page = NULL; - struct ext2_inode_info *ei = EXT2_I(dir); - ext2_dirent * de; - int dir_has_error = 0; - - if (npages == 0) - goto out; - - /* OFFSET_CACHE */ - *res_page = NULL; - - start = ei->i_dir_start_lookup; - if (start >= npages) - start = 0; - n = start; - do { - char *kaddr; - page = ext2_get_page(dir, n, dir_has_error); - if (!IS_ERR(page)) { - kaddr = page_address(page); - de = (ext2_dirent *) kaddr; - kaddr += ext2_last_byte(dir, n) - reclen; - while ((char *) de <= kaddr) { - if (de->rec_len == 0) { - ext2_error(dir->i_sb, __func__, - "zero-length directory entry"); - ext2_put_page(page); - goto out; - } - if (ext2_match (namelen, name, de)) - goto found; - de = ext2_next_entry(de); - } - ext2_put_page(page); - } else - dir_has_error = 1; - - if (++n >= npages) - n = 0; - /* next page is past the blocks we've got */ - if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) { - ext2_error(dir->i_sb, __func__, - "dir %lu size %lld exceeds block count %llu", - dir->i_ino, dir->i_size, - (unsigned long long)dir->i_blocks); - goto out; - } - } while (n != start); -out: - return NULL; - -found: - *res_page = page; - ei->i_dir_start_lookup = n; - return de; -} - -struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) -{ - struct page *page = ext2_get_page(dir, 0, 0); - ext2_dirent *de = NULL; - - if (!IS_ERR(page)) { - de = ext2_next_entry((ext2_dirent *) page_address(page)); - *p = page; - } - return de; -} - -ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child) -{ - ino_t res = 0; - struct ext2_dir_entry_2 *de; - struct page *page; - - de = ext2_find_entry (dir, child, &page); - if (de) { - res = le32_to_cpu(de->inode); - ext2_put_page(page); - } - return res; -} - -static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len) -{ - return __block_write_begin(page, pos, len, ext2_get_block); -} - -/* Releases the page */ -void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, - struct page *page, struct inode *inode, int update_times) -{ - loff_t pos = page_offset(page) + - (char *) de - (char *) page_address(page); - unsigned len = ext2_rec_len_from_disk(de->rec_len); - int err; - - lock_page(page); - err = ext2_prepare_chunk(page, pos, len); - BUG_ON(err); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type(de, inode); - err = ext2_commit_chunk(page, pos, len); - ext2_put_page(page); - if (update_times) - dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; - EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; - mark_inode_dirty(dir); -} - -/* - * Parent is locked. - */ -int ext2_add_link (struct dentry *dentry, struct inode *inode) -{ - struct inode *dir = dentry->d_parent->d_inode; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - unsigned chunk_size = ext2_chunk_size(dir); - unsigned reclen = EXT2_DIR_REC_LEN(namelen); - unsigned short rec_len, name_len; - struct page *page = NULL; - ext2_dirent * de; - unsigned long npages = dir_pages(dir); - unsigned long n; - char *kaddr; - loff_t pos; - int err; - - /* - * We take care of directory expansion in the same loop. - * This code plays outside i_size, so it locks the page - * to protect that region. - */ - for (n = 0; n <= npages; n++) { - char *dir_end; - - page = ext2_get_page(dir, n, 0); - err = PTR_ERR(page); - if (IS_ERR(page)) - goto out; - lock_page(page); - kaddr = page_address(page); - dir_end = kaddr + ext2_last_byte(dir, n); - de = (ext2_dirent *)kaddr; - kaddr += PAGE_CACHE_SIZE - reclen; - while ((char *)de <= kaddr) { - if ((char *)de == dir_end) { - /* We hit i_size */ - name_len = 0; - rec_len = chunk_size; - de->rec_len = ext2_rec_len_to_disk(chunk_size); - de->inode = 0; - goto got_it; - } - if (de->rec_len == 0) { - ext2_error(dir->i_sb, __func__, - "zero-length directory entry"); - err = -EIO; - goto out_unlock; - } - err = -EEXIST; - if (ext2_match (namelen, name, de)) - goto out_unlock; - name_len = EXT2_DIR_REC_LEN(de->name_len); - rec_len = ext2_rec_len_from_disk(de->rec_len); - if (!de->inode && rec_len >= reclen) - goto got_it; - if (rec_len >= name_len + reclen) - goto got_it; - de = (ext2_dirent *) ((char *) de + rec_len); - } - unlock_page(page); - ext2_put_page(page); - } - BUG(); - return -EINVAL; - -got_it: - pos = page_offset(page) + - (char*)de - (char*)page_address(page); - err = ext2_prepare_chunk(page, pos, rec_len); - if (err) - goto out_unlock; - if (de->inode) { - ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len); - de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len); - de->rec_len = ext2_rec_len_to_disk(name_len); - de = de1; - } - de->name_len = namelen; - memcpy(de->name, name, namelen); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - err = ext2_commit_chunk(page, pos, rec_len); - dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; - EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; - mark_inode_dirty(dir); - /* OFFSET_CACHE */ -out_put: - ext2_put_page(page); -out: - return err; -out_unlock: - unlock_page(page); - goto out_put; -} - -/* - * ext2_delete_entry deletes a directory entry by merging it with the - * previous entry. Page is up-to-date. Releases the page. - */ -int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) -{ - struct inode *inode = page->mapping->host; - char *kaddr = page_address(page); - unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); - unsigned to = ((char *)dir - kaddr) + - ext2_rec_len_from_disk(dir->rec_len); - loff_t pos; - ext2_dirent * pde = NULL; - ext2_dirent * de = (ext2_dirent *) (kaddr + from); - int err; - - while ((char*)de < (char*)dir) { - if (de->rec_len == 0) { - ext2_error(inode->i_sb, __func__, - "zero-length directory entry"); - err = -EIO; - goto out; - } - pde = de; - de = ext2_next_entry(de); - } - if (pde) - from = (char*)pde - (char*)page_address(page); - pos = page_offset(page) + from; - lock_page(page); - err = ext2_prepare_chunk(page, pos, to - from); - BUG_ON(err); - if (pde) - pde->rec_len = ext2_rec_len_to_disk(to - from); - dir->inode = 0; - err = ext2_commit_chunk(page, pos, to - from); - inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; - EXT2_I(inode)->i_flags &= ~EXT2_BTREE_FL; - mark_inode_dirty(inode); -out: - ext2_put_page(page); - return err; -} - -/* - * Set the first fragment of directory. - */ -int ext2_make_empty(struct inode *inode, struct inode *parent) -{ - struct page *page = grab_cache_page(inode->i_mapping, 0); - unsigned chunk_size = ext2_chunk_size(inode); - struct ext2_dir_entry_2 * de; - int err; - void *kaddr; - - if (!page) - return -ENOMEM; - - err = ext2_prepare_chunk(page, 0, chunk_size); - if (err) { - unlock_page(page); - goto fail; - } - kaddr = kmap_atomic(page); - memset(kaddr, 0, chunk_size); - de = (struct ext2_dir_entry_2 *)kaddr; - de->name_len = 1; - de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1)); - memcpy (de->name, ".\0\0", 4); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - - de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1)); - de->name_len = 2; - de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1)); - de->inode = cpu_to_le32(parent->i_ino); - memcpy (de->name, "..\0", 4); - ext2_set_de_type (de, inode); - kunmap_atomic(kaddr); - err = ext2_commit_chunk(page, 0, chunk_size); -fail: - page_cache_release(page); - return err; -} - -/* - * routine to check that the specified directory is empty (for rmdir) - */ -int ext2_empty_dir (struct inode * inode) -{ - struct page *page = NULL; - unsigned long i, npages = dir_pages(inode); - int dir_has_error = 0; - - for (i = 0; i < npages; i++) { - char *kaddr; - ext2_dirent * de; - page = ext2_get_page(inode, i, dir_has_error); - - if (IS_ERR(page)) { - dir_has_error = 1; - continue; - } - - kaddr = page_address(page); - de = (ext2_dirent *)kaddr; - kaddr += ext2_last_byte(inode, i) - EXT2_DIR_REC_LEN(1); - - while ((char *)de <= kaddr) { - if (de->rec_len == 0) { - ext2_error(inode->i_sb, __func__, - "zero-length directory entry"); - printk("kaddr=%p, de=%p\n", kaddr, de); - goto not_empty; - } - if (de->inode != 0) { - /* check for . and .. */ - if (de->name[0] != '.') - goto not_empty; - if (de->name_len > 2) - goto not_empty; - if (de->name_len < 2) { - if (de->inode != - cpu_to_le32(inode->i_ino)) - goto not_empty; - } else if (de->name[1] != '.') - goto not_empty; - } - de = ext2_next_entry(de); - } - ext2_put_page(page); - } - return 1; - -not_empty: - ext2_put_page(page); - return 0; -} - -const struct file_operations ext2_dir_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .readdir = ext2_readdir, - .unlocked_ioctl = ext2_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext2_compat_ioctl, -#endif - .fsync = ext2_fsync, -}; diff --git a/ANDROID_3.4.5/fs/ext2/ext2.h b/ANDROID_3.4.5/fs/ext2/ext2.h deleted file mode 100644 index 0b2b4db5..00000000 --- a/ANDROID_3.4.5/fs/ext2/ext2.h +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/include/linux/minix_fs.h - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ -#include <linux/fs.h> -#include <linux/ext2_fs.h> -#include <linux/blockgroup_lock.h> -#include <linux/percpu_counter.h> -#include <linux/rbtree.h> - -/* XXX Here for now... not interested in restructing headers JUST now */ - -/* data type for block offset of block group */ -typedef int ext2_grpblk_t; - -/* data type for filesystem-wide blocks number */ -typedef unsigned long ext2_fsblk_t; - -#define E2FSBLK "%lu" - -struct ext2_reserve_window { - ext2_fsblk_t _rsv_start; /* First byte reserved */ - ext2_fsblk_t _rsv_end; /* Last byte reserved or 0 */ -}; - -struct ext2_reserve_window_node { - struct rb_node rsv_node; - __u32 rsv_goal_size; - __u32 rsv_alloc_hit; - struct ext2_reserve_window rsv_window; -}; - -struct ext2_block_alloc_info { - /* information about reservation window */ - struct ext2_reserve_window_node rsv_window_node; - /* - * was i_next_alloc_block in ext2_inode_info - * is the logical (file-relative) number of the - * most-recently-allocated block in this file. - * We use this for detecting linearly ascending allocation requests. - */ - __u32 last_alloc_logical_block; - /* - * Was i_next_alloc_goal in ext2_inode_info - * is the *physical* companion to i_next_alloc_block. - * it the the physical block number of the block which was most-recentl - * allocated to this file. This give us the goal (target) for the next - * allocation when we detect linearly ascending requests. - */ - ext2_fsblk_t last_alloc_physical_block; -}; - -#define rsv_start rsv_window._rsv_start -#define rsv_end rsv_window._rsv_end - -/* - * second extended-fs super-block data in memory - */ -struct ext2_sb_info { - unsigned long s_frag_size; /* Size of a fragment in bytes */ - unsigned long s_frags_per_block;/* Number of fragments per block */ - unsigned long s_inodes_per_block;/* Number of inodes per block */ - unsigned long s_frags_per_group;/* Number of fragments in a group */ - unsigned long s_blocks_per_group;/* Number of blocks in a group */ - unsigned long s_inodes_per_group;/* Number of inodes in a group */ - unsigned long s_itb_per_group; /* Number of inode table blocks per group */ - unsigned long s_gdb_count; /* Number of group descriptor blocks */ - unsigned long s_desc_per_block; /* Number of group descriptors per block */ - unsigned long s_groups_count; /* Number of groups in the fs */ - unsigned long s_overhead_last; /* Last calculated overhead */ - unsigned long s_blocks_last; /* Last seen block count */ - struct buffer_head * s_sbh; /* Buffer containing the super block */ - struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */ - struct buffer_head ** s_group_desc; - unsigned long s_mount_opt; - unsigned long s_sb_block; - uid_t s_resuid; - gid_t s_resgid; - unsigned short s_mount_state; - unsigned short s_pad; - int s_addr_per_block_bits; - int s_desc_per_block_bits; - int s_inode_size; - int s_first_ino; - spinlock_t s_next_gen_lock; - u32 s_next_generation; - unsigned long s_dir_count; - u8 *s_debts; - struct percpu_counter s_freeblocks_counter; - struct percpu_counter s_freeinodes_counter; - struct percpu_counter s_dirs_counter; - struct blockgroup_lock *s_blockgroup_lock; - /* root of the per fs reservation window tree */ - spinlock_t s_rsv_window_lock; - struct rb_root s_rsv_window_root; - struct ext2_reserve_window_node s_rsv_window_head; - /* - * s_lock protects against concurrent modifications of s_mount_state, - * s_blocks_last, s_overhead_last and the content of superblock's - * buffer pointed to by sbi->s_es. - * - * Note: It is used in ext2_show_options() to provide a consistent view - * of the mount options. - */ - spinlock_t s_lock; -}; - -static inline spinlock_t * -sb_bgl_lock(struct ext2_sb_info *sbi, unsigned int block_group) -{ - return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group); -} - -/* - * Define EXT2FS_DEBUG to produce debug messages - */ -#undef EXT2FS_DEBUG - -/* - * Define EXT2_RESERVATION to reserve data blocks for expanding files - */ -#define EXT2_DEFAULT_RESERVE_BLOCKS 8 -/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */ -#define EXT2_MAX_RESERVE_BLOCKS 1027 -#define EXT2_RESERVE_WINDOW_NOT_ALLOCATED 0 -/* - * The second extended file system version - */ -#define EXT2FS_DATE "95/08/09" -#define EXT2FS_VERSION "0.5b" - -/* - * Debug code - */ -#ifdef EXT2FS_DEBUG -# define ext2_debug(f, a...) { \ - printk ("EXT2-fs DEBUG (%s, %d): %s:", \ - __FILE__, __LINE__, __func__); \ - printk (f, ## a); \ - } -#else -# define ext2_debug(f, a...) /**/ -#endif - -/* - * Special inode numbers - */ -#define EXT2_BAD_INO 1 /* Bad blocks inode */ -#define EXT2_ROOT_INO 2 /* Root inode */ -#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ -#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ - -/* First non-reserved inode for old ext2 filesystems */ -#define EXT2_GOOD_OLD_FIRST_INO 11 - -static inline struct ext2_sb_info *EXT2_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -/* - * Macro-instructions used to manage several block sizes - */ -#define EXT2_MIN_BLOCK_SIZE 1024 -#define EXT2_MAX_BLOCK_SIZE 4096 -#define EXT2_MIN_BLOCK_LOG_SIZE 10 -#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) -#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) -#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) -#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_addr_per_block_bits) -#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size) -#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino) - -/* - * Macro-instructions used to manage fragments - */ -#define EXT2_MIN_FRAG_SIZE 1024 -#define EXT2_MAX_FRAG_SIZE 4096 -#define EXT2_MIN_FRAG_LOG_SIZE 10 -#define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size) -#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block) - -/* - * Structure of a blocks group descriptor - */ -struct ext2_group_desc -{ - __le32 bg_block_bitmap; /* Blocks bitmap block */ - __le32 bg_inode_bitmap; /* Inodes bitmap block */ - __le32 bg_inode_table; /* Inodes table block */ - __le16 bg_free_blocks_count; /* Free blocks count */ - __le16 bg_free_inodes_count; /* Free inodes count */ - __le16 bg_used_dirs_count; /* Directories count */ - __le16 bg_pad; - __le32 bg_reserved[3]; -}; - -/* - * Macro-instructions used to manage group descriptors - */ -#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group) -#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block) -#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group) -#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits) - -/* - * Constants relative to the data blocks - */ -#define EXT2_NDIR_BLOCKS 12 -#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS -#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) -#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) -#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) - -/* - * Inode flags (GETFLAGS/SETFLAGS) - */ -#define EXT2_SECRM_FL FS_SECRM_FL /* Secure deletion */ -#define EXT2_UNRM_FL FS_UNRM_FL /* Undelete */ -#define EXT2_COMPR_FL FS_COMPR_FL /* Compress file */ -#define EXT2_SYNC_FL FS_SYNC_FL /* Synchronous updates */ -#define EXT2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */ -#define EXT2_APPEND_FL FS_APPEND_FL /* writes to file may only append */ -#define EXT2_NODUMP_FL FS_NODUMP_FL /* do not dump file */ -#define EXT2_NOATIME_FL FS_NOATIME_FL /* do not update atime */ -/* Reserved for compression usage... */ -#define EXT2_DIRTY_FL FS_DIRTY_FL -#define EXT2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */ -#define EXT2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */ -#define EXT2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */ -/* End compression flags --- maybe not all used */ -#define EXT2_BTREE_FL FS_BTREE_FL /* btree format dir */ -#define EXT2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */ -#define EXT2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */ -#define EXT2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */ -#define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */ -#define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ -#define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/ -#define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */ - -#define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */ -#define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */ - -/* Flags that should be inherited by new inodes from their parent. */ -#define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\ - EXT2_SYNC_FL | EXT2_NODUMP_FL |\ - EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\ - EXT2_NOCOMP_FL | EXT2_JOURNAL_DATA_FL |\ - EXT2_NOTAIL_FL | EXT2_DIRSYNC_FL) - -/* Flags that are appropriate for regular files (all but dir-specific ones). */ -#define EXT2_REG_FLMASK (~(EXT2_DIRSYNC_FL | EXT2_TOPDIR_FL)) - -/* Flags that are appropriate for non-directories/regular files. */ -#define EXT2_OTHER_FLMASK (EXT2_NODUMP_FL | EXT2_NOATIME_FL) - -/* Mask out flags that are inappropriate for the given type of inode. */ -static inline __u32 ext2_mask_flags(umode_t mode, __u32 flags) -{ - if (S_ISDIR(mode)) - return flags; - else if (S_ISREG(mode)) - return flags & EXT2_REG_FLMASK; - else - return flags & EXT2_OTHER_FLMASK; -} - -/* - * ioctl commands - */ -#define EXT2_IOC_GETFLAGS FS_IOC_GETFLAGS -#define EXT2_IOC_SETFLAGS FS_IOC_SETFLAGS -#define EXT2_IOC_GETVERSION FS_IOC_GETVERSION -#define EXT2_IOC_SETVERSION FS_IOC_SETVERSION -#define EXT2_IOC_GETRSVSZ _IOR('f', 5, long) -#define EXT2_IOC_SETRSVSZ _IOW('f', 6, long) - -/* - * ioctl commands in 32 bit emulation - */ -#define EXT2_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define EXT2_IOC32_SETFLAGS FS_IOC32_SETFLAGS -#define EXT2_IOC32_GETVERSION FS_IOC32_GETVERSION -#define EXT2_IOC32_SETVERSION FS_IOC32_SETVERSION - -/* - * Structure of an inode on the disk - */ -struct ext2_inode { - __le16 i_mode; /* File mode */ - __le16 i_uid; /* Low 16 bits of Owner Uid */ - __le32 i_size; /* Size in bytes */ - __le32 i_atime; /* Access time */ - __le32 i_ctime; /* Creation time */ - __le32 i_mtime; /* Modification time */ - __le32 i_dtime; /* Deletion Time */ - __le16 i_gid; /* Low 16 bits of Group Id */ - __le16 i_links_count; /* Links count */ - __le32 i_blocks; /* Blocks count */ - __le32 i_flags; /* File flags */ - union { - struct { - __le32 l_i_reserved1; - } linux1; - struct { - __le32 h_i_translator; - } hurd1; - struct { - __le32 m_i_reserved1; - } masix1; - } osd1; /* OS dependent 1 */ - __le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ - __le32 i_generation; /* File version (for NFS) */ - __le32 i_file_acl; /* File ACL */ - __le32 i_dir_acl; /* Directory ACL */ - __le32 i_faddr; /* Fragment address */ - union { - struct { - __u8 l_i_frag; /* Fragment number */ - __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ - __u32 l_i_reserved2; - } linux2; - struct { - __u8 h_i_frag; /* Fragment number */ - __u8 h_i_fsize; /* Fragment size */ - __le16 h_i_mode_high; - __le16 h_i_uid_high; - __le16 h_i_gid_high; - __le32 h_i_author; - } hurd2; - struct { - __u8 m_i_frag; /* Fragment number */ - __u8 m_i_fsize; /* Fragment size */ - __u16 m_pad1; - __u32 m_i_reserved2[2]; - } masix2; - } osd2; /* OS dependent 2 */ -}; - -#define i_size_high i_dir_acl - -#define i_reserved1 osd1.linux1.l_i_reserved1 -#define i_frag osd2.linux2.l_i_frag -#define i_fsize osd2.linux2.l_i_fsize -#define i_uid_low i_uid -#define i_gid_low i_gid -#define i_uid_high osd2.linux2.l_i_uid_high -#define i_gid_high osd2.linux2.l_i_gid_high -#define i_reserved2 osd2.linux2.l_i_reserved2 - -/* - * File system states - */ -#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ -#define EXT2_ERROR_FS 0x0002 /* Errors detected */ - -/* - * Mount flags - */ -#define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */ -#define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */ -#define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */ -#define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */ -#define EXT2_MOUNT_ERRORS_CONT 0x000010 /* Continue on errors */ -#define EXT2_MOUNT_ERRORS_RO 0x000020 /* Remount fs ro on errors */ -#define EXT2_MOUNT_ERRORS_PANIC 0x000040 /* Panic on errors */ -#define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */ -#define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */ -#define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */ -#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */ -#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */ -#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */ -#define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */ -#define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */ -#define EXT2_MOUNT_RESERVATION 0x080000 /* Preallocation */ - - -#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt -#define set_opt(o, opt) o |= EXT2_MOUNT_##opt -#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \ - EXT2_MOUNT_##opt) -/* - * Maximal mount counts between two filesystem checks - */ -#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ -#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ - -/* - * Behaviour when detecting errors - */ -#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ -#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ -#define EXT2_ERRORS_PANIC 3 /* Panic */ -#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE - -/* - * Structure of the super block - */ -struct ext2_super_block { - __le32 s_inodes_count; /* Inodes count */ - __le32 s_blocks_count; /* Blocks count */ - __le32 s_r_blocks_count; /* Reserved blocks count */ - __le32 s_free_blocks_count; /* Free blocks count */ - __le32 s_free_inodes_count; /* Free inodes count */ - __le32 s_first_data_block; /* First Data Block */ - __le32 s_log_block_size; /* Block size */ - __le32 s_log_frag_size; /* Fragment size */ - __le32 s_blocks_per_group; /* # Blocks per group */ - __le32 s_frags_per_group; /* # Fragments per group */ - __le32 s_inodes_per_group; /* # Inodes per group */ - __le32 s_mtime; /* Mount time */ - __le32 s_wtime; /* Write time */ - __le16 s_mnt_count; /* Mount count */ - __le16 s_max_mnt_count; /* Maximal mount count */ - __le16 s_magic; /* Magic signature */ - __le16 s_state; /* File system state */ - __le16 s_errors; /* Behaviour when detecting errors */ - __le16 s_minor_rev_level; /* minor revision level */ - __le32 s_lastcheck; /* time of last check */ - __le32 s_checkinterval; /* max. time between checks */ - __le32 s_creator_os; /* OS */ - __le32 s_rev_level; /* Revision level */ - __le16 s_def_resuid; /* Default uid for reserved blocks */ - __le16 s_def_resgid; /* Default gid for reserved blocks */ - /* - * These fields are for EXT2_DYNAMIC_REV superblocks only. - * - * Note: the difference between the compatible feature set and - * the incompatible feature set is that if there is a bit set - * in the incompatible feature set that the kernel doesn't - * know about, it should refuse to mount the filesystem. - * - * e2fsck's requirements are more strict; if it doesn't know - * about a feature in either the compatible or incompatible - * feature set, it must abort and not try to meddle with - * things it doesn't understand... - */ - __le32 s_first_ino; /* First non-reserved inode */ - __le16 s_inode_size; /* size of inode structure */ - __le16 s_block_group_nr; /* block group # of this superblock */ - __le32 s_feature_compat; /* compatible feature set */ - __le32 s_feature_incompat; /* incompatible feature set */ - __le32 s_feature_ro_compat; /* readonly-compatible feature set */ - __u8 s_uuid[16]; /* 128-bit uuid for volume */ - char s_volume_name[16]; /* volume name */ - char s_last_mounted[64]; /* directory where last mounted */ - __le32 s_algorithm_usage_bitmap; /* For compression */ - /* - * Performance hints. Directory preallocation should only - * happen if the EXT2_COMPAT_PREALLOC flag is on. - */ - __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ - __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __u16 s_padding1; - /* - * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. - */ - __u8 s_journal_uuid[16]; /* uuid of journal superblock */ - __u32 s_journal_inum; /* inode number of journal file */ - __u32 s_journal_dev; /* device number of journal file */ - __u32 s_last_orphan; /* start of list of inodes to delete */ - __u32 s_hash_seed[4]; /* HTREE hash seed */ - __u8 s_def_hash_version; /* Default hash version to use */ - __u8 s_reserved_char_pad; - __u16 s_reserved_word_pad; - __le32 s_default_mount_opts; - __le32 s_first_meta_bg; /* First metablock block group */ - __u32 s_reserved[190]; /* Padding to the end of the block */ -}; - -/* - * Codes for operating systems - */ -#define EXT2_OS_LINUX 0 -#define EXT2_OS_HURD 1 -#define EXT2_OS_MASIX 2 -#define EXT2_OS_FREEBSD 3 -#define EXT2_OS_LITES 4 - -/* - * Revision levels - */ -#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ -#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ - -#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV -#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV - -#define EXT2_GOOD_OLD_INODE_SIZE 128 - -/* - * Feature set definitions - */ - -#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ - ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) -#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ - ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) -#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ - ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) -#define EXT2_SET_COMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) -#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) -#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) -#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) -#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) -#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \ - EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) - -#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 -#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 -#define EXT2_FEATURE_COMPAT_ANY 0xffffffff - -#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 -#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff - -#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 -#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff - -#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR -#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ - EXT2_FEATURE_INCOMPAT_META_BG) -#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT2_FEATURE_RO_COMPAT_BTREE_DIR) -#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP -#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP - -/* - * Default values for user and/or group using reserved blocks - */ -#define EXT2_DEF_RESUID 0 -#define EXT2_DEF_RESGID 0 - -/* - * Default mount options - */ -#define EXT2_DEFM_DEBUG 0x0001 -#define EXT2_DEFM_BSDGROUPS 0x0002 -#define EXT2_DEFM_XATTR_USER 0x0004 -#define EXT2_DEFM_ACL 0x0008 -#define EXT2_DEFM_UID16 0x0010 - /* Not used by ext2, but reserved for use by ext3 */ -#define EXT3_DEFM_JMODE 0x0060 -#define EXT3_DEFM_JMODE_DATA 0x0020 -#define EXT3_DEFM_JMODE_ORDERED 0x0040 -#define EXT3_DEFM_JMODE_WBACK 0x0060 - -/* - * Structure of a directory entry - */ - -struct ext2_dir_entry { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __le16 name_len; /* Name length */ - char name[]; /* File name, up to EXT2_NAME_LEN */ -}; - -/* - * The new version of the directory entry. Since EXT2 structures are - * stored in intel byte order, and the name_len field could never be - * bigger than 255 chars, it's safe to reclaim the extra byte for the - * file_type field. - */ -struct ext2_dir_entry_2 { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __u8 name_len; /* Name length */ - __u8 file_type; - char name[]; /* File name, up to EXT2_NAME_LEN */ -}; - -/* - * Ext2 directory file types. Only the low 3 bits are used. The - * other bits are reserved for now. - */ -enum { - EXT2_FT_UNKNOWN = 0, - EXT2_FT_REG_FILE = 1, - EXT2_FT_DIR = 2, - EXT2_FT_CHRDEV = 3, - EXT2_FT_BLKDEV = 4, - EXT2_FT_FIFO = 5, - EXT2_FT_SOCK = 6, - EXT2_FT_SYMLINK = 7, - EXT2_FT_MAX -}; - -/* - * EXT2_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 4 - */ -#define EXT2_DIR_PAD 4 -#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) -#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ - ~EXT2_DIR_ROUND) -#define EXT2_MAX_REC_LEN ((1<<16)-1) - -static inline void verify_offsets(void) -{ -#define A(x,y) BUILD_BUG_ON(x != offsetof(struct ext2_super_block, y)); - A(EXT2_SB_MAGIC_OFFSET, s_magic); - A(EXT2_SB_BLOCKS_OFFSET, s_blocks_count); - A(EXT2_SB_BSIZE_OFFSET, s_log_block_size); -#undef A -} - -/* - * ext2 mount options - */ -struct ext2_mount_options { - unsigned long s_mount_opt; - uid_t s_resuid; - gid_t s_resgid; -}; - -/* - * second extended file system inode data in memory - */ -struct ext2_inode_info { - __le32 i_data[15]; - __u32 i_flags; - __u32 i_faddr; - __u8 i_frag_no; - __u8 i_frag_size; - __u16 i_state; - __u32 i_file_acl; - __u32 i_dir_acl; - __u32 i_dtime; - - /* - * i_block_group is the number of the block group which contains - * this file's inode. Constant across the lifetime of the inode, - * it is used for making block allocation decisions - we try to - * place a file's data blocks near its inode block, and new inodes - * near to their parent directory's inode. - */ - __u32 i_block_group; - - /* block reservation info */ - struct ext2_block_alloc_info *i_block_alloc_info; - - __u32 i_dir_start_lookup; -#ifdef CONFIG_EXT2_FS_XATTR - /* - * Extended attributes can be read independently of the main file - * data. Taking i_mutex even when reading would cause contention - * between readers of EAs and writers of regular file data, so - * instead we synchronize on xattr_sem when reading or changing - * EAs. - */ - struct rw_semaphore xattr_sem; -#endif - rwlock_t i_meta_lock; - - /* - * truncate_mutex is for serialising ext2_truncate() against - * ext2_getblock(). It also protects the internals of the inode's - * reservation data structures: ext2_reserve_window and - * ext2_reserve_window_node. - */ - struct mutex truncate_mutex; - struct inode vfs_inode; - struct list_head i_orphan; /* unlinked but open inodes */ -}; - -/* - * Inode dynamic state flags - */ -#define EXT2_STATE_NEW 0x00000001 /* inode is newly created */ - - -/* - * Function prototypes - */ - -/* - * Ok, these declarations are also in <linux/kernel.h> but none of the - * ext2 source programs needs to include it so they are duplicated here. - */ - -static inline struct ext2_inode_info *EXT2_I(struct inode *inode) -{ - return container_of(inode, struct ext2_inode_info, vfs_inode); -} - -/* balloc.c */ -extern int ext2_bg_has_super(struct super_block *sb, int group); -extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group); -extern ext2_fsblk_t ext2_new_block(struct inode *, unsigned long, int *); -extern ext2_fsblk_t ext2_new_blocks(struct inode *, unsigned long, - unsigned long *, int *); -extern void ext2_free_blocks (struct inode *, unsigned long, - unsigned long); -extern unsigned long ext2_count_free_blocks (struct super_block *); -extern unsigned long ext2_count_dirs (struct super_block *); -extern void ext2_check_blocks_bitmap (struct super_block *); -extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, - unsigned int block_group, - struct buffer_head ** bh); -extern void ext2_discard_reservation (struct inode *); -extern int ext2_should_retry_alloc(struct super_block *sb, int *retries); -extern void ext2_init_block_alloc_info(struct inode *); -extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv); - -/* dir.c */ -extern int ext2_add_link (struct dentry *, struct inode *); -extern ino_t ext2_inode_by_name(struct inode *, struct qstr *); -extern int ext2_make_empty(struct inode *, struct inode *); -extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, struct page **); -extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); -extern int ext2_empty_dir (struct inode *); -extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); -extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int); - -/* ialloc.c */ -extern struct inode * ext2_new_inode (struct inode *, umode_t, const struct qstr *); -extern void ext2_free_inode (struct inode *); -extern unsigned long ext2_count_free_inodes (struct super_block *); -extern void ext2_check_inodes_bitmap (struct super_block *); -extern unsigned long ext2_count_free (struct buffer_head *, unsigned); - -/* inode.c */ -extern struct inode *ext2_iget (struct super_block *, unsigned long); -extern int ext2_write_inode (struct inode *, struct writeback_control *); -extern void ext2_evict_inode(struct inode *); -extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int); -extern int ext2_setattr (struct dentry *, struct iattr *); -extern void ext2_set_inode_flags(struct inode *inode); -extern void ext2_get_inode_flags(struct ext2_inode_info *); -extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len); - -/* ioctl.c */ -extern long ext2_ioctl(struct file *, unsigned int, unsigned long); -extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); - -/* namei.c */ -struct dentry *ext2_get_parent(struct dentry *child); - -/* super.c */ -extern __printf(3, 4) -void ext2_error(struct super_block *, const char *, const char *, ...); -extern __printf(3, 4) -void ext2_msg(struct super_block *, const char *, const char *, ...); -extern void ext2_update_dynamic_rev (struct super_block *sb); -extern void ext2_write_super (struct super_block *); - -/* - * Inodes and files operations - */ - -/* dir.c */ -extern const struct file_operations ext2_dir_operations; - -/* file.c */ -extern int ext2_fsync(struct file *file, loff_t start, loff_t end, - int datasync); -extern const struct inode_operations ext2_file_inode_operations; -extern const struct file_operations ext2_file_operations; -extern const struct file_operations ext2_xip_file_operations; - -/* inode.c */ -extern const struct address_space_operations ext2_aops; -extern const struct address_space_operations ext2_aops_xip; -extern const struct address_space_operations ext2_nobh_aops; - -/* namei.c */ -extern const struct inode_operations ext2_dir_inode_operations; -extern const struct inode_operations ext2_special_inode_operations; - -/* symlink.c */ -extern const struct inode_operations ext2_fast_symlink_inode_operations; -extern const struct inode_operations ext2_symlink_inode_operations; - -static inline ext2_fsblk_t -ext2_group_first_block_no(struct super_block *sb, unsigned long group_no) -{ - return group_no * (ext2_fsblk_t)EXT2_BLOCKS_PER_GROUP(sb) + - le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block); -} - -#define ext2_set_bit __test_and_set_bit_le -#define ext2_clear_bit __test_and_clear_bit_le -#define ext2_test_bit test_bit_le -#define ext2_find_first_zero_bit find_first_zero_bit_le -#define ext2_find_next_zero_bit find_next_zero_bit_le diff --git a/ANDROID_3.4.5/fs/ext2/file.c b/ANDROID_3.4.5/fs/ext2/file.c deleted file mode 100644 index a5b3a5db..00000000 --- a/ANDROID_3.4.5/fs/ext2/file.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * linux/fs/ext2/file.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/file.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext2 fs regular file handling primitives - * - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - */ - -#include <linux/time.h> -#include <linux/pagemap.h> -#include <linux/quotaops.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" - -/* - * Called when filp is released. This happens when all file descriptors - * for a single struct file are closed. Note that different open() calls - * for the same file yield different struct file structures. - */ -static int ext2_release_file (struct inode * inode, struct file * filp) -{ - if (filp->f_mode & FMODE_WRITE) { - mutex_lock(&EXT2_I(inode)->truncate_mutex); - ext2_discard_reservation(inode); - mutex_unlock(&EXT2_I(inode)->truncate_mutex); - } - return 0; -} - -int ext2_fsync(struct file *file, loff_t start, loff_t end, int datasync) -{ - int ret; - struct super_block *sb = file->f_mapping->host->i_sb; - struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; - - ret = generic_file_fsync(file, start, end, datasync); - if (ret == -EIO || test_and_clear_bit(AS_EIO, &mapping->flags)) { - /* We don't really know where the IO error happened... */ - ext2_error(sb, __func__, - "detected IO error when writing metadata buffers"); - ret = -EIO; - } - return ret; -} - -/* - * We have mostly NULL's here: the current defaults are ok for - * the ext2 filesystem. - */ -const struct file_operations ext2_file_operations = { - .llseek = generic_file_llseek, - .read = do_sync_read, - .write = do_sync_write, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, - .unlocked_ioctl = ext2_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext2_compat_ioctl, -#endif - .mmap = generic_file_mmap, - .open = dquot_file_open, - .release = ext2_release_file, - .fsync = ext2_fsync, - .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, -}; - -#ifdef CONFIG_EXT2_FS_XIP -const struct file_operations ext2_xip_file_operations = { - .llseek = generic_file_llseek, - .read = xip_file_read, - .write = xip_file_write, - .unlocked_ioctl = ext2_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext2_compat_ioctl, -#endif - .mmap = xip_file_mmap, - .open = dquot_file_open, - .release = ext2_release_file, - .fsync = ext2_fsync, -}; -#endif - -const struct inode_operations ext2_file_inode_operations = { -#ifdef CONFIG_EXT2_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext2_listxattr, - .removexattr = generic_removexattr, -#endif - .setattr = ext2_setattr, - .get_acl = ext2_get_acl, - .fiemap = ext2_fiemap, -}; diff --git a/ANDROID_3.4.5/fs/ext2/ialloc.c b/ANDROID_3.4.5/fs/ext2/ialloc.c deleted file mode 100644 index 8b15cf8c..00000000 --- a/ANDROID_3.4.5/fs/ext2/ialloc.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * linux/fs/ext2/ialloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * BSD ufs-inspired inode and directory allocation by - * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include <linux/quotaops.h> -#include <linux/sched.h> -#include <linux/backing-dev.h> -#include <linux/buffer_head.h> -#include <linux/random.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" - -/* - * ialloc.c contains the inodes allocation and deallocation routines - */ - -/* - * The free inodes are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. - */ - - -/* - * Read the inode allocation bitmap for a given block_group, reading - * into the specified slot in the superblock's bitmap cache. - * - * Return buffer_head of bitmap on success or NULL. - */ -static struct buffer_head * -read_inode_bitmap(struct super_block * sb, unsigned long block_group) -{ - struct ext2_group_desc *desc; - struct buffer_head *bh = NULL; - - desc = ext2_get_group_desc(sb, block_group, NULL); - if (!desc) - goto error_out; - - bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); - if (!bh) - ext2_error(sb, "read_inode_bitmap", - "Cannot read inode bitmap - " - "block_group = %lu, inode_bitmap = %u", - block_group, le32_to_cpu(desc->bg_inode_bitmap)); -error_out: - return bh; -} - -static void ext2_release_inode(struct super_block *sb, int group, int dir) -{ - struct ext2_group_desc * desc; - struct buffer_head *bh; - - desc = ext2_get_group_desc(sb, group, &bh); - if (!desc) { - ext2_error(sb, "ext2_release_inode", - "can't get descriptor for group %d", group); - return; - } - - spin_lock(sb_bgl_lock(EXT2_SB(sb), group)); - le16_add_cpu(&desc->bg_free_inodes_count, 1); - if (dir) - le16_add_cpu(&desc->bg_used_dirs_count, -1); - spin_unlock(sb_bgl_lock(EXT2_SB(sb), group)); - if (dir) - percpu_counter_dec(&EXT2_SB(sb)->s_dirs_counter); - sb->s_dirt = 1; - mark_buffer_dirty(bh); -} - -/* - * NOTE! When we get the inode, we're the only people - * that have access to it, and as such there are no - * race conditions we have to worry about. The inode - * is not on the hash-lists, and it cannot be reached - * through the filesystem because the directory entry - * has been deleted earlier. - * - * HOWEVER: we must make sure that we get no aliases, - * which means that we have to call "clear_inode()" - * _before_ we mark the inode not in use in the inode - * bitmaps. Otherwise a newly created file might use - * the same inode number (not actually the same pointer - * though), and then we'd have two inodes sharing the - * same inode number and space on the harddisk. - */ -void ext2_free_inode (struct inode * inode) -{ - struct super_block * sb = inode->i_sb; - int is_directory; - unsigned long ino; - struct buffer_head *bitmap_bh; - unsigned long block_group; - unsigned long bit; - struct ext2_super_block * es; - - ino = inode->i_ino; - ext2_debug ("freeing inode %lu\n", ino); - - /* - * Note: we must free any quota before locking the superblock, - * as writing the quota to disk may need the lock as well. - */ - /* Quota is already initialized in iput() */ - ext2_xattr_delete_inode(inode); - dquot_free_inode(inode); - dquot_drop(inode); - - es = EXT2_SB(sb)->s_es; - is_directory = S_ISDIR(inode->i_mode); - - if (ino < EXT2_FIRST_INO(sb) || - ino > le32_to_cpu(es->s_inodes_count)) { - ext2_error (sb, "ext2_free_inode", - "reserved or nonexistent inode %lu", ino); - return; - } - block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb); - bitmap_bh = read_inode_bitmap(sb, block_group); - if (!bitmap_bh) - return; - - /* Ok, now we can actually update the inode bitmaps.. */ - if (!ext2_clear_bit_atomic(sb_bgl_lock(EXT2_SB(sb), block_group), - bit, (void *) bitmap_bh->b_data)) - ext2_error (sb, "ext2_free_inode", - "bit already cleared for inode %lu", ino); - else - ext2_release_inode(sb, block_group, is_directory); - mark_buffer_dirty(bitmap_bh); - if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); - - brelse(bitmap_bh); -} - -/* - * We perform asynchronous prereading of the new inode's inode block when - * we create the inode, in the expectation that the inode will be written - * back soon. There are two reasons: - * - * - When creating a large number of files, the async prereads will be - * nicely merged into large reads - * - When writing out a large number of inodes, we don't need to keep on - * stalling the writes while we read the inode block. - * - * FIXME: ext2_get_group_desc() needs to be simplified. - */ -static void ext2_preread_inode(struct inode *inode) -{ - unsigned long block_group; - unsigned long offset; - unsigned long block; - struct ext2_group_desc * gdp; - struct backing_dev_info *bdi; - - bdi = inode->i_mapping->backing_dev_info; - if (bdi_read_congested(bdi)) - return; - if (bdi_write_congested(bdi)) - return; - - block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); - gdp = ext2_get_group_desc(inode->i_sb, block_group, NULL); - if (gdp == NULL) - return; - - /* - * Figure out the offset within the block group inode table - */ - offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) * - EXT2_INODE_SIZE(inode->i_sb); - block = le32_to_cpu(gdp->bg_inode_table) + - (offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); - sb_breadahead(inode->i_sb, block); -} - -/* - * There are two policies for allocating an inode. If the new inode is - * a directory, then a forward search is made for a block group with both - * free space and a low directory-to-inode ratio; if that fails, then of - * the groups with above-average free space, that group with the fewest - * directories already is chosen. - * - * For other inodes, search forward from the parent directory\'s block - * group to find a free inode. - */ -static int find_group_dir(struct super_block *sb, struct inode *parent) -{ - int ngroups = EXT2_SB(sb)->s_groups_count; - int avefreei = ext2_count_free_inodes(sb) / ngroups; - struct ext2_group_desc *desc, *best_desc = NULL; - int group, best_group = -1; - - for (group = 0; group < ngroups; group++) { - desc = ext2_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) - continue; - if (!best_desc || - (le16_to_cpu(desc->bg_free_blocks_count) > - le16_to_cpu(best_desc->bg_free_blocks_count))) { - best_group = group; - best_desc = desc; - } - } - if (!best_desc) - return -1; - - return best_group; -} - -/* - * Orlov's allocator for directories. - * - * We always try to spread first-level directories. - * - * If there are blockgroups with both free inodes and free blocks counts - * not worse than average we return one with smallest directory count. - * Otherwise we simply return a random group. - * - * For the rest rules look so: - * - * It's OK to put directory into a group unless - * it has too many directories already (max_dirs) or - * it has too few free inodes left (min_inodes) or - * it has too few free blocks left (min_blocks) or - * it's already running too large debt (max_debt). - * Parent's group is preferred, if it doesn't satisfy these - * conditions we search cyclically through the rest. If none - * of the groups look good we just look for a group with more - * free inodes than average (starting at parent's group). - * - * Debt is incremented each time we allocate a directory and decremented - * when we allocate an inode, within 0--255. - */ - -#define INODE_COST 64 -#define BLOCK_COST 256 - -static int find_group_orlov(struct super_block *sb, struct inode *parent) -{ - int parent_group = EXT2_I(parent)->i_block_group; - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - int ngroups = sbi->s_groups_count; - int inodes_per_group = EXT2_INODES_PER_GROUP(sb); - int freei; - int avefreei; - int free_blocks; - int avefreeb; - int blocks_per_dir; - int ndirs; - int max_debt, max_dirs, min_blocks, min_inodes; - int group = -1, i; - struct ext2_group_desc *desc; - - freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); - avefreei = freei / ngroups; - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - avefreeb = free_blocks / ngroups; - ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); - - if ((parent == sb->s_root->d_inode) || - (EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) { - struct ext2_group_desc *best_desc = NULL; - int best_ndir = inodes_per_group; - int best_group = -1; - - get_random_bytes(&group, sizeof(group)); - parent_group = (unsigned)group % ngroups; - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) - continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) - continue; - best_group = group; - best_ndir = le16_to_cpu(desc->bg_used_dirs_count); - best_desc = desc; - } - if (best_group >= 0) { - desc = best_desc; - group = best_group; - goto found; - } - goto fallback; - } - - if (ndirs == 0) - ndirs = 1; /* percpu_counters are approximate... */ - - blocks_per_dir = (le32_to_cpu(es->s_blocks_count)-free_blocks) / ndirs; - - max_dirs = ndirs / ngroups + inodes_per_group / 16; - min_inodes = avefreei - inodes_per_group / 4; - min_blocks = avefreeb - EXT2_BLOCKS_PER_GROUP(sb) / 4; - - max_debt = EXT2_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST); - if (max_debt * INODE_COST > inodes_per_group) - max_debt = inodes_per_group / INODE_COST; - if (max_debt > 255) - max_debt = 255; - if (max_debt == 0) - max_debt = 1; - - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (sbi->s_debts[group] >= max_debt) - continue; - if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) - continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) - continue; - goto found; - } - -fallback: - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext2_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) - goto found; - } - - if (avefreei) { - /* - * The free-inodes counter is approximate, and for really small - * filesystems the above test can fail to find any blockgroups - */ - avefreei = 0; - goto fallback; - } - - return -1; - -found: - return group; -} - -static int find_group_other(struct super_block *sb, struct inode *parent) -{ - int parent_group = EXT2_I(parent)->i_block_group; - int ngroups = EXT2_SB(sb)->s_groups_count; - struct ext2_group_desc *desc; - int group, i; - - /* - * Try to place the inode in its parent directory - */ - group = parent_group; - desc = ext2_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count) && - le16_to_cpu(desc->bg_free_blocks_count)) - goto found; - - /* - * We're going to place this inode in a different blockgroup from its - * parent. We want to cause files in a common directory to all land in - * the same blockgroup. But we want files which are in a different - * directory which shares a blockgroup with our parent to land in a - * different blockgroup. - * - * So add our directory's i_ino into the starting point for the hash. - */ - group = (group + parent->i_ino) % ngroups; - - /* - * Use a quadratic hash to find a group with a free inode and some - * free blocks. - */ - for (i = 1; i < ngroups; i <<= 1) { - group += i; - if (group >= ngroups) - group -= ngroups; - desc = ext2_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count) && - le16_to_cpu(desc->bg_free_blocks_count)) - goto found; - } - - /* - * That failed: try linear search for a free inode, even if that group - * has no free blocks. - */ - group = parent_group; - for (i = 0; i < ngroups; i++) { - if (++group >= ngroups) - group = 0; - desc = ext2_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count)) - goto found; - } - - return -1; - -found: - return group; -} - -struct inode *ext2_new_inode(struct inode *dir, umode_t mode, - const struct qstr *qstr) -{ - struct super_block *sb; - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *bh2; - int group, i; - ino_t ino = 0; - struct inode * inode; - struct ext2_group_desc *gdp; - struct ext2_super_block *es; - struct ext2_inode_info *ei; - struct ext2_sb_info *sbi; - int err; - - sb = dir->i_sb; - inode = new_inode(sb); - if (!inode) - return ERR_PTR(-ENOMEM); - - ei = EXT2_I(inode); - sbi = EXT2_SB(sb); - es = sbi->s_es; - if (S_ISDIR(mode)) { - if (test_opt(sb, OLDALLOC)) - group = find_group_dir(sb, dir); - else - group = find_group_orlov(sb, dir); - } else - group = find_group_other(sb, dir); - - if (group == -1) { - err = -ENOSPC; - goto fail; - } - - for (i = 0; i < sbi->s_groups_count; i++) { - gdp = ext2_get_group_desc(sb, group, &bh2); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) { - err = -EIO; - goto fail; - } - ino = 0; - -repeat_in_this_group: - ino = ext2_find_next_zero_bit((unsigned long *)bitmap_bh->b_data, - EXT2_INODES_PER_GROUP(sb), ino); - if (ino >= EXT2_INODES_PER_GROUP(sb)) { - /* - * Rare race: find_group_xx() decided that there were - * free inodes in this group, but by the time we tried - * to allocate one, they're all gone. This can also - * occur because the counters which find_group_orlov() - * uses are approximate. So just go and search the - * next block group. - */ - if (++group == sbi->s_groups_count) - group = 0; - continue; - } - if (ext2_set_bit_atomic(sb_bgl_lock(sbi, group), - ino, bitmap_bh->b_data)) { - /* we lost this inode */ - if (++ino >= EXT2_INODES_PER_GROUP(sb)) { - /* this group is exhausted, try next group */ - if (++group == sbi->s_groups_count) - group = 0; - continue; - } - /* try to find free inode in the same group */ - goto repeat_in_this_group; - } - goto got; - } - - /* - * Scanned all blockgroups. - */ - err = -ENOSPC; - goto fail; -got: - mark_buffer_dirty(bitmap_bh); - if (sb->s_flags & MS_SYNCHRONOUS) - sync_dirty_buffer(bitmap_bh); - brelse(bitmap_bh); - - ino += group * EXT2_INODES_PER_GROUP(sb) + 1; - if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext2_error (sb, "ext2_new_inode", - "reserved inode or inode > inodes count - " - "block_group = %d,inode=%lu", group, - (unsigned long) ino); - err = -EIO; - goto fail; - } - - percpu_counter_add(&sbi->s_freeinodes_counter, -1); - if (S_ISDIR(mode)) - percpu_counter_inc(&sbi->s_dirs_counter); - - spin_lock(sb_bgl_lock(sbi, group)); - le16_add_cpu(&gdp->bg_free_inodes_count, -1); - if (S_ISDIR(mode)) { - if (sbi->s_debts[group] < 255) - sbi->s_debts[group]++; - le16_add_cpu(&gdp->bg_used_dirs_count, 1); - } else { - if (sbi->s_debts[group]) - sbi->s_debts[group]--; - } - spin_unlock(sb_bgl_lock(sbi, group)); - - sb->s_dirt = 1; - mark_buffer_dirty(bh2); - if (test_opt(sb, GRPID)) { - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = dir->i_gid; - } else - inode_init_owner(inode, dir, mode); - - inode->i_ino = ino; - inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_flags = - ext2_mask_flags(mode, EXT2_I(dir)->i_flags & EXT2_FL_INHERITED); - ei->i_faddr = 0; - ei->i_frag_no = 0; - ei->i_frag_size = 0; - ei->i_file_acl = 0; - ei->i_dir_acl = 0; - ei->i_dtime = 0; - ei->i_block_alloc_info = NULL; - ei->i_block_group = group; - ei->i_dir_start_lookup = 0; - ei->i_state = EXT2_STATE_NEW; - ext2_set_inode_flags(inode); - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; - spin_unlock(&sbi->s_next_gen_lock); - if (insert_inode_locked(inode) < 0) { - ext2_error(sb, "ext2_new_inode", - "inode number already in use - inode=%lu", - (unsigned long) ino); - err = -EIO; - goto fail; - } - - dquot_initialize(inode); - err = dquot_alloc_inode(inode); - if (err) - goto fail_drop; - - err = ext2_init_acl(inode, dir); - if (err) - goto fail_free_drop; - - err = ext2_init_security(inode, dir, qstr); - if (err) - goto fail_free_drop; - - mark_inode_dirty(inode); - ext2_debug("allocating inode %lu\n", inode->i_ino); - ext2_preread_inode(inode); - return inode; - -fail_free_drop: - dquot_free_inode(inode); - -fail_drop: - dquot_drop(inode); - inode->i_flags |= S_NOQUOTA; - clear_nlink(inode); - unlock_new_inode(inode); - iput(inode); - return ERR_PTR(err); - -fail: - make_bad_inode(inode); - iput(inode); - return ERR_PTR(err); -} - -unsigned long ext2_count_free_inodes (struct super_block * sb) -{ - struct ext2_group_desc *desc; - unsigned long desc_count = 0; - int i; - -#ifdef EXT2FS_DEBUG - struct ext2_super_block *es; - unsigned long bitmap_count = 0; - struct buffer_head *bitmap_bh = NULL; - - es = EXT2_SB(sb)->s_es; - for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - unsigned x; - - desc = ext2_get_group_desc (sb, i, NULL); - if (!desc) - continue; - desc_count += le16_to_cpu(desc->bg_free_inodes_count); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, i); - if (!bitmap_bh) - continue; - - x = ext2_count_free(bitmap_bh, EXT2_INODES_PER_GROUP(sb) / 8); - printk("group %d: stored = %d, counted = %u\n", - i, le16_to_cpu(desc->bg_free_inodes_count), x); - bitmap_count += x; - } - brelse(bitmap_bh); - printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", - percpu_counter_read(&EXT2_SB(sb)->s_freeinodes_counter), - desc_count, bitmap_count); - return desc_count; -#else - for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - desc = ext2_get_group_desc (sb, i, NULL); - if (!desc) - continue; - desc_count += le16_to_cpu(desc->bg_free_inodes_count); - } - return desc_count; -#endif -} - -/* Called at mount-time, super-block is locked */ -unsigned long ext2_count_dirs (struct super_block * sb) -{ - unsigned long count = 0; - int i; - - for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++) { - struct ext2_group_desc *gdp = ext2_get_group_desc (sb, i, NULL); - if (!gdp) - continue; - count += le16_to_cpu(gdp->bg_used_dirs_count); - } - return count; -} - diff --git a/ANDROID_3.4.5/fs/ext2/inode.c b/ANDROID_3.4.5/fs/ext2/inode.c deleted file mode 100644 index 740cad8d..00000000 --- a/ANDROID_3.4.5/fs/ext2/inode.c +++ /dev/null @@ -1,1549 +0,0 @@ -/* - * linux/fs/ext2/inode.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Goal-directed block allocation by Stephen Tweedie - * (sct@dcs.ed.ac.uk), 1993, 1998 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - * - * Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000 - */ - -#include <linux/time.h> -#include <linux/highuid.h> -#include <linux/pagemap.h> -#include <linux/quotaops.h> -#include <linux/writeback.h> -#include <linux/buffer_head.h> -#include <linux/mpage.h> -#include <linux/fiemap.h> -#include <linux/namei.h> -#include "ext2.h" -#include "acl.h" -#include "xip.h" - -static int __ext2_write_inode(struct inode *inode, int do_sync); - -/* - * Test whether an inode is a fast symlink. - */ -static inline int ext2_inode_is_fast_symlink(struct inode *inode) -{ - int ea_blocks = EXT2_I(inode)->i_file_acl ? - (inode->i_sb->s_blocksize >> 9) : 0; - - return (S_ISLNK(inode->i_mode) && - inode->i_blocks - ea_blocks == 0); -} - -static void ext2_truncate_blocks(struct inode *inode, loff_t offset); - -static void ext2_write_failed(struct address_space *mapping, loff_t to) -{ - struct inode *inode = mapping->host; - - if (to > inode->i_size) { - truncate_pagecache(inode, to, inode->i_size); - ext2_truncate_blocks(inode, inode->i_size); - } -} - -/* - * Called at the last iput() if i_nlink is zero. - */ -void ext2_evict_inode(struct inode * inode) -{ - struct ext2_block_alloc_info *rsv; - int want_delete = 0; - - if (!inode->i_nlink && !is_bad_inode(inode)) { - want_delete = 1; - dquot_initialize(inode); - } else { - dquot_drop(inode); - } - - truncate_inode_pages(&inode->i_data, 0); - - if (want_delete) { - /* set dtime */ - EXT2_I(inode)->i_dtime = get_seconds(); - mark_inode_dirty(inode); - __ext2_write_inode(inode, inode_needs_sync(inode)); - /* truncate to 0 */ - inode->i_size = 0; - if (inode->i_blocks) - ext2_truncate_blocks(inode, 0); - } - - invalidate_inode_buffers(inode); - end_writeback(inode); - - ext2_discard_reservation(inode); - rsv = EXT2_I(inode)->i_block_alloc_info; - EXT2_I(inode)->i_block_alloc_info = NULL; - if (unlikely(rsv)) - kfree(rsv); - - if (want_delete) - ext2_free_inode(inode); -} - -typedef struct { - __le32 *p; - __le32 key; - struct buffer_head *bh; -} Indirect; - -static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) -{ - p->key = *(p->p = v); - p->bh = bh; -} - -static inline int verify_chain(Indirect *from, Indirect *to) -{ - while (from <= to && from->key == *from->p) - from++; - return (from > to); -} - -/** - * ext2_block_to_path - parse the block number into array of offsets - * @inode: inode in question (we are only interested in its superblock) - * @i_block: block number to be parsed - * @offsets: array to store the offsets in - * @boundary: set this non-zero if the referred-to block is likely to be - * followed (on disk) by an indirect block. - * To store the locations of file's data ext2 uses a data structure common - * for UNIX filesystems - tree of pointers anchored in the inode, with - * data blocks at leaves and indirect blocks in intermediate nodes. - * This function translates the block number into path in that tree - - * return value is the path length and @offsets[n] is the offset of - * pointer to (n+1)th node in the nth one. If @block is out of range - * (negative or too large) warning is printed and zero returned. - * - * Note: function doesn't find node addresses, so no IO is needed. All - * we need to know is the capacity of indirect blocks (taken from the - * inode->i_sb). - */ - -/* - * Portability note: the last comparison (check that we fit into triple - * indirect block) is spelled differently, because otherwise on an - * architecture with 32-bit longs and 8Kb pages we might get into trouble - * if our filesystem had 8Kb blocks. We might use long long, but that would - * kill us on x86. Oh, well, at least the sign propagation does not matter - - * i_block would have to be negative in the very beginning, so we would not - * get there at all. - */ - -static int ext2_block_to_path(struct inode *inode, - long i_block, int offsets[4], int *boundary) -{ - int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT2_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)); - int n = 0; - int final = 0; - - if (i_block < 0) { - ext2_msg(inode->i_sb, KERN_WARNING, - "warning: %s: block < 0", __func__); - } else if (i_block < direct_blocks) { - offsets[n++] = i_block; - final = direct_blocks; - } else if ( (i_block -= direct_blocks) < indirect_blocks) { - offsets[n++] = EXT2_IND_BLOCK; - offsets[n++] = i_block; - final = ptrs; - } else if ((i_block -= indirect_blocks) < double_blocks) { - offsets[n++] = EXT2_DIND_BLOCK; - offsets[n++] = i_block >> ptrs_bits; - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { - offsets[n++] = EXT2_TIND_BLOCK; - offsets[n++] = i_block >> (ptrs_bits * 2); - offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else { - ext2_msg(inode->i_sb, KERN_WARNING, - "warning: %s: block is too big", __func__); - } - if (boundary) - *boundary = final - 1 - (i_block & (ptrs - 1)); - - return n; -} - -/** - * ext2_get_branch - read the chain of indirect blocks leading to data - * @inode: inode in question - * @depth: depth of the chain (1 - direct pointer, etc.) - * @offsets: offsets of pointers in inode/indirect blocks - * @chain: place to store the result - * @err: here we store the error value - * - * Function fills the array of triples <key, p, bh> and returns %NULL - * if everything went OK or the pointer to the last filled triple - * (incomplete one) otherwise. Upon the return chain[i].key contains - * the number of (i+1)-th block in the chain (as it is stored in memory, - * i.e. little-endian 32-bit), chain[i].p contains the address of that - * number (it points into struct inode for i==0 and into the bh->b_data - * for i>0) and chain[i].bh points to the buffer_head of i-th indirect - * block for i>0 and NULL for i==0. In other words, it holds the block - * numbers of the chain, addresses they were taken from (and where we can - * verify that chain did not change) and buffer_heads hosting these - * numbers. - * - * Function stops when it stumbles upon zero pointer (absent block) - * (pointer to last triple returned, *@err == 0) - * or when it gets an IO error reading an indirect block - * (ditto, *@err == -EIO) - * or when it notices that chain had been changed while it was reading - * (ditto, *@err == -EAGAIN) - * or when it reads all @depth-1 indirect blocks successfully and finds - * the whole chain, all way to the data (returns %NULL, *err == 0). - */ -static Indirect *ext2_get_branch(struct inode *inode, - int depth, - int *offsets, - Indirect chain[4], - int *err) -{ - struct super_block *sb = inode->i_sb; - Indirect *p = chain; - struct buffer_head *bh; - - *err = 0; - /* i_data is not going away, no lock needed */ - add_chain (chain, NULL, EXT2_I(inode)->i_data + *offsets); - if (!p->key) - goto no_block; - while (--depth) { - bh = sb_bread(sb, le32_to_cpu(p->key)); - if (!bh) - goto failure; - read_lock(&EXT2_I(inode)->i_meta_lock); - if (!verify_chain(chain, p)) - goto changed; - add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); - read_unlock(&EXT2_I(inode)->i_meta_lock); - if (!p->key) - goto no_block; - } - return NULL; - -changed: - read_unlock(&EXT2_I(inode)->i_meta_lock); - brelse(bh); - *err = -EAGAIN; - goto no_block; -failure: - *err = -EIO; -no_block: - return p; -} - -/** - * ext2_find_near - find a place for allocation with sufficient locality - * @inode: owner - * @ind: descriptor of indirect block. - * - * This function returns the preferred place for block allocation. - * It is used when heuristic for sequential allocation fails. - * Rules are: - * + if there is a block to the left of our position - allocate near it. - * + if pointer will live in indirect block - allocate near that block. - * + if pointer will live in inode - allocate in the same cylinder group. - * - * In the latter case we colour the starting block by the callers PID to - * prevent it from clashing with concurrent allocations for a different inode - * in the same block group. The PID is used here so that functionally related - * files will be close-by on-disk. - * - * Caller must make sure that @ind is valid and will stay that way. - */ - -static ext2_fsblk_t ext2_find_near(struct inode *inode, Indirect *ind) -{ - struct ext2_inode_info *ei = EXT2_I(inode); - __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; - __le32 *p; - ext2_fsblk_t bg_start; - ext2_fsblk_t colour; - - /* Try to find previous block */ - for (p = ind->p - 1; p >= start; p--) - if (*p) - return le32_to_cpu(*p); - - /* No such thing, so let's try location of indirect block */ - if (ind->bh) - return ind->bh->b_blocknr; - - /* - * It is going to be referred from inode itself? OK, just put it into - * the same cylinder group then. - */ - bg_start = ext2_group_first_block_no(inode->i_sb, ei->i_block_group); - colour = (current->pid % 16) * - (EXT2_BLOCKS_PER_GROUP(inode->i_sb) / 16); - return bg_start + colour; -} - -/** - * ext2_find_goal - find a preferred place for allocation. - * @inode: owner - * @block: block we want - * @partial: pointer to the last triple within a chain - * - * Returns preferred place for a block (the goal). - */ - -static inline ext2_fsblk_t ext2_find_goal(struct inode *inode, long block, - Indirect *partial) -{ - struct ext2_block_alloc_info *block_i; - - block_i = EXT2_I(inode)->i_block_alloc_info; - - /* - * try the heuristic for sequential allocation, - * failing that at least try to get decent locality. - */ - if (block_i && (block == block_i->last_alloc_logical_block + 1) - && (block_i->last_alloc_physical_block != 0)) { - return block_i->last_alloc_physical_block + 1; - } - - return ext2_find_near(inode, partial); -} - -/** - * ext2_blks_to_allocate: Look up the block map and count the number - * of direct blocks need to be allocated for the given branch. - * - * @branch: chain of indirect blocks - * @k: number of blocks need for indirect blocks - * @blks: number of data blocks to be mapped. - * @blocks_to_boundary: the offset in the indirect block - * - * return the total number of blocks to be allocate, including the - * direct and indirect blocks. - */ -static int -ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks, - int blocks_to_boundary) -{ - unsigned long count = 0; - - /* - * Simple case, [t,d]Indirect block(s) has not allocated yet - * then it's clear blocks on that path have not allocated - */ - if (k > 0) { - /* right now don't hanel cross boundary allocation */ - if (blks < blocks_to_boundary + 1) - count += blks; - else - count += blocks_to_boundary + 1; - return count; - } - - count++; - while (count < blks && count <= blocks_to_boundary - && le32_to_cpu(*(branch[0].p + count)) == 0) { - count++; - } - return count; -} - -/** - * ext2_alloc_blocks: multiple allocate blocks needed for a branch - * @indirect_blks: the number of blocks need to allocate for indirect - * blocks - * - * @new_blocks: on return it will store the new block numbers for - * the indirect blocks(if needed) and the first direct block, - * @blks: on return it will store the total number of allocated - * direct blocks - */ -static int ext2_alloc_blocks(struct inode *inode, - ext2_fsblk_t goal, int indirect_blks, int blks, - ext2_fsblk_t new_blocks[4], int *err) -{ - int target, i; - unsigned long count = 0; - int index = 0; - ext2_fsblk_t current_block = 0; - int ret = 0; - - /* - * Here we try to allocate the requested multiple blocks at once, - * on a best-effort basis. - * To build a branch, we should allocate blocks for - * the indirect blocks(if not allocated yet), and at least - * the first direct block of this branch. That's the - * minimum number of blocks need to allocate(required) - */ - target = blks + indirect_blks; - - while (1) { - count = target; - /* allocating blocks for indirect blocks and direct blocks */ - current_block = ext2_new_blocks(inode,goal,&count,err); - if (*err) - goto failed_out; - - target -= count; - /* allocate blocks for indirect blocks */ - while (index < indirect_blks && count) { - new_blocks[index++] = current_block++; - count--; - } - - if (count > 0) - break; - } - - /* save the new block number for the first direct block */ - new_blocks[index] = current_block; - - /* total number of blocks allocated for direct blocks */ - ret = count; - *err = 0; - return ret; -failed_out: - for (i = 0; i <index; i++) - ext2_free_blocks(inode, new_blocks[i], 1); - if (index) - mark_inode_dirty(inode); - return ret; -} - -/** - * ext2_alloc_branch - allocate and set up a chain of blocks. - * @inode: owner - * @num: depth of the chain (number of blocks to allocate) - * @offsets: offsets (in the blocks) to store the pointers to next. - * @branch: place to store the chain in. - * - * This function allocates @num blocks, zeroes out all but the last one, - * links them into chain and (if we are synchronous) writes them to disk. - * In other words, it prepares a branch that can be spliced onto the - * inode. It stores the information about that chain in the branch[], in - * the same format as ext2_get_branch() would do. We are calling it after - * we had read the existing part of chain and partial points to the last - * triple of that (one with zero ->key). Upon the exit we have the same - * picture as after the successful ext2_get_block(), except that in one - * place chain is disconnected - *branch->p is still zero (we did not - * set the last link), but branch->key contains the number that should - * be placed into *branch->p to fill that gap. - * - * If allocation fails we free all blocks we've allocated (and forget - * their buffer_heads) and return the error value the from failed - * ext2_alloc_block() (normally -ENOSPC). Otherwise we set the chain - * as described above and return 0. - */ - -static int ext2_alloc_branch(struct inode *inode, - int indirect_blks, int *blks, ext2_fsblk_t goal, - int *offsets, Indirect *branch) -{ - int blocksize = inode->i_sb->s_blocksize; - int i, n = 0; - int err = 0; - struct buffer_head *bh; - int num; - ext2_fsblk_t new_blocks[4]; - ext2_fsblk_t current_block; - - num = ext2_alloc_blocks(inode, goal, indirect_blks, - *blks, new_blocks, &err); - if (err) - return err; - - branch[0].key = cpu_to_le32(new_blocks[0]); - /* - * metadata blocks and data blocks are allocated. - */ - for (n = 1; n <= indirect_blks; n++) { - /* - * Get buffer_head for parent block, zero it out - * and set the pointer to new one, then send - * parent to disk. - */ - bh = sb_getblk(inode->i_sb, new_blocks[n-1]); - branch[n].bh = bh; - lock_buffer(bh); - memset(bh->b_data, 0, blocksize); - branch[n].p = (__le32 *) bh->b_data + offsets[n]; - branch[n].key = cpu_to_le32(new_blocks[n]); - *branch[n].p = branch[n].key; - if ( n == indirect_blks) { - current_block = new_blocks[n]; - /* - * End of chain, update the last new metablock of - * the chain to point to the new allocated - * data blocks numbers - */ - for (i=1; i < num; i++) - *(branch[n].p + i) = cpu_to_le32(++current_block); - } - set_buffer_uptodate(bh); - unlock_buffer(bh); - mark_buffer_dirty_inode(bh, inode); - /* We used to sync bh here if IS_SYNC(inode). - * But we now rely upon generic_write_sync() - * and b_inode_buffers. But not for directories. - */ - if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) - sync_dirty_buffer(bh); - } - *blks = num; - return err; -} - -/** - * ext2_splice_branch - splice the allocated branch onto inode. - * @inode: owner - * @block: (logical) number of block we are adding - * @where: location of missing link - * @num: number of indirect blocks we are adding - * @blks: number of direct blocks we are adding - * - * This function fills the missing link and does all housekeeping needed in - * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. - */ -static void ext2_splice_branch(struct inode *inode, - long block, Indirect *where, int num, int blks) -{ - int i; - struct ext2_block_alloc_info *block_i; - ext2_fsblk_t current_block; - - block_i = EXT2_I(inode)->i_block_alloc_info; - - /* XXX LOCKING probably should have i_meta_lock ?*/ - /* That's it */ - - *where->p = where->key; - - /* - * Update the host buffer_head or inode to point to more just allocated - * direct blocks blocks - */ - if (num == 0 && blks > 1) { - current_block = le32_to_cpu(where->key) + 1; - for (i = 1; i < blks; i++) - *(where->p + i ) = cpu_to_le32(current_block++); - } - - /* - * update the most recently allocated logical & physical block - * in i_block_alloc_info, to assist find the proper goal block for next - * allocation - */ - if (block_i) { - block_i->last_alloc_logical_block = block + blks - 1; - block_i->last_alloc_physical_block = - le32_to_cpu(where[num].key) + blks - 1; - } - - /* We are done with atomic stuff, now do the rest of housekeeping */ - - /* had we spliced it onto indirect block? */ - if (where->bh) - mark_buffer_dirty_inode(where->bh, inode); - - inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); -} - -/* - * Allocation strategy is simple: if we have to allocate something, we will - * have to go the whole way to leaf. So let's do it before attaching anything - * to tree, set linkage between the newborn blocks, write them if sync is - * required, recheck the path, free and repeat if check fails, otherwise - * set the last missing link (that will protect us from any truncate-generated - * removals - all blocks on the path are immune now) and possibly force the - * write on the parent block. - * That has a nice additional property: no special recovery from the failed - * allocations is needed - we simply release blocks and do not touch anything - * reachable from inode. - * - * `handle' can be NULL if create == 0. - * - * return > 0, # of blocks mapped or allocated. - * return = 0, if plain lookup failed. - * return < 0, error case. - */ -static int ext2_get_blocks(struct inode *inode, - sector_t iblock, unsigned long maxblocks, - struct buffer_head *bh_result, - int create) -{ - int err = -EIO; - int offsets[4]; - Indirect chain[4]; - Indirect *partial; - ext2_fsblk_t goal; - int indirect_blks; - int blocks_to_boundary = 0; - int depth; - struct ext2_inode_info *ei = EXT2_I(inode); - int count = 0; - ext2_fsblk_t first_block = 0; - - depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary); - - if (depth == 0) - return (err); - - partial = ext2_get_branch(inode, depth, offsets, chain, &err); - /* Simplest case - block found, no allocation needed */ - if (!partial) { - first_block = le32_to_cpu(chain[depth - 1].key); - clear_buffer_new(bh_result); /* What's this do? */ - count++; - /*map more blocks*/ - while (count < maxblocks && count <= blocks_to_boundary) { - ext2_fsblk_t blk; - - if (!verify_chain(chain, chain + depth - 1)) { - /* - * Indirect block might be removed by - * truncate while we were reading it. - * Handling of that case: forget what we've - * got now, go to reread. - */ - err = -EAGAIN; - count = 0; - break; - } - blk = le32_to_cpu(*(chain[depth-1].p + count)); - if (blk == first_block + count) - count++; - else - break; - } - if (err != -EAGAIN) - goto got_it; - } - - /* Next simple case - plain lookup or failed read of indirect block */ - if (!create || err == -EIO) - goto cleanup; - - mutex_lock(&ei->truncate_mutex); - /* - * If the indirect block is missing while we are reading - * the chain(ext2_get_branch() returns -EAGAIN err), or - * if the chain has been changed after we grab the semaphore, - * (either because another process truncated this branch, or - * another get_block allocated this branch) re-grab the chain to see if - * the request block has been allocated or not. - * - * Since we already block the truncate/other get_block - * at this point, we will have the current copy of the chain when we - * splice the branch into the tree. - */ - if (err == -EAGAIN || !verify_chain(chain, partial)) { - while (partial > chain) { - brelse(partial->bh); - partial--; - } - partial = ext2_get_branch(inode, depth, offsets, chain, &err); - if (!partial) { - count++; - mutex_unlock(&ei->truncate_mutex); - if (err) - goto cleanup; - clear_buffer_new(bh_result); - goto got_it; - } - } - - /* - * Okay, we need to do block allocation. Lazily initialize the block - * allocation info here if necessary - */ - if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) - ext2_init_block_alloc_info(inode); - - goal = ext2_find_goal(inode, iblock, partial); - - /* the number of blocks need to allocate for [d,t]indirect blocks */ - indirect_blks = (chain + depth) - partial - 1; - /* - * Next look up the indirect map to count the totoal number of - * direct blocks to allocate for this branch. - */ - count = ext2_blks_to_allocate(partial, indirect_blks, - maxblocks, blocks_to_boundary); - /* - * XXX ???? Block out ext2_truncate while we alter the tree - */ - err = ext2_alloc_branch(inode, indirect_blks, &count, goal, - offsets + (partial - chain), partial); - - if (err) { - mutex_unlock(&ei->truncate_mutex); - goto cleanup; - } - - if (ext2_use_xip(inode->i_sb)) { - /* - * we need to clear the block - */ - err = ext2_clear_xip_target (inode, - le32_to_cpu(chain[depth-1].key)); - if (err) { - mutex_unlock(&ei->truncate_mutex); - goto cleanup; - } - } - - ext2_splice_branch(inode, iblock, partial, indirect_blks, count); - mutex_unlock(&ei->truncate_mutex); - set_buffer_new(bh_result); -got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (count > blocks_to_boundary) - set_buffer_boundary(bh_result); - err = count; - /* Clean up and exit */ - partial = chain + depth - 1; /* the whole chain */ -cleanup: - while (partial > chain) { - brelse(partial->bh); - partial--; - } - return err; -} - -int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) -{ - unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; - int ret = ext2_get_blocks(inode, iblock, max_blocks, - bh_result, create); - if (ret > 0) { - bh_result->b_size = (ret << inode->i_blkbits); - ret = 0; - } - return ret; - -} - -int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len) -{ - return generic_block_fiemap(inode, fieinfo, start, len, - ext2_get_block); -} - -static int ext2_writepage(struct page *page, struct writeback_control *wbc) -{ - return block_write_full_page(page, ext2_get_block, wbc); -} - -static int ext2_readpage(struct file *file, struct page *page) -{ - return mpage_readpage(page, ext2_get_block); -} - -static int -ext2_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); -} - -static int -ext2_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - int ret; - - ret = block_write_begin(mapping, pos, len, flags, pagep, - ext2_get_block); - if (ret < 0) - ext2_write_failed(mapping, pos + len); - return ret; -} - -static int ext2_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - int ret; - - ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); - if (ret < len) - ext2_write_failed(mapping, pos + len); - return ret; -} - -static int -ext2_nobh_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - int ret; - - ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, - ext2_get_block); - if (ret < 0) - ext2_write_failed(mapping, pos + len); - return ret; -} - -static int ext2_nobh_writepage(struct page *page, - struct writeback_control *wbc) -{ - return nobh_writepage(page, ext2_get_block, wbc); -} - -static sector_t ext2_bmap(struct address_space *mapping, sector_t block) -{ - return generic_block_bmap(mapping,block,ext2_get_block); -} - -static ssize_t -ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, - loff_t offset, unsigned long nr_segs) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - ssize_t ret; - - ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, - ext2_get_block); - if (ret < 0 && (rw & WRITE)) - ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); - return ret; -} - -static int -ext2_writepages(struct address_space *mapping, struct writeback_control *wbc) -{ - return mpage_writepages(mapping, wbc, ext2_get_block); -} - -const struct address_space_operations ext2_aops = { - .readpage = ext2_readpage, - .readpages = ext2_readpages, - .writepage = ext2_writepage, - .write_begin = ext2_write_begin, - .write_end = ext2_write_end, - .bmap = ext2_bmap, - .direct_IO = ext2_direct_IO, - .writepages = ext2_writepages, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -const struct address_space_operations ext2_aops_xip = { - .bmap = ext2_bmap, - .get_xip_mem = ext2_get_xip_mem, -}; - -const struct address_space_operations ext2_nobh_aops = { - .readpage = ext2_readpage, - .readpages = ext2_readpages, - .writepage = ext2_nobh_writepage, - .write_begin = ext2_nobh_write_begin, - .write_end = nobh_write_end, - .bmap = ext2_bmap, - .direct_IO = ext2_direct_IO, - .writepages = ext2_writepages, - .migratepage = buffer_migrate_page, - .error_remove_page = generic_error_remove_page, -}; - -/* - * Probably it should be a library function... search for first non-zero word - * or memcmp with zero_page, whatever is better for particular architecture. - * Linus? - */ -static inline int all_zeroes(__le32 *p, __le32 *q) -{ - while (p < q) - if (*p++) - return 0; - return 1; -} - -/** - * ext2_find_shared - find the indirect blocks for partial truncation. - * @inode: inode in question - * @depth: depth of the affected branch - * @offsets: offsets of pointers in that branch (see ext2_block_to_path) - * @chain: place to store the pointers to partial indirect blocks - * @top: place to the (detached) top of branch - * - * This is a helper function used by ext2_truncate(). - * - * When we do truncate() we may have to clean the ends of several indirect - * blocks but leave the blocks themselves alive. Block is partially - * truncated if some data below the new i_size is referred from it (and - * it is on the path to the first completely truncated data block, indeed). - * We have to free the top of that path along with everything to the right - * of the path. Since no allocation past the truncation point is possible - * until ext2_truncate() finishes, we may safely do the latter, but top - * of branch may require special attention - pageout below the truncation - * point might try to populate it. - * - * We atomically detach the top of branch from the tree, store the block - * number of its root in *@top, pointers to buffer_heads of partially - * truncated blocks - in @chain[].bh and pointers to their last elements - * that should not be removed - in @chain[].p. Return value is the pointer - * to last filled element of @chain. - * - * The work left to caller to do the actual freeing of subtrees: - * a) free the subtree starting from *@top - * b) free the subtrees whose roots are stored in - * (@chain[i].p+1 .. end of @chain[i].bh->b_data) - * c) free the subtrees growing from the inode past the @chain[0].p - * (no partially truncated stuff there). - */ - -static Indirect *ext2_find_shared(struct inode *inode, - int depth, - int offsets[4], - Indirect chain[4], - __le32 *top) -{ - Indirect *partial, *p; - int k, err; - - *top = 0; - for (k = depth; k > 1 && !offsets[k-1]; k--) - ; - partial = ext2_get_branch(inode, k, offsets, chain, &err); - if (!partial) - partial = chain + k-1; - /* - * If the branch acquired continuation since we've looked at it - - * fine, it should all survive and (new) top doesn't belong to us. - */ - write_lock(&EXT2_I(inode)->i_meta_lock); - if (!partial->key && *partial->p) { - write_unlock(&EXT2_I(inode)->i_meta_lock); - goto no_top; - } - for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--) - ; - /* - * OK, we've found the last block that must survive. The rest of our - * branch should be detached before unlocking. However, if that rest - * of branch is all ours and does not grow immediately from the inode - * it's easier to cheat and just decrement partial->p. - */ - if (p == chain + k - 1 && p > chain) { - p->p--; - } else { - *top = *p->p; - *p->p = 0; - } - write_unlock(&EXT2_I(inode)->i_meta_lock); - - while(partial > p) - { - brelse(partial->bh); - partial--; - } -no_top: - return partial; -} - -/** - * ext2_free_data - free a list of data blocks - * @inode: inode we are dealing with - * @p: array of block numbers - * @q: points immediately past the end of array - * - * We are freeing all blocks referred from that array (numbers are - * stored as little-endian 32-bit) and updating @inode->i_blocks - * appropriately. - */ -static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) -{ - unsigned long block_to_free = 0, count = 0; - unsigned long nr; - - for ( ; p < q ; p++) { - nr = le32_to_cpu(*p); - if (nr) { - *p = 0; - /* accumulate blocks to free if they're contiguous */ - if (count == 0) - goto free_this; - else if (block_to_free == nr - count) - count++; - else { - ext2_free_blocks (inode, block_to_free, count); - mark_inode_dirty(inode); - free_this: - block_to_free = nr; - count = 1; - } - } - } - if (count > 0) { - ext2_free_blocks (inode, block_to_free, count); - mark_inode_dirty(inode); - } -} - -/** - * ext2_free_branches - free an array of branches - * @inode: inode we are dealing with - * @p: array of block numbers - * @q: pointer immediately past the end of array - * @depth: depth of the branches to free - * - * We are freeing all blocks referred from these branches (numbers are - * stored as little-endian 32-bit) and updating @inode->i_blocks - * appropriately. - */ -static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth) -{ - struct buffer_head * bh; - unsigned long nr; - - if (depth--) { - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - for ( ; p < q ; p++) { - nr = le32_to_cpu(*p); - if (!nr) - continue; - *p = 0; - bh = sb_bread(inode->i_sb, nr); - /* - * A read failure? Report error and clear slot - * (should be rare). - */ - if (!bh) { - ext2_error(inode->i_sb, "ext2_free_branches", - "Read failure, inode=%ld, block=%ld", - inode->i_ino, nr); - continue; - } - ext2_free_branches(inode, - (__le32*)bh->b_data, - (__le32*)bh->b_data + addr_per_block, - depth); - bforget(bh); - ext2_free_blocks(inode, nr, 1); - mark_inode_dirty(inode); - } - } else - ext2_free_data(inode, p, q); -} - -static void __ext2_truncate_blocks(struct inode *inode, loff_t offset) -{ - __le32 *i_data = EXT2_I(inode)->i_data; - struct ext2_inode_info *ei = EXT2_I(inode); - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int offsets[4]; - Indirect chain[4]; - Indirect *partial; - __le32 nr = 0; - int n; - long iblock; - unsigned blocksize; - blocksize = inode->i_sb->s_blocksize; - iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); - - n = ext2_block_to_path(inode, iblock, offsets, NULL); - if (n == 0) - return; - - /* - * From here we block out all ext2_get_block() callers who want to - * modify the block allocation tree. - */ - mutex_lock(&ei->truncate_mutex); - - if (n == 1) { - ext2_free_data(inode, i_data+offsets[0], - i_data + EXT2_NDIR_BLOCKS); - goto do_indirects; - } - - partial = ext2_find_shared(inode, n, offsets, chain, &nr); - /* Kill the top of shared branch (already detached) */ - if (nr) { - if (partial == chain) - mark_inode_dirty(inode); - else - mark_buffer_dirty_inode(partial->bh, inode); - ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); - } - /* Clear the ends of indirect blocks on the shared branch */ - while (partial > chain) { - ext2_free_branches(inode, - partial->p + 1, - (__le32*)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - mark_buffer_dirty_inode(partial->bh, inode); - brelse (partial->bh); - partial--; - } -do_indirects: - /* Kill the remaining (whole) subtrees */ - switch (offsets[0]) { - default: - nr = i_data[EXT2_IND_BLOCK]; - if (nr) { - i_data[EXT2_IND_BLOCK] = 0; - mark_inode_dirty(inode); - ext2_free_branches(inode, &nr, &nr+1, 1); - } - case EXT2_IND_BLOCK: - nr = i_data[EXT2_DIND_BLOCK]; - if (nr) { - i_data[EXT2_DIND_BLOCK] = 0; - mark_inode_dirty(inode); - ext2_free_branches(inode, &nr, &nr+1, 2); - } - case EXT2_DIND_BLOCK: - nr = i_data[EXT2_TIND_BLOCK]; - if (nr) { - i_data[EXT2_TIND_BLOCK] = 0; - mark_inode_dirty(inode); - ext2_free_branches(inode, &nr, &nr+1, 3); - } - case EXT2_TIND_BLOCK: - ; - } - - ext2_discard_reservation(inode); - - mutex_unlock(&ei->truncate_mutex); -} - -static void ext2_truncate_blocks(struct inode *inode, loff_t offset) -{ - /* - * XXX: it seems like a bug here that we don't allow - * IS_APPEND inode to have blocks-past-i_size trimmed off. - * review and fix this. - * - * Also would be nice to be able to handle IO errors and such, - * but that's probably too much to ask. - */ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - if (ext2_inode_is_fast_symlink(inode)) - return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; - __ext2_truncate_blocks(inode, offset); -} - -static int ext2_setsize(struct inode *inode, loff_t newsize) -{ - int error; - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return -EINVAL; - if (ext2_inode_is_fast_symlink(inode)) - return -EINVAL; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return -EPERM; - - inode_dio_wait(inode); - - if (mapping_is_xip(inode->i_mapping)) - error = xip_truncate_page(inode->i_mapping, newsize); - else if (test_opt(inode->i_sb, NOBH)) - error = nobh_truncate_page(inode->i_mapping, - newsize, ext2_get_block); - else - error = block_truncate_page(inode->i_mapping, - newsize, ext2_get_block); - if (error) - return error; - - truncate_setsize(inode, newsize); - __ext2_truncate_blocks(inode, newsize); - - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - if (inode_needs_sync(inode)) { - sync_mapping_buffers(inode->i_mapping); - sync_inode_metadata(inode, 1); - } else { - mark_inode_dirty(inode); - } - - return 0; -} - -static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino, - struct buffer_head **p) -{ - struct buffer_head * bh; - unsigned long block_group; - unsigned long block; - unsigned long offset; - struct ext2_group_desc * gdp; - - *p = NULL; - if ((ino != EXT2_ROOT_INO && ino < EXT2_FIRST_INO(sb)) || - ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count)) - goto Einval; - - block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); - gdp = ext2_get_group_desc(sb, block_group, NULL); - if (!gdp) - goto Egdp; - /* - * Figure out the offset within the block group inode table - */ - offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb); - block = le32_to_cpu(gdp->bg_inode_table) + - (offset >> EXT2_BLOCK_SIZE_BITS(sb)); - if (!(bh = sb_bread(sb, block))) - goto Eio; - - *p = bh; - offset &= (EXT2_BLOCK_SIZE(sb) - 1); - return (struct ext2_inode *) (bh->b_data + offset); - -Einval: - ext2_error(sb, "ext2_get_inode", "bad inode number: %lu", - (unsigned long) ino); - return ERR_PTR(-EINVAL); -Eio: - ext2_error(sb, "ext2_get_inode", - "unable to read inode block - inode=%lu, block=%lu", - (unsigned long) ino, block); -Egdp: - return ERR_PTR(-EIO); -} - -void ext2_set_inode_flags(struct inode *inode) -{ - unsigned int flags = EXT2_I(inode)->i_flags; - - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (flags & EXT2_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT2_APPEND_FL) - inode->i_flags |= S_APPEND; - if (flags & EXT2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - if (flags & EXT2_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT2_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -} - -/* Propagate flags from i_flags to EXT2_I(inode)->i_flags */ -void ext2_get_inode_flags(struct ext2_inode_info *ei) -{ - unsigned int flags = ei->vfs_inode.i_flags; - - ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL| - EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT2_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT2_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT2_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT2_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT2_DIRSYNC_FL; -} - -struct inode *ext2_iget (struct super_block *sb, unsigned long ino) -{ - struct ext2_inode_info *ei; - struct buffer_head * bh; - struct ext2_inode *raw_inode; - struct inode *inode; - long ret = -EIO; - int n; - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - ei = EXT2_I(inode); - ei->i_block_alloc_info = NULL; - - raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); - if (IS_ERR(raw_inode)) { - ret = PTR_ERR(raw_inode); - goto bad_inode; - } - - inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if (!(test_opt (inode->i_sb, NO_UID32))) { - inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } - set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); - inode->i_size = le32_to_cpu(raw_inode->i_size); - inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); - inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime); - inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime); - inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0; - ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); - /* We now have enough fields to check if the inode was active or not. - * This is needed because nfsd might try to access dead inodes - * the test is that same one that e2fsck uses - * NeilBrown 1999oct15 - */ - if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) { - /* this inode is deleted */ - brelse (bh); - ret = -ESTALE; - goto bad_inode; - } - inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); - ei->i_flags = le32_to_cpu(raw_inode->i_flags); - ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); - ei->i_frag_no = raw_inode->i_frag; - ei->i_frag_size = raw_inode->i_fsize; - ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); - ei->i_dir_acl = 0; - if (S_ISREG(inode->i_mode)) - inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; - else - ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); - ei->i_dtime = 0; - inode->i_generation = le32_to_cpu(raw_inode->i_generation); - ei->i_state = 0; - ei->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); - ei->i_dir_start_lookup = 0; - - /* - * NOTE! The in-memory inode i_data array is in little-endian order - * even on big-endian machines: we do NOT byteswap the block numbers! - */ - for (n = 0; n < EXT2_N_BLOCKS; n++) - ei->i_data[n] = raw_inode->i_block[n]; - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ext2_file_inode_operations; - if (ext2_use_xip(inode->i_sb)) { - inode->i_mapping->a_ops = &ext2_aops_xip; - inode->i_fop = &ext2_xip_file_operations; - } else if (test_opt(inode->i_sb, NOBH)) { - inode->i_mapping->a_ops = &ext2_nobh_aops; - inode->i_fop = &ext2_file_operations; - } else { - inode->i_mapping->a_ops = &ext2_aops; - inode->i_fop = &ext2_file_operations; - } - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ext2_dir_inode_operations; - inode->i_fop = &ext2_dir_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; - } else if (S_ISLNK(inode->i_mode)) { - if (ext2_inode_is_fast_symlink(inode)) { - inode->i_op = &ext2_fast_symlink_inode_operations; - nd_terminate_link(ei->i_data, inode->i_size, - sizeof(ei->i_data) - 1); - } else { - inode->i_op = &ext2_symlink_inode_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; - } - } else { - inode->i_op = &ext2_special_inode_operations; - if (raw_inode->i_block[0]) - init_special_inode(inode, inode->i_mode, - old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); - else - init_special_inode(inode, inode->i_mode, - new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); - } - brelse (bh); - ext2_set_inode_flags(inode); - unlock_new_inode(inode); - return inode; - -bad_inode: - iget_failed(inode); - return ERR_PTR(ret); -} - -static int __ext2_write_inode(struct inode *inode, int do_sync) -{ - struct ext2_inode_info *ei = EXT2_I(inode); - struct super_block *sb = inode->i_sb; - ino_t ino = inode->i_ino; - uid_t uid = inode->i_uid; - gid_t gid = inode->i_gid; - struct buffer_head * bh; - struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); - int n; - int err = 0; - - if (IS_ERR(raw_inode)) - return -EIO; - - /* For fields not not tracking in the in-memory inode, - * initialise them to zero for new inodes. */ - if (ei->i_state & EXT2_STATE_NEW) - memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size); - - ext2_get_inode_flags(ei); - raw_inode->i_mode = cpu_to_le16(inode->i_mode); - if (!(test_opt(sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); -/* - * Fix up interoperability with old kernels. Otherwise, old inodes get - * re-used with the upper 16 bits of the uid/gid intact - */ - if (!ei->i_dtime) { - raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid)); - raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid)); - } else { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - } else { - raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid)); - raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - raw_inode->i_size = cpu_to_le32(inode->i_size); - raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); - raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); - raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); - - raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); - raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); - raw_inode->i_flags = cpu_to_le32(ei->i_flags); - raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); - raw_inode->i_frag = ei->i_frag_no; - raw_inode->i_fsize = ei->i_frag_size; - raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl); - if (!S_ISREG(inode->i_mode)) - raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); - else { - raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); - if (inode->i_size > 0x7fffffffULL) { - if (!EXT2_HAS_RO_COMPAT_FEATURE(sb, - EXT2_FEATURE_RO_COMPAT_LARGE_FILE) || - EXT2_SB(sb)->s_es->s_rev_level == - cpu_to_le32(EXT2_GOOD_OLD_REV)) { - /* If this is the first large file - * created, add a flag to the superblock. - */ - spin_lock(&EXT2_SB(sb)->s_lock); - ext2_update_dynamic_rev(sb); - EXT2_SET_RO_COMPAT_FEATURE(sb, - EXT2_FEATURE_RO_COMPAT_LARGE_FILE); - spin_unlock(&EXT2_SB(sb)->s_lock); - ext2_write_super(sb); - } - } - } - - raw_inode->i_generation = cpu_to_le32(inode->i_generation); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - if (old_valid_dev(inode->i_rdev)) { - raw_inode->i_block[0] = - cpu_to_le32(old_encode_dev(inode->i_rdev)); - raw_inode->i_block[1] = 0; - } else { - raw_inode->i_block[0] = 0; - raw_inode->i_block[1] = - cpu_to_le32(new_encode_dev(inode->i_rdev)); - raw_inode->i_block[2] = 0; - } - } else for (n = 0; n < EXT2_N_BLOCKS; n++) - raw_inode->i_block[n] = ei->i_data[n]; - mark_buffer_dirty(bh); - if (do_sync) { - sync_dirty_buffer(bh); - if (buffer_req(bh) && !buffer_uptodate(bh)) { - printk ("IO error syncing ext2 inode [%s:%08lx]\n", - sb->s_id, (unsigned long) ino); - err = -EIO; - } - } - ei->i_state &= ~EXT2_STATE_NEW; - brelse (bh); - return err; -} - -int ext2_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); -} - -int ext2_setattr(struct dentry *dentry, struct iattr *iattr) -{ - struct inode *inode = dentry->d_inode; - int error; - - error = inode_change_ok(inode, iattr); - if (error) - return error; - - if (is_quota_modification(inode, iattr)) - dquot_initialize(inode); - if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || - (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { - error = dquot_transfer(inode, iattr); - if (error) - return error; - } - if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) { - error = ext2_setsize(inode, iattr->ia_size); - if (error) - return error; - } - setattr_copy(inode, iattr); - if (iattr->ia_valid & ATTR_MODE) - error = ext2_acl_chmod(inode); - mark_inode_dirty(inode); - - return error; -} diff --git a/ANDROID_3.4.5/fs/ext2/ioctl.c b/ANDROID_3.4.5/fs/ext2/ioctl.c deleted file mode 100644 index 2de655f5..00000000 --- a/ANDROID_3.4.5/fs/ext2/ioctl.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * linux/fs/ext2/ioctl.c - * - * Copyright (C) 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include "ext2.h" -#include <linux/capability.h> -#include <linux/time.h> -#include <linux/sched.h> -#include <linux/compat.h> -#include <linux/mount.h> -#include <asm/current.h> -#include <asm/uaccess.h> - - -long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = filp->f_dentry->d_inode; - struct ext2_inode_info *ei = EXT2_I(inode); - unsigned int flags; - unsigned short rsv_window_size; - int ret; - - ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); - - switch (cmd) { - case EXT2_IOC_GETFLAGS: - ext2_get_inode_flags(ei); - flags = ei->i_flags & EXT2_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case EXT2_IOC_SETFLAGS: { - unsigned int oldflags; - - ret = mnt_want_write_file(filp); - if (ret) - return ret; - - if (!inode_owner_or_capable(inode)) { - ret = -EACCES; - goto setflags_out; - } - - if (get_user(flags, (int __user *) arg)) { - ret = -EFAULT; - goto setflags_out; - } - - flags = ext2_mask_flags(inode->i_mode, flags); - - mutex_lock(&inode->i_mutex); - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) { - mutex_unlock(&inode->i_mutex); - ret = -EPERM; - goto setflags_out; - } - oldflags = ei->i_flags; - - /* - * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the relevant capability. - * - * This test looks nicer. Thanks to Pauline Middelink - */ - if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - mutex_unlock(&inode->i_mutex); - ret = -EPERM; - goto setflags_out; - } - } - - flags = flags & EXT2_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT2_FL_USER_MODIFIABLE; - ei->i_flags = flags; - - ext2_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME_SEC; - mutex_unlock(&inode->i_mutex); - - mark_inode_dirty(inode); -setflags_out: - mnt_drop_write_file(filp); - return ret; - } - case EXT2_IOC_GETVERSION: - return put_user(inode->i_generation, (int __user *) arg); - case EXT2_IOC_SETVERSION: { - __u32 generation; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - ret = mnt_want_write_file(filp); - if (ret) - return ret; - if (get_user(generation, (int __user *) arg)) { - ret = -EFAULT; - goto setversion_out; - } - - mutex_lock(&inode->i_mutex); - inode->i_ctime = CURRENT_TIME_SEC; - inode->i_generation = generation; - mutex_unlock(&inode->i_mutex); - - mark_inode_dirty(inode); -setversion_out: - mnt_drop_write_file(filp); - return ret; - } - case EXT2_IOC_GETRSVSZ: - if (test_opt(inode->i_sb, RESERVATION) - && S_ISREG(inode->i_mode) - && ei->i_block_alloc_info) { - rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; - return put_user(rsv_window_size, (int __user *)arg); - } - return -ENOTTY; - case EXT2_IOC_SETRSVSZ: { - - if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) - return -ENOTTY; - - if (!inode_owner_or_capable(inode)) - return -EACCES; - - if (get_user(rsv_window_size, (int __user *)arg)) - return -EFAULT; - - ret = mnt_want_write_file(filp); - if (ret) - return ret; - - if (rsv_window_size > EXT2_MAX_RESERVE_BLOCKS) - rsv_window_size = EXT2_MAX_RESERVE_BLOCKS; - - /* - * need to allocate reservation structure for this inode - * before set the window size - */ - /* - * XXX What lock should protect the rsv_goal_size? - * Accessed in ext2_get_block only. ext3 uses i_truncate. - */ - mutex_lock(&ei->truncate_mutex); - if (!ei->i_block_alloc_info) - ext2_init_block_alloc_info(inode); - - if (ei->i_block_alloc_info){ - struct ext2_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; - rsv->rsv_goal_size = rsv_window_size; - } - mutex_unlock(&ei->truncate_mutex); - mnt_drop_write_file(filp); - return 0; - } - default: - return -ENOTTY; - } -} - -#ifdef CONFIG_COMPAT -long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT2_IOC32_GETFLAGS: - cmd = EXT2_IOC_GETFLAGS; - break; - case EXT2_IOC32_SETFLAGS: - cmd = EXT2_IOC_SETFLAGS; - break; - case EXT2_IOC32_GETVERSION: - cmd = EXT2_IOC_GETVERSION; - break; - case EXT2_IOC32_SETVERSION: - cmd = EXT2_IOC_SETVERSION; - break; - default: - return -ENOIOCTLCMD; - } - return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); -} -#endif diff --git a/ANDROID_3.4.5/fs/ext2/namei.c b/ANDROID_3.4.5/fs/ext2/namei.c deleted file mode 100644 index dffb8653..00000000 --- a/ANDROID_3.4.5/fs/ext2/namei.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * linux/fs/ext2/namei.c - * - * Rewrite to pagecache. Almost all code had been changed, so blame me - * if the things go wrong. Please, send bug reports to - * viro@parcelfarce.linux.theplanet.co.uk - * - * Stuff here is basically a glue between the VFS and generic UNIXish - * filesystem that keeps everything in pagecache. All knowledge of the - * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable - * and it's easier to debug that way. In principle we might want to - * generalize that a bit and turn it into a library. Or not. - * - * The only non-static object here is ext2_dir_inode_operations. - * - * TODO: get rid of kmap() use, add readahead. - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/namei.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include <linux/pagemap.h> -#include <linux/quotaops.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" -#include "xip.h" - -static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode) -{ - int err = ext2_add_link(dentry, inode); - if (!err) { - d_instantiate(dentry, inode); - unlock_new_inode(inode); - return 0; - } - inode_dec_link_count(inode); - unlock_new_inode(inode); - iput(inode); - return err; -} - -/* - * Methods themselves. - */ - -static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) -{ - struct inode * inode; - ino_t ino; - - if (dentry->d_name.len > EXT2_NAME_LEN) - return ERR_PTR(-ENAMETOOLONG); - - ino = ext2_inode_by_name(dir, &dentry->d_name); - inode = NULL; - if (ino) { - inode = ext2_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext2_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - (unsigned long) ino); - return ERR_PTR(-EIO); - } - } - return d_splice_alias(inode, dentry); -} - -struct dentry *ext2_get_parent(struct dentry *child) -{ - struct qstr dotdot = {.name = "..", .len = 2}; - unsigned long ino = ext2_inode_by_name(child->d_inode, &dotdot); - if (!ino) - return ERR_PTR(-ENOENT); - return d_obtain_alias(ext2_iget(child->d_inode->i_sb, ino)); -} - -/* - * By the time this is called, we already have created - * the directory cache entry for the new file, but it - * is so far negative - it has no inode. - * - * If the create succeeds, we fill in the inode information - * with d_instantiate(). - */ -static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd) -{ - struct inode *inode; - - dquot_initialize(dir); - - inode = ext2_new_inode(dir, mode, &dentry->d_name); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - inode->i_op = &ext2_file_inode_operations; - if (ext2_use_xip(inode->i_sb)) { - inode->i_mapping->a_ops = &ext2_aops_xip; - inode->i_fop = &ext2_xip_file_operations; - } else if (test_opt(inode->i_sb, NOBH)) { - inode->i_mapping->a_ops = &ext2_nobh_aops; - inode->i_fop = &ext2_file_operations; - } else { - inode->i_mapping->a_ops = &ext2_aops; - inode->i_fop = &ext2_file_operations; - } - mark_inode_dirty(inode); - return ext2_add_nondir(dentry, inode); -} - -static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev) -{ - struct inode * inode; - int err; - - if (!new_valid_dev(rdev)) - return -EINVAL; - - dquot_initialize(dir); - - inode = ext2_new_inode (dir, mode, &dentry->d_name); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - init_special_inode(inode, inode->i_mode, rdev); -#ifdef CONFIG_EXT2_FS_XATTR - inode->i_op = &ext2_special_inode_operations; -#endif - mark_inode_dirty(inode); - err = ext2_add_nondir(dentry, inode); - } - return err; -} - -static int ext2_symlink (struct inode * dir, struct dentry * dentry, - const char * symname) -{ - struct super_block * sb = dir->i_sb; - int err = -ENAMETOOLONG; - unsigned l = strlen(symname)+1; - struct inode * inode; - - if (l > sb->s_blocksize) - goto out; - - dquot_initialize(dir); - - inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out; - - if (l > sizeof (EXT2_I(inode)->i_data)) { - /* slow symlink */ - inode->i_op = &ext2_symlink_inode_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; - err = page_symlink(inode, symname, l); - if (err) - goto out_fail; - } else { - /* fast symlink */ - inode->i_op = &ext2_fast_symlink_inode_operations; - memcpy((char*)(EXT2_I(inode)->i_data),symname,l); - inode->i_size = l-1; - } - mark_inode_dirty(inode); - - err = ext2_add_nondir(dentry, inode); -out: - return err; - -out_fail: - inode_dec_link_count(inode); - unlock_new_inode(inode); - iput (inode); - goto out; -} - -static int ext2_link (struct dentry * old_dentry, struct inode * dir, - struct dentry *dentry) -{ - struct inode *inode = old_dentry->d_inode; - int err; - - dquot_initialize(dir); - - inode->i_ctime = CURRENT_TIME_SEC; - inode_inc_link_count(inode); - ihold(inode); - - err = ext2_add_link(dentry, inode); - if (!err) { - d_instantiate(dentry, inode); - return 0; - } - inode_dec_link_count(inode); - iput(inode); - return err; -} - -static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) -{ - struct inode * inode; - int err; - - dquot_initialize(dir); - - inode_inc_link_count(dir); - - inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_dir; - - inode->i_op = &ext2_dir_inode_operations; - inode->i_fop = &ext2_dir_operations; - if (test_opt(inode->i_sb, NOBH)) - inode->i_mapping->a_ops = &ext2_nobh_aops; - else - inode->i_mapping->a_ops = &ext2_aops; - - inode_inc_link_count(inode); - - err = ext2_make_empty(inode, dir); - if (err) - goto out_fail; - - err = ext2_add_link(dentry, inode); - if (err) - goto out_fail; - - d_instantiate(dentry, inode); - unlock_new_inode(inode); -out: - return err; - -out_fail: - inode_dec_link_count(inode); - inode_dec_link_count(inode); - unlock_new_inode(inode); - iput(inode); -out_dir: - inode_dec_link_count(dir); - goto out; -} - -static int ext2_unlink(struct inode * dir, struct dentry *dentry) -{ - struct inode * inode = dentry->d_inode; - struct ext2_dir_entry_2 * de; - struct page * page; - int err = -ENOENT; - - dquot_initialize(dir); - - de = ext2_find_entry (dir, &dentry->d_name, &page); - if (!de) - goto out; - - err = ext2_delete_entry (de, page); - if (err) - goto out; - - inode->i_ctime = dir->i_ctime; - inode_dec_link_count(inode); - err = 0; -out: - return err; -} - -static int ext2_rmdir (struct inode * dir, struct dentry *dentry) -{ - struct inode * inode = dentry->d_inode; - int err = -ENOTEMPTY; - - if (ext2_empty_dir(inode)) { - err = ext2_unlink(dir, dentry); - if (!err) { - inode->i_size = 0; - inode_dec_link_count(inode); - inode_dec_link_count(dir); - } - } - return err; -} - -static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, - struct inode * new_dir, struct dentry * new_dentry ) -{ - struct inode * old_inode = old_dentry->d_inode; - struct inode * new_inode = new_dentry->d_inode; - struct page * dir_page = NULL; - struct ext2_dir_entry_2 * dir_de = NULL; - struct page * old_page; - struct ext2_dir_entry_2 * old_de; - int err = -ENOENT; - - dquot_initialize(old_dir); - dquot_initialize(new_dir); - - old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); - if (!old_de) - goto out; - - if (S_ISDIR(old_inode->i_mode)) { - err = -EIO; - dir_de = ext2_dotdot(old_inode, &dir_page); - if (!dir_de) - goto out_old; - } - - if (new_inode) { - struct page *new_page; - struct ext2_dir_entry_2 *new_de; - - err = -ENOTEMPTY; - if (dir_de && !ext2_empty_dir (new_inode)) - goto out_dir; - - err = -ENOENT; - new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); - if (!new_de) - goto out_dir; - ext2_set_link(new_dir, new_de, new_page, old_inode, 1); - new_inode->i_ctime = CURRENT_TIME_SEC; - if (dir_de) - drop_nlink(new_inode); - inode_dec_link_count(new_inode); - } else { - err = ext2_add_link(new_dentry, old_inode); - if (err) - goto out_dir; - if (dir_de) - inode_inc_link_count(new_dir); - } - - /* - * Like most other Unix systems, set the ctime for inodes on a - * rename. - */ - old_inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(old_inode); - - ext2_delete_entry (old_de, old_page); - - if (dir_de) { - if (old_dir != new_dir) - ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); - else { - kunmap(dir_page); - page_cache_release(dir_page); - } - inode_dec_link_count(old_dir); - } - return 0; - - -out_dir: - if (dir_de) { - kunmap(dir_page); - page_cache_release(dir_page); - } -out_old: - kunmap(old_page); - page_cache_release(old_page); -out: - return err; -} - -const struct inode_operations ext2_dir_inode_operations = { - .create = ext2_create, - .lookup = ext2_lookup, - .link = ext2_link, - .unlink = ext2_unlink, - .symlink = ext2_symlink, - .mkdir = ext2_mkdir, - .rmdir = ext2_rmdir, - .mknod = ext2_mknod, - .rename = ext2_rename, -#ifdef CONFIG_EXT2_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext2_listxattr, - .removexattr = generic_removexattr, -#endif - .setattr = ext2_setattr, - .get_acl = ext2_get_acl, -}; - -const struct inode_operations ext2_special_inode_operations = { -#ifdef CONFIG_EXT2_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext2_listxattr, - .removexattr = generic_removexattr, -#endif - .setattr = ext2_setattr, - .get_acl = ext2_get_acl, -}; diff --git a/ANDROID_3.4.5/fs/ext2/super.c b/ANDROID_3.4.5/fs/ext2/super.c deleted file mode 100644 index e1025c7a..00000000 --- a/ANDROID_3.4.5/fs/ext2/super.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * linux/fs/ext2/super.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/blkdev.h> -#include <linux/parser.h> -#include <linux/random.h> -#include <linux/buffer_head.h> -#include <linux/exportfs.h> -#include <linux/vfs.h> -#include <linux/seq_file.h> -#include <linux/mount.h> -#include <linux/log2.h> -#include <linux/quotaops.h> -#include <asm/uaccess.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" -#include "xip.h" - -static void ext2_sync_super(struct super_block *sb, - struct ext2_super_block *es, int wait); -static int ext2_remount (struct super_block * sb, int * flags, char * data); -static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); -static int ext2_sync_fs(struct super_block *sb, int wait); - -void ext2_error(struct super_block *sb, const char *function, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - - if (!(sb->s_flags & MS_RDONLY)) { - spin_lock(&sbi->s_lock); - sbi->s_mount_state |= EXT2_ERROR_FS; - es->s_state |= cpu_to_le16(EXT2_ERROR_FS); - spin_unlock(&sbi->s_lock); - ext2_sync_super(sb, es, 1); - } - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk(KERN_CRIT "EXT2-fs (%s): error: %s: %pV\n", - sb->s_id, function, &vaf); - - va_end(args); - - if (test_opt(sb, ERRORS_PANIC)) - panic("EXT2-fs: panic from previous error\n"); - if (test_opt(sb, ERRORS_RO)) { - ext2_msg(sb, KERN_CRIT, - "error: remounting filesystem read-only"); - sb->s_flags |= MS_RDONLY; - } -} - -void ext2_msg(struct super_block *sb, const char *prefix, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk("%sEXT2-fs (%s): %pV\n", prefix, sb->s_id, &vaf); - - va_end(args); -} - -/* - * This must be called with sbi->s_lock held. - */ -void ext2_update_dynamic_rev(struct super_block *sb) -{ - struct ext2_super_block *es = EXT2_SB(sb)->s_es; - - if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) - return; - - ext2_msg(sb, KERN_WARNING, - "warning: updating to rev %d because of " - "new feature flag, running e2fsck is recommended", - EXT2_DYNAMIC_REV); - - es->s_first_ino = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO); - es->s_inode_size = cpu_to_le16(EXT2_GOOD_OLD_INODE_SIZE); - es->s_rev_level = cpu_to_le32(EXT2_DYNAMIC_REV); - /* leave es->s_feature_*compat flags alone */ - /* es->s_uuid will be set by e2fsck if empty */ - - /* - * The rest of the superblock fields should be zero, and if not it - * means they are likely already in use, so leave them alone. We - * can leave it up to e2fsck to clean up any inconsistencies there. - */ -} - -static void ext2_put_super (struct super_block * sb) -{ - int db_count; - int i; - struct ext2_sb_info *sbi = EXT2_SB(sb); - - dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); - - if (sb->s_dirt) - ext2_write_super(sb); - - ext2_xattr_put_super(sb); - if (!(sb->s_flags & MS_RDONLY)) { - struct ext2_super_block *es = sbi->s_es; - - spin_lock(&sbi->s_lock); - es->s_state = cpu_to_le16(sbi->s_mount_state); - spin_unlock(&sbi->s_lock); - ext2_sync_super(sb, es, 1); - } - db_count = sbi->s_gdb_count; - for (i = 0; i < db_count; i++) - if (sbi->s_group_desc[i]) - brelse (sbi->s_group_desc[i]); - kfree(sbi->s_group_desc); - kfree(sbi->s_debts); - percpu_counter_destroy(&sbi->s_freeblocks_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); - brelse (sbi->s_sbh); - sb->s_fs_info = NULL; - kfree(sbi->s_blockgroup_lock); - kfree(sbi); -} - -static struct kmem_cache * ext2_inode_cachep; - -static struct inode *ext2_alloc_inode(struct super_block *sb) -{ - struct ext2_inode_info *ei; - ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); - if (!ei) - return NULL; - ei->i_block_alloc_info = NULL; - ei->vfs_inode.i_version = 1; - return &ei->vfs_inode; -} - -static void ext2_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); -} - -static void ext2_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, ext2_i_callback); -} - -static void init_once(void *foo) -{ - struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; - - rwlock_init(&ei->i_meta_lock); -#ifdef CONFIG_EXT2_FS_XATTR - init_rwsem(&ei->xattr_sem); -#endif - mutex_init(&ei->truncate_mutex); - inode_init_once(&ei->vfs_inode); -} - -static int init_inodecache(void) -{ - ext2_inode_cachep = kmem_cache_create("ext2_inode_cache", - sizeof(struct ext2_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD), - init_once); - if (ext2_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static void destroy_inodecache(void) -{ - kmem_cache_destroy(ext2_inode_cachep); -} - -static int ext2_show_options(struct seq_file *seq, struct dentry *root) -{ - struct super_block *sb = root->d_sb; - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - unsigned long def_mount_opts; - - spin_lock(&sbi->s_lock); - def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - - if (sbi->s_sb_block != 1) - seq_printf(seq, ",sb=%lu", sbi->s_sb_block); - if (test_opt(sb, MINIX_DF)) - seq_puts(seq, ",minixdf"); - if (test_opt(sb, GRPID)) - seq_puts(seq, ",grpid"); - if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS)) - seq_puts(seq, ",nogrpid"); - if (sbi->s_resuid != EXT2_DEF_RESUID || - le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) { - seq_printf(seq, ",resuid=%u", sbi->s_resuid); - } - if (sbi->s_resgid != EXT2_DEF_RESGID || - le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { - seq_printf(seq, ",resgid=%u", sbi->s_resgid); - } - if (test_opt(sb, ERRORS_RO)) { - int def_errors = le16_to_cpu(es->s_errors); - - if (def_errors == EXT2_ERRORS_PANIC || - def_errors == EXT2_ERRORS_CONTINUE) { - seq_puts(seq, ",errors=remount-ro"); - } - } - if (test_opt(sb, ERRORS_CONT)) - seq_puts(seq, ",errors=continue"); - if (test_opt(sb, ERRORS_PANIC)) - seq_puts(seq, ",errors=panic"); - if (test_opt(sb, NO_UID32)) - seq_puts(seq, ",nouid32"); - if (test_opt(sb, DEBUG)) - seq_puts(seq, ",debug"); - if (test_opt(sb, OLDALLOC)) - seq_puts(seq, ",oldalloc"); - -#ifdef CONFIG_EXT2_FS_XATTR - if (test_opt(sb, XATTR_USER)) - seq_puts(seq, ",user_xattr"); - if (!test_opt(sb, XATTR_USER) && - (def_mount_opts & EXT2_DEFM_XATTR_USER)) { - seq_puts(seq, ",nouser_xattr"); - } -#endif - -#ifdef CONFIG_EXT2_FS_POSIX_ACL - if (test_opt(sb, POSIX_ACL)) - seq_puts(seq, ",acl"); - if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT2_DEFM_ACL)) - seq_puts(seq, ",noacl"); -#endif - - if (test_opt(sb, NOBH)) - seq_puts(seq, ",nobh"); - -#if defined(CONFIG_QUOTA) - if (sbi->s_mount_opt & EXT2_MOUNT_USRQUOTA) - seq_puts(seq, ",usrquota"); - - if (sbi->s_mount_opt & EXT2_MOUNT_GRPQUOTA) - seq_puts(seq, ",grpquota"); -#endif - -#if defined(CONFIG_EXT2_FS_XIP) - if (sbi->s_mount_opt & EXT2_MOUNT_XIP) - seq_puts(seq, ",xip"); -#endif - - if (!test_opt(sb, RESERVATION)) - seq_puts(seq, ",noreservation"); - - spin_unlock(&sbi->s_lock); - return 0; -} - -#ifdef CONFIG_QUOTA -static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); -static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); -#endif - -static const struct super_operations ext2_sops = { - .alloc_inode = ext2_alloc_inode, - .destroy_inode = ext2_destroy_inode, - .write_inode = ext2_write_inode, - .evict_inode = ext2_evict_inode, - .put_super = ext2_put_super, - .write_super = ext2_write_super, - .sync_fs = ext2_sync_fs, - .statfs = ext2_statfs, - .remount_fs = ext2_remount, - .show_options = ext2_show_options, -#ifdef CONFIG_QUOTA - .quota_read = ext2_quota_read, - .quota_write = ext2_quota_write, -#endif -}; - -static struct inode *ext2_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation) -{ - struct inode *inode; - - if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO) - return ERR_PTR(-ESTALE); - if (ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count)) - return ERR_PTR(-ESTALE); - - /* - * ext2_iget isn't quite right if the inode is currently unallocated! - * However ext2_iget currently does appropriate checks to handle stale - * inodes so everything is OK. - */ - inode = ext2_iget(sb, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { - /* we didn't find the right inode.. */ - iput(inode); - return ERR_PTR(-ESTALE); - } - return inode; -} - -static struct dentry *ext2_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - ext2_nfs_get_inode); -} - -static struct dentry *ext2_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - ext2_nfs_get_inode); -} - -/* Yes, most of these are left as NULL!! - * A NULL value implies the default, which works with ext2-like file - * systems, but can be improved upon. - * Currently only get_parent is required. - */ -static const struct export_operations ext2_export_ops = { - .fh_to_dentry = ext2_fh_to_dentry, - .fh_to_parent = ext2_fh_to_parent, - .get_parent = ext2_get_parent, -}; - -static unsigned long get_sb_block(void **data) -{ - unsigned long sb_block; - char *options = (char *) *data; - - if (!options || strncmp(options, "sb=", 3) != 0) - return 1; /* Default location */ - options += 3; - sb_block = simple_strtoul(options, &options, 0); - if (*options && *options != ',') { - printk("EXT2-fs: Invalid sb specification: %s\n", - (char *) *data); - return 1; - } - if (*options == ',') - options++; - *data = (void *) options; - return sb_block; -} - -enum { - Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, - Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, - Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, - Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, - Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation -}; - -static const match_table_t tokens = { - {Opt_bsd_df, "bsddf"}, - {Opt_minix_df, "minixdf"}, - {Opt_grpid, "grpid"}, - {Opt_grpid, "bsdgroups"}, - {Opt_nogrpid, "nogrpid"}, - {Opt_nogrpid, "sysvgroups"}, - {Opt_resgid, "resgid=%u"}, - {Opt_resuid, "resuid=%u"}, - {Opt_sb, "sb=%u"}, - {Opt_err_cont, "errors=continue"}, - {Opt_err_panic, "errors=panic"}, - {Opt_err_ro, "errors=remount-ro"}, - {Opt_nouid32, "nouid32"}, - {Opt_nocheck, "check=none"}, - {Opt_nocheck, "nocheck"}, - {Opt_debug, "debug"}, - {Opt_oldalloc, "oldalloc"}, - {Opt_orlov, "orlov"}, - {Opt_nobh, "nobh"}, - {Opt_user_xattr, "user_xattr"}, - {Opt_nouser_xattr, "nouser_xattr"}, - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_xip, "xip"}, - {Opt_grpquota, "grpquota"}, - {Opt_ignore, "noquota"}, - {Opt_quota, "quota"}, - {Opt_usrquota, "usrquota"}, - {Opt_reservation, "reservation"}, - {Opt_noreservation, "noreservation"}, - {Opt_err, NULL} -}; - -static int parse_options(char *options, struct super_block *sb) -{ - char *p; - struct ext2_sb_info *sbi = EXT2_SB(sb); - substring_t args[MAX_OPT_ARGS]; - int option; - - if (!options) - return 1; - - while ((p = strsep (&options, ",")) != NULL) { - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_bsd_df: - clear_opt (sbi->s_mount_opt, MINIX_DF); - break; - case Opt_minix_df: - set_opt (sbi->s_mount_opt, MINIX_DF); - break; - case Opt_grpid: - set_opt (sbi->s_mount_opt, GRPID); - break; - case Opt_nogrpid: - clear_opt (sbi->s_mount_opt, GRPID); - break; - case Opt_resuid: - if (match_int(&args[0], &option)) - return 0; - sbi->s_resuid = option; - break; - case Opt_resgid: - if (match_int(&args[0], &option)) - return 0; - sbi->s_resgid = option; - break; - case Opt_sb: - /* handled by get_sb_block() instead of here */ - /* *sb_block = match_int(&args[0]); */ - break; - case Opt_err_panic: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_RO); - set_opt (sbi->s_mount_opt, ERRORS_PANIC); - break; - case Opt_err_ro: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_RO); - break; - case Opt_err_cont: - clear_opt (sbi->s_mount_opt, ERRORS_RO); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_CONT); - break; - case Opt_nouid32: - set_opt (sbi->s_mount_opt, NO_UID32); - break; - case Opt_nocheck: - clear_opt (sbi->s_mount_opt, CHECK); - break; - case Opt_debug: - set_opt (sbi->s_mount_opt, DEBUG); - break; - case Opt_oldalloc: - set_opt (sbi->s_mount_opt, OLDALLOC); - break; - case Opt_orlov: - clear_opt (sbi->s_mount_opt, OLDALLOC); - break; - case Opt_nobh: - set_opt (sbi->s_mount_opt, NOBH); - break; -#ifdef CONFIG_EXT2_FS_XATTR - case Opt_user_xattr: - set_opt (sbi->s_mount_opt, XATTR_USER); - break; - case Opt_nouser_xattr: - clear_opt (sbi->s_mount_opt, XATTR_USER); - break; -#else - case Opt_user_xattr: - case Opt_nouser_xattr: - ext2_msg(sb, KERN_INFO, "(no)user_xattr options" - "not supported"); - break; -#endif -#ifdef CONFIG_EXT2_FS_POSIX_ACL - case Opt_acl: - set_opt(sbi->s_mount_opt, POSIX_ACL); - break; - case Opt_noacl: - clear_opt(sbi->s_mount_opt, POSIX_ACL); - break; -#else - case Opt_acl: - case Opt_noacl: - ext2_msg(sb, KERN_INFO, - "(no)acl options not supported"); - break; -#endif - case Opt_xip: -#ifdef CONFIG_EXT2_FS_XIP - set_opt (sbi->s_mount_opt, XIP); -#else - ext2_msg(sb, KERN_INFO, "xip option not supported"); -#endif - break; - -#if defined(CONFIG_QUOTA) - case Opt_quota: - case Opt_usrquota: - set_opt(sbi->s_mount_opt, USRQUOTA); - break; - - case Opt_grpquota: - set_opt(sbi->s_mount_opt, GRPQUOTA); - break; -#else - case Opt_quota: - case Opt_usrquota: - case Opt_grpquota: - ext2_msg(sb, KERN_INFO, - "quota operations not supported"); - break; -#endif - - case Opt_reservation: - set_opt(sbi->s_mount_opt, RESERVATION); - ext2_msg(sb, KERN_INFO, "reservations ON"); - break; - case Opt_noreservation: - clear_opt(sbi->s_mount_opt, RESERVATION); - ext2_msg(sb, KERN_INFO, "reservations OFF"); - break; - case Opt_ignore: - break; - default: - return 0; - } - } - return 1; -} - -static int ext2_setup_super (struct super_block * sb, - struct ext2_super_block * es, - int read_only) -{ - int res = 0; - struct ext2_sb_info *sbi = EXT2_SB(sb); - - if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) { - ext2_msg(sb, KERN_ERR, - "error: revision level too high, " - "forcing read-only mode"); - res = MS_RDONLY; - } - if (read_only) - return res; - if (!(sbi->s_mount_state & EXT2_VALID_FS)) - ext2_msg(sb, KERN_WARNING, - "warning: mounting unchecked fs, " - "running e2fsck is recommended"); - else if ((sbi->s_mount_state & EXT2_ERROR_FS)) - ext2_msg(sb, KERN_WARNING, - "warning: mounting fs with errors, " - "running e2fsck is recommended"); - else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && - le16_to_cpu(es->s_mnt_count) >= - (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) - ext2_msg(sb, KERN_WARNING, - "warning: maximal mount count reached, " - "running e2fsck is recommended"); - else if (le32_to_cpu(es->s_checkinterval) && - (le32_to_cpu(es->s_lastcheck) + - le32_to_cpu(es->s_checkinterval) <= get_seconds())) - ext2_msg(sb, KERN_WARNING, - "warning: checktime reached, " - "running e2fsck is recommended"); - if (!le16_to_cpu(es->s_max_mnt_count)) - es->s_max_mnt_count = cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT); - le16_add_cpu(&es->s_mnt_count, 1); - if (test_opt (sb, DEBUG)) - ext2_msg(sb, KERN_INFO, "%s, %s, bs=%lu, fs=%lu, gc=%lu, " - "bpg=%lu, ipg=%lu, mo=%04lx]", - EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, - sbi->s_frag_size, - sbi->s_groups_count, - EXT2_BLOCKS_PER_GROUP(sb), - EXT2_INODES_PER_GROUP(sb), - sbi->s_mount_opt); - return res; -} - -static int ext2_check_descriptors(struct super_block *sb) -{ - int i; - struct ext2_sb_info *sbi = EXT2_SB(sb); - - ext2_debug ("Checking group descriptors"); - - for (i = 0; i < sbi->s_groups_count; i++) { - struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); - ext2_fsblk_t first_block = ext2_group_first_block_no(sb, i); - ext2_fsblk_t last_block; - - if (i == sbi->s_groups_count - 1) - last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; - else - last_block = first_block + - (EXT2_BLOCKS_PER_GROUP(sb) - 1); - - if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || - le32_to_cpu(gdp->bg_block_bitmap) > last_block) - { - ext2_error (sb, "ext2_check_descriptors", - "Block bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); - return 0; - } - if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || - le32_to_cpu(gdp->bg_inode_bitmap) > last_block) - { - ext2_error (sb, "ext2_check_descriptors", - "Inode bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); - return 0; - } - if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > - last_block) - { - ext2_error (sb, "ext2_check_descriptors", - "Inode table for group %d" - " not in group (block %lu)!", - i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); - return 0; - } - } - return 1; -} - -/* - * Maximal file size. There is a direct, and {,double-,triple-}indirect - * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. - * We need to be 1 filesystem block less than the 2^32 sector limit. - */ -static loff_t ext2_max_size(int bits) -{ - loff_t res = EXT2_NDIR_BLOCKS; - int meta_blocks; - loff_t upper_limit; - - /* This is calculated to be the largest file size for a - * dense, file such that the total number of - * sectors in the file, including data and all indirect blocks, - * does not exceed 2^32 -1 - * __u32 i_blocks representing the total number of - * 512 bytes blocks of the file - */ - upper_limit = (1LL << 32) - 1; - - /* total blocks in file system block size */ - upper_limit >>= (bits - 9); - - - /* indirect blocks */ - meta_blocks = 1; - /* double indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)); - /* tripple indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); - - upper_limit -= meta_blocks; - upper_limit <<= bits; - - res += 1LL << (bits-2); - res += 1LL << (2*(bits-2)); - res += 1LL << (3*(bits-2)); - res <<= bits; - if (res > upper_limit) - res = upper_limit; - - if (res > MAX_LFS_FILESIZE) - res = MAX_LFS_FILESIZE; - - return res; -} - -static unsigned long descriptor_loc(struct super_block *sb, - unsigned long logic_sb_block, - int nr) -{ - struct ext2_sb_info *sbi = EXT2_SB(sb); - unsigned long bg, first_meta_bg; - int has_super = 0; - - first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); - - if (!EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_META_BG) || - nr < first_meta_bg) - return (logic_sb_block + nr + 1); - bg = sbi->s_desc_per_block * nr; - if (ext2_bg_has_super(sb, bg)) - has_super = 1; - - return ext2_group_first_block_no(sb, bg) + has_super; -} - -static int ext2_fill_super(struct super_block *sb, void *data, int silent) -{ - struct buffer_head * bh; - struct ext2_sb_info * sbi; - struct ext2_super_block * es; - struct inode *root; - unsigned long block; - unsigned long sb_block = get_sb_block(&data); - unsigned long logic_sb_block; - unsigned long offset = 0; - unsigned long def_mount_opts; - long ret = -EINVAL; - int blocksize = BLOCK_SIZE; - int db_count; - int i, j; - __le32 features; - int err; - - err = -ENOMEM; - sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); - if (!sbi) - goto failed_unlock; - - sbi->s_blockgroup_lock = - kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); - if (!sbi->s_blockgroup_lock) { - kfree(sbi); - goto failed_unlock; - } - sb->s_fs_info = sbi; - sbi->s_sb_block = sb_block; - - spin_lock_init(&sbi->s_lock); - - /* - * See what the current blocksize for the device is, and - * use that as the blocksize. Otherwise (or if the blocksize - * is smaller than the default) use the default. - * This is important for devices that have a hardware - * sectorsize that is larger than the default. - */ - blocksize = sb_min_blocksize(sb, BLOCK_SIZE); - if (!blocksize) { - ext2_msg(sb, KERN_ERR, "error: unable to set blocksize"); - goto failed_sbi; - } - - /* - * If the superblock doesn't start on a hardware sector boundary, - * calculate the offset. - */ - if (blocksize != BLOCK_SIZE) { - logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; - offset = (sb_block*BLOCK_SIZE) % blocksize; - } else { - logic_sb_block = sb_block; - } - - if (!(bh = sb_bread(sb, logic_sb_block))) { - ext2_msg(sb, KERN_ERR, "error: unable to read superblock"); - goto failed_sbi; - } - /* - * Note: s_es must be initialized as soon as possible because - * some ext2 macro-instructions depend on its value - */ - es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); - sbi->s_es = es; - sb->s_magic = le16_to_cpu(es->s_magic); - - if (sb->s_magic != EXT2_SUPER_MAGIC) - goto cantfind_ext2; - - /* Set defaults before we parse the mount options */ - def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - if (def_mount_opts & EXT2_DEFM_DEBUG) - set_opt(sbi->s_mount_opt, DEBUG); - if (def_mount_opts & EXT2_DEFM_BSDGROUPS) - set_opt(sbi->s_mount_opt, GRPID); - if (def_mount_opts & EXT2_DEFM_UID16) - set_opt(sbi->s_mount_opt, NO_UID32); -#ifdef CONFIG_EXT2_FS_XATTR - if (def_mount_opts & EXT2_DEFM_XATTR_USER) - set_opt(sbi->s_mount_opt, XATTR_USER); -#endif -#ifdef CONFIG_EXT2_FS_POSIX_ACL - if (def_mount_opts & EXT2_DEFM_ACL) - set_opt(sbi->s_mount_opt, POSIX_ACL); -#endif - - if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) - set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE) - set_opt(sbi->s_mount_opt, ERRORS_CONT); - else - set_opt(sbi->s_mount_opt, ERRORS_RO); - - sbi->s_resuid = le16_to_cpu(es->s_def_resuid); - sbi->s_resgid = le16_to_cpu(es->s_def_resgid); - - set_opt(sbi->s_mount_opt, RESERVATION); - - if (!parse_options((char *) data, sb)) - goto failed_mount; - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? - MS_POSIXACL : 0); - - ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset - EXT2_MOUNT_XIP if not */ - - if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && - (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || - EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || - EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U))) - ext2_msg(sb, KERN_WARNING, - "warning: feature flags set on rev 0 fs, " - "running e2fsck is recommended"); - /* - * Check feature flags regardless of the revision level, since we - * previously didn't change the revision level when setting the flags, - * so there is a chance incompat flags are set on a rev 0 filesystem. - */ - features = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP); - if (features) { - ext2_msg(sb, KERN_ERR, "error: couldn't mount because of " - "unsupported optional features (%x)", - le32_to_cpu(features)); - goto failed_mount; - } - if (!(sb->s_flags & MS_RDONLY) && - (features = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){ - ext2_msg(sb, KERN_ERR, "error: couldn't mount RDWR because of " - "unsupported optional features (%x)", - le32_to_cpu(features)); - goto failed_mount; - } - - blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); - - if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) { - if (!silent) - ext2_msg(sb, KERN_ERR, - "error: unsupported blocksize for xip"); - goto failed_mount; - } - - /* If the blocksize doesn't match, re-read the thing.. */ - if (sb->s_blocksize != blocksize) { - brelse(bh); - - if (!sb_set_blocksize(sb, blocksize)) { - ext2_msg(sb, KERN_ERR, - "error: bad blocksize %d", blocksize); - goto failed_sbi; - } - - logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; - offset = (sb_block*BLOCK_SIZE) % blocksize; - bh = sb_bread(sb, logic_sb_block); - if(!bh) { - ext2_msg(sb, KERN_ERR, "error: couldn't read" - "superblock on 2nd try"); - goto failed_sbi; - } - es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); - sbi->s_es = es; - if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) { - ext2_msg(sb, KERN_ERR, "error: magic mismatch"); - goto failed_mount; - } - } - - sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); - sb->s_max_links = EXT2_LINK_MAX; - - if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { - sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if ((sbi->s_inode_size < EXT2_GOOD_OLD_INODE_SIZE) || - !is_power_of_2(sbi->s_inode_size) || - (sbi->s_inode_size > blocksize)) { - ext2_msg(sb, KERN_ERR, - "error: unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - } - - sbi->s_frag_size = EXT2_MIN_FRAG_SIZE << - le32_to_cpu(es->s_log_frag_size); - if (sbi->s_frag_size == 0) - goto cantfind_ext2; - sbi->s_frags_per_block = sb->s_blocksize / sbi->s_frag_size; - - sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); - sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); - sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - - if (EXT2_INODE_SIZE(sb) == 0) - goto cantfind_ext2; - sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb); - if (sbi->s_inodes_per_block == 0 || sbi->s_inodes_per_group == 0) - goto cantfind_ext2; - sbi->s_itb_per_group = sbi->s_inodes_per_group / - sbi->s_inodes_per_block; - sbi->s_desc_per_block = sb->s_blocksize / - sizeof (struct ext2_group_desc); - sbi->s_sbh = bh; - sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = - ilog2 (EXT2_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = - ilog2 (EXT2_DESC_PER_BLOCK(sb)); - - if (sb->s_magic != EXT2_SUPER_MAGIC) - goto cantfind_ext2; - - if (sb->s_blocksize != bh->b_size) { - if (!silent) - ext2_msg(sb, KERN_ERR, "error: unsupported blocksize"); - goto failed_mount; - } - - if (sb->s_blocksize != sbi->s_frag_size) { - ext2_msg(sb, KERN_ERR, - "error: fragsize %lu != blocksize %lu" - "(not supported yet)", - sbi->s_frag_size, sb->s_blocksize); - goto failed_mount; - } - - if (sbi->s_blocks_per_group > sb->s_blocksize * 8) { - ext2_msg(sb, KERN_ERR, - "error: #blocks per group too big: %lu", - sbi->s_blocks_per_group); - goto failed_mount; - } - if (sbi->s_frags_per_group > sb->s_blocksize * 8) { - ext2_msg(sb, KERN_ERR, - "error: #fragments per group too big: %lu", - sbi->s_frags_per_group); - goto failed_mount; - } - if (sbi->s_inodes_per_group > sb->s_blocksize * 8) { - ext2_msg(sb, KERN_ERR, - "error: #inodes per group too big: %lu", - sbi->s_inodes_per_group); - goto failed_mount; - } - - if (EXT2_BLOCKS_PER_GROUP(sb) == 0) - goto cantfind_ext2; - sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) - 1) - / EXT2_BLOCKS_PER_GROUP(sb)) + 1; - db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / - EXT2_DESC_PER_BLOCK(sb); - sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); - if (sbi->s_group_desc == NULL) { - ext2_msg(sb, KERN_ERR, "error: not enough memory"); - goto failed_mount; - } - bgl_lock_init(sbi->s_blockgroup_lock); - sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL); - if (!sbi->s_debts) { - ext2_msg(sb, KERN_ERR, "error: not enough memory"); - goto failed_mount_group_desc; - } - for (i = 0; i < db_count; i++) { - block = descriptor_loc(sb, logic_sb_block, i); - sbi->s_group_desc[i] = sb_bread(sb, block); - if (!sbi->s_group_desc[i]) { - for (j = 0; j < i; j++) - brelse (sbi->s_group_desc[j]); - ext2_msg(sb, KERN_ERR, - "error: unable to read group descriptors"); - goto failed_mount_group_desc; - } - } - if (!ext2_check_descriptors (sb)) { - ext2_msg(sb, KERN_ERR, "group descriptors corrupted"); - goto failed_mount2; - } - sbi->s_gdb_count = db_count; - get_random_bytes(&sbi->s_next_generation, sizeof(u32)); - spin_lock_init(&sbi->s_next_gen_lock); - - /* per fileystem reservation list head & lock */ - spin_lock_init(&sbi->s_rsv_window_lock); - sbi->s_rsv_window_root = RB_ROOT; - /* - * Add a single, static dummy reservation to the start of the - * reservation window list --- it gives us a placeholder for - * append-at-start-of-list which makes the allocation logic - * _much_ simpler. - */ - sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_alloc_hit = 0; - sbi->s_rsv_window_head.rsv_goal_size = 0; - ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); - - err = percpu_counter_init(&sbi->s_freeblocks_counter, - ext2_count_free_blocks(sb)); - if (!err) { - err = percpu_counter_init(&sbi->s_freeinodes_counter, - ext2_count_free_inodes(sb)); - } - if (!err) { - err = percpu_counter_init(&sbi->s_dirs_counter, - ext2_count_dirs(sb)); - } - if (err) { - ext2_msg(sb, KERN_ERR, "error: insufficient memory"); - goto failed_mount3; - } - /* - * set up enough so that it can read an inode - */ - sb->s_op = &ext2_sops; - sb->s_export_op = &ext2_export_ops; - sb->s_xattr = ext2_xattr_handlers; - -#ifdef CONFIG_QUOTA - sb->dq_op = &dquot_operations; - sb->s_qcop = &dquot_quotactl_ops; -#endif - - root = ext2_iget(sb, EXT2_ROOT_INO); - if (IS_ERR(root)) { - ret = PTR_ERR(root); - goto failed_mount3; - } - if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { - iput(root); - ext2_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); - goto failed_mount3; - } - - sb->s_root = d_make_root(root); - if (!sb->s_root) { - ext2_msg(sb, KERN_ERR, "error: get root inode failed"); - ret = -ENOMEM; - goto failed_mount3; - } - if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) - ext2_msg(sb, KERN_WARNING, - "warning: mounting ext3 filesystem as ext2"); - if (ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY)) - sb->s_flags |= MS_RDONLY; - ext2_write_super(sb); - return 0; - -cantfind_ext2: - if (!silent) - ext2_msg(sb, KERN_ERR, - "error: can't find an ext2 filesystem on dev %s.", - sb->s_id); - goto failed_mount; -failed_mount3: - percpu_counter_destroy(&sbi->s_freeblocks_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); -failed_mount2: - for (i = 0; i < db_count; i++) - brelse(sbi->s_group_desc[i]); -failed_mount_group_desc: - kfree(sbi->s_group_desc); - kfree(sbi->s_debts); -failed_mount: - brelse(bh); -failed_sbi: - sb->s_fs_info = NULL; - kfree(sbi->s_blockgroup_lock); - kfree(sbi); -failed_unlock: - return ret; -} - -static void ext2_clear_super_error(struct super_block *sb) -{ - struct buffer_head *sbh = EXT2_SB(sb)->s_sbh; - - if (buffer_write_io_error(sbh)) { - /* - * Oh, dear. A previous attempt to write the - * superblock failed. This could happen because the - * USB device was yanked out. Or it could happen to - * be a transient write error and maybe the block will - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ - ext2_msg(sb, KERN_ERR, - "previous I/O error to superblock detected\n"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } -} - -static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es, - int wait) -{ - ext2_clear_super_error(sb); - spin_lock(&EXT2_SB(sb)->s_lock); - es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); - es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); - es->s_wtime = cpu_to_le32(get_seconds()); - /* unlock before we do IO */ - spin_unlock(&EXT2_SB(sb)->s_lock); - mark_buffer_dirty(EXT2_SB(sb)->s_sbh); - if (wait) - sync_dirty_buffer(EXT2_SB(sb)->s_sbh); - sb->s_dirt = 0; -} - -/* - * In the second extended file system, it is not necessary to - * write the super block since we use a mapping of the - * disk super block in a buffer. - * - * However, this function is still used to set the fs valid - * flags to 0. We need to set this flag to 0 since the fs - * may have been checked while mounted and e2fsck may have - * set s_state to EXT2_VALID_FS after some corrections. - */ -static int ext2_sync_fs(struct super_block *sb, int wait) -{ - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = EXT2_SB(sb)->s_es; - - spin_lock(&sbi->s_lock); - if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { - ext2_debug("setting valid to 0\n"); - es->s_state &= cpu_to_le16(~EXT2_VALID_FS); - } - spin_unlock(&sbi->s_lock); - ext2_sync_super(sb, es, wait); - return 0; -} - - -void ext2_write_super(struct super_block *sb) -{ - if (!(sb->s_flags & MS_RDONLY)) - ext2_sync_fs(sb, 1); - else - sb->s_dirt = 0; -} - -static int ext2_remount (struct super_block * sb, int * flags, char * data) -{ - struct ext2_sb_info * sbi = EXT2_SB(sb); - struct ext2_super_block * es; - unsigned long old_mount_opt = sbi->s_mount_opt; - struct ext2_mount_options old_opts; - unsigned long old_sb_flags; - int err; - - spin_lock(&sbi->s_lock); - - /* Store the old options */ - old_sb_flags = sb->s_flags; - old_opts.s_mount_opt = sbi->s_mount_opt; - old_opts.s_resuid = sbi->s_resuid; - old_opts.s_resgid = sbi->s_resgid; - - /* - * Allow the "check" option to be passed as a remount option. - */ - if (!parse_options(data, sb)) { - err = -EINVAL; - goto restore_opts; - } - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); - - ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset - EXT2_MOUNT_XIP if not */ - - if ((ext2_use_xip(sb)) && (sb->s_blocksize != PAGE_SIZE)) { - ext2_msg(sb, KERN_WARNING, - "warning: unsupported blocksize for xip"); - err = -EINVAL; - goto restore_opts; - } - - es = sbi->s_es; - if ((sbi->s_mount_opt ^ old_mount_opt) & EXT2_MOUNT_XIP) { - ext2_msg(sb, KERN_WARNING, "warning: refusing change of " - "xip flag with busy inodes while remounting"); - sbi->s_mount_opt &= ~EXT2_MOUNT_XIP; - sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; - } - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { - spin_unlock(&sbi->s_lock); - return 0; - } - if (*flags & MS_RDONLY) { - if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || - !(sbi->s_mount_state & EXT2_VALID_FS)) { - spin_unlock(&sbi->s_lock); - return 0; - } - - /* - * OK, we are remounting a valid rw partition rdonly, so set - * the rdonly flag and then mark the partition as valid again. - */ - es->s_state = cpu_to_le16(sbi->s_mount_state); - es->s_mtime = cpu_to_le32(get_seconds()); - spin_unlock(&sbi->s_lock); - - err = dquot_suspend(sb, -1); - if (err < 0) { - spin_lock(&sbi->s_lock); - goto restore_opts; - } - - ext2_sync_super(sb, es, 1); - } else { - __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, - ~EXT2_FEATURE_RO_COMPAT_SUPP); - if (ret) { - ext2_msg(sb, KERN_WARNING, - "warning: couldn't remount RDWR because of " - "unsupported optional features (%x).", - le32_to_cpu(ret)); - err = -EROFS; - goto restore_opts; - } - /* - * Mounting a RDONLY partition read-write, so reread and - * store the current valid flag. (It may have been changed - * by e2fsck since we originally mounted the partition.) - */ - sbi->s_mount_state = le16_to_cpu(es->s_state); - if (!ext2_setup_super (sb, es, 0)) - sb->s_flags &= ~MS_RDONLY; - spin_unlock(&sbi->s_lock); - - ext2_write_super(sb); - - dquot_resume(sb, -1); - } - - return 0; -restore_opts: - sbi->s_mount_opt = old_opts.s_mount_opt; - sbi->s_resuid = old_opts.s_resuid; - sbi->s_resgid = old_opts.s_resgid; - sb->s_flags = old_sb_flags; - spin_unlock(&sbi->s_lock); - return err; -} - -static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) -{ - struct super_block *sb = dentry->d_sb; - struct ext2_sb_info *sbi = EXT2_SB(sb); - struct ext2_super_block *es = sbi->s_es; - u64 fsid; - - spin_lock(&sbi->s_lock); - - if (test_opt (sb, MINIX_DF)) - sbi->s_overhead_last = 0; - else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { - unsigned long i, overhead = 0; - smp_rmb(); - - /* - * Compute the overhead (FS structures). This is constant - * for a given filesystem unless the number of block groups - * changes so we cache the previous value until it does. - */ - - /* - * All of the blocks before first_data_block are - * overhead - */ - overhead = le32_to_cpu(es->s_first_data_block); - - /* - * Add the overhead attributed to the superblock and - * block group descriptors. If the sparse superblocks - * feature is turned on, then not all groups have this. - */ - for (i = 0; i < sbi->s_groups_count; i++) - overhead += ext2_bg_has_super(sb, i) + - ext2_bg_num_gdb(sb, i); - - /* - * Every block group has an inode bitmap, a block - * bitmap, and an inode table. - */ - overhead += (sbi->s_groups_count * - (2 + sbi->s_itb_per_group)); - sbi->s_overhead_last = overhead; - smp_wmb(); - sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); - } - - buf->f_type = EXT2_SUPER_MAGIC; - buf->f_bsize = sb->s_blocksize; - buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; - buf->f_bfree = ext2_count_free_blocks(sb); - es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); - buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); - if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) - buf->f_bavail = 0; - buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = ext2_count_free_inodes(sb); - es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); - buf->f_namelen = EXT2_NAME_LEN; - fsid = le64_to_cpup((void *)es->s_uuid) ^ - le64_to_cpup((void *)es->s_uuid + sizeof(u64)); - buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; - buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; - spin_unlock(&sbi->s_lock); - return 0; -} - -static struct dentry *ext2_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super); -} - -#ifdef CONFIG_QUOTA - -/* Read data from quotafile - avoid pagecache and such because we cannot afford - * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and no one else should touch the files) - * we don't have to be afraid of races */ -static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t toread; - struct buffer_head tmp_bh; - struct buffer_head *bh; - loff_t i_size = i_size_read(inode); - - if (off > i_size) - return 0; - if (off+len > i_size) - len = i_size-off; - toread = len; - while (toread > 0) { - tocopy = sb->s_blocksize - offset < toread ? - sb->s_blocksize - offset : toread; - - tmp_bh.b_state = 0; - tmp_bh.b_size = sb->s_blocksize; - err = ext2_get_block(inode, blk, &tmp_bh, 0); - if (err < 0) - return err; - if (!buffer_mapped(&tmp_bh)) /* A hole? */ - memset(data, 0, tocopy); - else { - bh = sb_bread(sb, tmp_bh.b_blocknr); - if (!bh) - return -EIO; - memcpy(data, bh->b_data+offset, tocopy); - brelse(bh); - } - offset = 0; - toread -= tocopy; - data += tocopy; - blk++; - } - return len; -} - -/* Write to quotafile */ -static ssize_t ext2_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t towrite = len; - struct buffer_head tmp_bh; - struct buffer_head *bh; - - mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); - while (towrite > 0) { - tocopy = sb->s_blocksize - offset < towrite ? - sb->s_blocksize - offset : towrite; - - tmp_bh.b_state = 0; - err = ext2_get_block(inode, blk, &tmp_bh, 1); - if (err < 0) - goto out; - if (offset || tocopy != EXT2_BLOCK_SIZE(sb)) - bh = sb_bread(sb, tmp_bh.b_blocknr); - else - bh = sb_getblk(sb, tmp_bh.b_blocknr); - if (!bh) { - err = -EIO; - goto out; - } - lock_buffer(bh); - memcpy(bh->b_data+offset, data, tocopy); - flush_dcache_page(bh->b_page); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - unlock_buffer(bh); - brelse(bh); - offset = 0; - towrite -= tocopy; - data += tocopy; - blk++; - } -out: - if (len == towrite) { - mutex_unlock(&inode->i_mutex); - return err; - } - if (inode->i_size < off+len-towrite) - i_size_write(inode, off+len-towrite); - inode->i_version++; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - mutex_unlock(&inode->i_mutex); - return len - towrite; -} - -#endif - -static struct file_system_type ext2_fs_type = { - .owner = THIS_MODULE, - .name = "ext2", - .mount = ext2_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - -static int __init init_ext2_fs(void) -{ - int err = init_ext2_xattr(); - if (err) - return err; - err = init_inodecache(); - if (err) - goto out1; - err = register_filesystem(&ext2_fs_type); - if (err) - goto out; - return 0; -out: - destroy_inodecache(); -out1: - exit_ext2_xattr(); - return err; -} - -static void __exit exit_ext2_fs(void) -{ - unregister_filesystem(&ext2_fs_type); - destroy_inodecache(); - exit_ext2_xattr(); -} - -MODULE_AUTHOR("Remy Card and others"); -MODULE_DESCRIPTION("Second Extended Filesystem"); -MODULE_LICENSE("GPL"); -module_init(init_ext2_fs) -module_exit(exit_ext2_fs) diff --git a/ANDROID_3.4.5/fs/ext2/symlink.c b/ANDROID_3.4.5/fs/ext2/symlink.c deleted file mode 100644 index 565cf817..00000000 --- a/ANDROID_3.4.5/fs/ext2/symlink.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/fs/ext2/symlink.c - * - * Only fast symlinks left here - the rest is done by generic code. AV, 1999 - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/symlink.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext2 symlink handling code - */ - -#include "ext2.h" -#include "xattr.h" -#include <linux/namei.h> - -static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd) -{ - struct ext2_inode_info *ei = EXT2_I(dentry->d_inode); - nd_set_link(nd, (char *)ei->i_data); - return NULL; -} - -const struct inode_operations ext2_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = page_follow_link_light, - .put_link = page_put_link, - .setattr = ext2_setattr, -#ifdef CONFIG_EXT2_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext2_listxattr, - .removexattr = generic_removexattr, -#endif -}; - -const struct inode_operations ext2_fast_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = ext2_follow_link, - .setattr = ext2_setattr, -#ifdef CONFIG_EXT2_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext2_listxattr, - .removexattr = generic_removexattr, -#endif -}; diff --git a/ANDROID_3.4.5/fs/ext2/xattr.c b/ANDROID_3.4.5/fs/ext2/xattr.c deleted file mode 100644 index 6dcafc7e..00000000 --- a/ANDROID_3.4.5/fs/ext2/xattr.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * linux/fs/ext2/xattr.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher <agruen@suse.de> - * - * Fix by Harrison Xing <harrison@mountainviewdata.com>. - * Extended attributes for symlinks and special files added per - * suggestion of Luka Renko <luka.renko@hermes.si>. - * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, - * Red Hat Inc. - * - */ - -/* - * Extended attributes are stored on disk blocks allocated outside of - * any inode. The i_file_acl field is then made to point to this allocated - * block. If all extended attributes of an inode are identical, these - * inodes may share the same extended attribute block. Such situations - * are automatically detected by keeping a cache of recent attribute block - * numbers and hashes over the block's contents in memory. - * - * - * Extended attribute block layout: - * - * +------------------+ - * | header | - * | entry 1 | | - * | entry 2 | | growing downwards - * | entry 3 | v - * | four null bytes | - * | . . . | - * | value 1 | ^ - * | value 3 | | growing upwards - * | value 2 | | - * +------------------+ - * - * The block header is followed by multiple entry descriptors. These entry - * descriptors are variable in size, and aligned to EXT2_XATTR_PAD - * byte boundaries. The entry descriptors are sorted by attribute name, - * so that two extended attribute blocks can be compared efficiently. - * - * Attribute values are aligned to the end of the block, stored in - * no specific order. They are also padded to EXT2_XATTR_PAD byte - * boundaries. No additional gaps are left between them. - * - * Locking strategy - * ---------------- - * EXT2_I(inode)->i_file_acl is protected by EXT2_I(inode)->xattr_sem. - * EA blocks are only changed if they are exclusive to an inode, so - * holding xattr_sem also means that nothing but the EA block's reference - * count will change. Multiple writers to an EA block are synchronized - * by the bh lock. No more than a single bh lock is held at any time - * to avoid deadlocks. - */ - -#include <linux/buffer_head.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/mbcache.h> -#include <linux/quotaops.h> -#include <linux/rwsem.h> -#include <linux/security.h> -#include "ext2.h" -#include "xattr.h" -#include "acl.h" - -#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) -#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) -#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) -#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) - -#ifdef EXT2_XATTR_DEBUG -# define ea_idebug(inode, f...) do { \ - printk(KERN_DEBUG "inode %s:%ld: ", \ - inode->i_sb->s_id, inode->i_ino); \ - printk(f); \ - printk("\n"); \ - } while (0) -# define ea_bdebug(bh, f...) do { \ - char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%lu: ", \ - bdevname(bh->b_bdev, b), \ - (unsigned long) bh->b_blocknr); \ - printk(f); \ - printk("\n"); \ - } while (0) -#else -# define ea_idebug(f...) -# define ea_bdebug(f...) -#endif - -static int ext2_xattr_set2(struct inode *, struct buffer_head *, - struct ext2_xattr_header *); - -static int ext2_xattr_cache_insert(struct buffer_head *); -static struct buffer_head *ext2_xattr_cache_find(struct inode *, - struct ext2_xattr_header *); -static void ext2_xattr_rehash(struct ext2_xattr_header *, - struct ext2_xattr_entry *); - -static struct mb_cache *ext2_xattr_cache; - -static const struct xattr_handler *ext2_xattr_handler_map[] = { - [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, -#ifdef CONFIG_EXT2_FS_POSIX_ACL - [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext2_xattr_acl_access_handler, - [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler, -#endif - [EXT2_XATTR_INDEX_TRUSTED] = &ext2_xattr_trusted_handler, -#ifdef CONFIG_EXT2_FS_SECURITY - [EXT2_XATTR_INDEX_SECURITY] = &ext2_xattr_security_handler, -#endif -}; - -const struct xattr_handler *ext2_xattr_handlers[] = { - &ext2_xattr_user_handler, - &ext2_xattr_trusted_handler, -#ifdef CONFIG_EXT2_FS_POSIX_ACL - &ext2_xattr_acl_access_handler, - &ext2_xattr_acl_default_handler, -#endif -#ifdef CONFIG_EXT2_FS_SECURITY - &ext2_xattr_security_handler, -#endif - NULL -}; - -static inline const struct xattr_handler * -ext2_xattr_handler(int name_index) -{ - const struct xattr_handler *handler = NULL; - - if (name_index > 0 && name_index < ARRAY_SIZE(ext2_xattr_handler_map)) - handler = ext2_xattr_handler_map[name_index]; - return handler; -} - -/* - * ext2_xattr_get() - * - * Copy an extended attribute into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -int -ext2_xattr_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - struct buffer_head *bh = NULL; - struct ext2_xattr_entry *entry; - size_t name_len, size; - char *end; - int error; - - ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", - name_index, name, buffer, (long)buffer_size); - - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - if (name_len > 255) - return -ERANGE; - - down_read(&EXT2_I(inode)->xattr_sem); - error = -ENODATA; - if (!EXT2_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); - end = bh->b_data + bh->b_size; - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - HDR(bh)->h_blocks != cpu_to_le32(1)) { -bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", - "inode %ld: bad block %d", inode->i_ino, - EXT2_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - - /* find named attribute */ - entry = FIRST_ENTRY(bh); - while (!IS_LAST_ENTRY(entry)) { - struct ext2_xattr_entry *next = - EXT2_XATTR_NEXT(entry); - if ((char *)next >= end) - goto bad_block; - if (name_index == entry->e_name_index && - name_len == entry->e_name_len && - memcmp(name, entry->e_name, name_len) == 0) - goto found; - entry = next; - } - if (ext2_xattr_cache_insert(bh)) - ea_idebug(inode, "cache insert failed"); - error = -ENODATA; - goto cleanup; -found: - /* check the buffer size */ - if (entry->e_value_block != 0) - goto bad_block; - size = le32_to_cpu(entry->e_value_size); - if (size > inode->i_sb->s_blocksize || - le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) - goto bad_block; - - if (ext2_xattr_cache_insert(bh)) - ea_idebug(inode, "cache insert failed"); - if (buffer) { - error = -ERANGE; - if (size > buffer_size) - goto cleanup; - /* return value of attribute */ - memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), - size); - } - error = size; - -cleanup: - brelse(bh); - up_read(&EXT2_I(inode)->xattr_sem); - - return error; -} - -/* - * ext2_xattr_list() - * - * Copy a list of attribute names into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -static int -ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - struct inode *inode = dentry->d_inode; - struct buffer_head *bh = NULL; - struct ext2_xattr_entry *entry; - char *end; - size_t rest = buffer_size; - int error; - - ea_idebug(inode, "buffer=%p, buffer_size=%ld", - buffer, (long)buffer_size); - - down_read(&EXT2_I(inode)->xattr_sem); - error = 0; - if (!EXT2_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); - end = bh->b_data + bh->b_size; - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - HDR(bh)->h_blocks != cpu_to_le32(1)) { -bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", - "inode %ld: bad block %d", inode->i_ino, - EXT2_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - - /* check the on-disk data structure */ - entry = FIRST_ENTRY(bh); - while (!IS_LAST_ENTRY(entry)) { - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); - - if ((char *)next >= end) - goto bad_block; - entry = next; - } - if (ext2_xattr_cache_insert(bh)) - ea_idebug(inode, "cache insert failed"); - - /* list the attribute names */ - for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); - entry = EXT2_XATTR_NEXT(entry)) { - const struct xattr_handler *handler = - ext2_xattr_handler(entry->e_name_index); - - if (handler) { - size_t size = handler->list(dentry, buffer, rest, - entry->e_name, - entry->e_name_len, - handler->flags); - if (buffer) { - if (size > rest) { - error = -ERANGE; - goto cleanup; - } - buffer += size; - } - rest -= size; - } - } - error = buffer_size - rest; /* total size */ - -cleanup: - brelse(bh); - up_read(&EXT2_I(inode)->xattr_sem); - - return error; -} - -/* - * Inode operation listxattr() - * - * dentry->d_inode->i_mutex: don't care - */ -ssize_t -ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - return ext2_xattr_list(dentry, buffer, size); -} - -/* - * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is - * not set, set it. - */ -static void ext2_xattr_update_super_block(struct super_block *sb) -{ - if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) - return; - - spin_lock(&EXT2_SB(sb)->s_lock); - EXT2_SET_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR); - spin_unlock(&EXT2_SB(sb)->s_lock); - sb->s_dirt = 1; - mark_buffer_dirty(EXT2_SB(sb)->s_sbh); -} - -/* - * ext2_xattr_set() - * - * Create, replace or remove an extended attribute for this inode. Value - * is NULL to remove an existing extended attribute, and non-NULL to - * either replace an existing extended attribute, or create a new extended - * attribute. The flags XATTR_REPLACE and XATTR_CREATE - * specify that an extended attribute must exist and must not exist - * previous to the call, respectively. - * - * Returns 0, or a negative error number on failure. - */ -int -ext2_xattr_set(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len, int flags) -{ - struct super_block *sb = inode->i_sb; - struct buffer_head *bh = NULL; - struct ext2_xattr_header *header = NULL; - struct ext2_xattr_entry *here, *last; - size_t name_len, free, min_offs = sb->s_blocksize; - int not_found = 1, error; - char *end; - - /* - * header -- Points either into bh, or to a temporarily - * allocated buffer. - * here -- The named entry found, or the place for inserting, within - * the block pointed to by header. - * last -- Points right after the last named entry within the block - * pointed to by header. - * min_offs -- The offset of the first value (values are aligned - * towards the end of the block). - * end -- Points right after the block pointed to by header. - */ - - ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", - name_index, name, value, (long)value_len); - - if (value == NULL) - value_len = 0; - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - if (name_len > 255 || value_len > sb->s_blocksize) - return -ERANGE; - down_write(&EXT2_I(inode)->xattr_sem); - if (EXT2_I(inode)->i_file_acl) { - /* The inode already has an extended attribute block. */ - bh = sb_bread(sb, EXT2_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), - le32_to_cpu(HDR(bh)->h_refcount)); - header = HDR(bh); - end = bh->b_data + bh->b_size; - if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - header->h_blocks != cpu_to_le32(1)) { -bad_block: ext2_error(sb, "ext2_xattr_set", - "inode %ld: bad block %d", inode->i_ino, - EXT2_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - /* Find the named attribute. */ - here = FIRST_ENTRY(bh); - while (!IS_LAST_ENTRY(here)) { - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); - if ((char *)next >= end) - goto bad_block; - if (!here->e_value_block && here->e_value_size) { - size_t offs = le16_to_cpu(here->e_value_offs); - if (offs < min_offs) - min_offs = offs; - } - not_found = name_index - here->e_name_index; - if (!not_found) - not_found = name_len - here->e_name_len; - if (!not_found) - not_found = memcmp(name, here->e_name,name_len); - if (not_found <= 0) - break; - here = next; - } - last = here; - /* We still need to compute min_offs and last. */ - while (!IS_LAST_ENTRY(last)) { - struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last); - if ((char *)next >= end) - goto bad_block; - if (!last->e_value_block && last->e_value_size) { - size_t offs = le16_to_cpu(last->e_value_offs); - if (offs < min_offs) - min_offs = offs; - } - last = next; - } - - /* Check whether we have enough space left. */ - free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); - } else { - /* We will use a new extended attribute block. */ - free = sb->s_blocksize - - sizeof(struct ext2_xattr_header) - sizeof(__u32); - here = last = NULL; /* avoid gcc uninitialized warning. */ - } - - if (not_found) { - /* Request to remove a nonexistent attribute? */ - error = -ENODATA; - if (flags & XATTR_REPLACE) - goto cleanup; - error = 0; - if (value == NULL) - goto cleanup; - } else { - /* Request to create an existing attribute? */ - error = -EEXIST; - if (flags & XATTR_CREATE) - goto cleanup; - if (!here->e_value_block && here->e_value_size) { - size_t size = le32_to_cpu(here->e_value_size); - - if (le16_to_cpu(here->e_value_offs) + size > - sb->s_blocksize || size > sb->s_blocksize) - goto bad_block; - free += EXT2_XATTR_SIZE(size); - } - free += EXT2_XATTR_LEN(name_len); - } - error = -ENOSPC; - if (free < EXT2_XATTR_LEN(name_len) + EXT2_XATTR_SIZE(value_len)) - goto cleanup; - - /* Here we know that we can set the new attribute. */ - - if (header) { - struct mb_cache_entry *ce; - - /* assert(header == HDR(bh)); */ - ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, - bh->b_blocknr); - lock_buffer(bh); - if (header->h_refcount == cpu_to_le32(1)) { - ea_bdebug(bh, "modifying in-place"); - if (ce) - mb_cache_entry_free(ce); - /* keep the buffer locked while modifying it. */ - } else { - int offset; - - if (ce) - mb_cache_entry_release(ce); - unlock_buffer(bh); - ea_bdebug(bh, "cloning"); - header = kmalloc(bh->b_size, GFP_KERNEL); - error = -ENOMEM; - if (header == NULL) - goto cleanup; - memcpy(header, HDR(bh), bh->b_size); - header->h_refcount = cpu_to_le32(1); - - offset = (char *)here - bh->b_data; - here = ENTRY((char *)header + offset); - offset = (char *)last - bh->b_data; - last = ENTRY((char *)header + offset); - } - } else { - /* Allocate a buffer where we construct the new block. */ - header = kzalloc(sb->s_blocksize, GFP_KERNEL); - error = -ENOMEM; - if (header == NULL) - goto cleanup; - end = (char *)header + sb->s_blocksize; - header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC); - header->h_blocks = header->h_refcount = cpu_to_le32(1); - last = here = ENTRY(header+1); - } - - /* Iff we are modifying the block in-place, bh is locked here. */ - - if (not_found) { - /* Insert the new name. */ - size_t size = EXT2_XATTR_LEN(name_len); - size_t rest = (char *)last - (char *)here; - memmove((char *)here + size, here, rest); - memset(here, 0, size); - here->e_name_index = name_index; - here->e_name_len = name_len; - memcpy(here->e_name, name, name_len); - } else { - if (!here->e_value_block && here->e_value_size) { - char *first_val = (char *)header + min_offs; - size_t offs = le16_to_cpu(here->e_value_offs); - char *val = (char *)header + offs; - size_t size = EXT2_XATTR_SIZE( - le32_to_cpu(here->e_value_size)); - - if (size == EXT2_XATTR_SIZE(value_len)) { - /* The old and the new value have the same - size. Just replace. */ - here->e_value_size = cpu_to_le32(value_len); - memset(val + size - EXT2_XATTR_PAD, 0, - EXT2_XATTR_PAD); /* Clear pad bytes. */ - memcpy(val, value, value_len); - goto skip_replace; - } - - /* Remove the old value. */ - memmove(first_val + size, first_val, val - first_val); - memset(first_val, 0, size); - here->e_value_offs = 0; - min_offs += size; - - /* Adjust all value offsets. */ - last = ENTRY(header+1); - while (!IS_LAST_ENTRY(last)) { - size_t o = le16_to_cpu(last->e_value_offs); - if (!last->e_value_block && o < offs) - last->e_value_offs = - cpu_to_le16(o + size); - last = EXT2_XATTR_NEXT(last); - } - } - if (value == NULL) { - /* Remove the old name. */ - size_t size = EXT2_XATTR_LEN(name_len); - last = ENTRY((char *)last - size); - memmove(here, (char*)here + size, - (char*)last - (char*)here); - memset(last, 0, size); - } - } - - if (value != NULL) { - /* Insert the new value. */ - here->e_value_size = cpu_to_le32(value_len); - if (value_len) { - size_t size = EXT2_XATTR_SIZE(value_len); - char *val = (char *)header + min_offs - size; - here->e_value_offs = - cpu_to_le16((char *)val - (char *)header); - memset(val + size - EXT2_XATTR_PAD, 0, - EXT2_XATTR_PAD); /* Clear the pad bytes. */ - memcpy(val, value, value_len); - } - } - -skip_replace: - if (IS_LAST_ENTRY(ENTRY(header+1))) { - /* This block is now empty. */ - if (bh && header == HDR(bh)) - unlock_buffer(bh); /* we were modifying in-place. */ - error = ext2_xattr_set2(inode, bh, NULL); - } else { - ext2_xattr_rehash(header, here); - if (bh && header == HDR(bh)) - unlock_buffer(bh); /* we were modifying in-place. */ - error = ext2_xattr_set2(inode, bh, header); - } - -cleanup: - brelse(bh); - if (!(bh && header == HDR(bh))) - kfree(header); - up_write(&EXT2_I(inode)->xattr_sem); - - return error; -} - -/* - * Second half of ext2_xattr_set(): Update the file system. - */ -static int -ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, - struct ext2_xattr_header *header) -{ - struct super_block *sb = inode->i_sb; - struct buffer_head *new_bh = NULL; - int error; - - if (header) { - new_bh = ext2_xattr_cache_find(inode, header); - if (new_bh) { - /* We found an identical block in the cache. */ - if (new_bh == old_bh) { - ea_bdebug(new_bh, "keeping this block"); - } else { - /* The old block is released after updating - the inode. */ - ea_bdebug(new_bh, "reusing block"); - - error = dquot_alloc_block(inode, 1); - if (error) { - unlock_buffer(new_bh); - goto cleanup; - } - le32_add_cpu(&HDR(new_bh)->h_refcount, 1); - ea_bdebug(new_bh, "refcount now=%d", - le32_to_cpu(HDR(new_bh)->h_refcount)); - } - unlock_buffer(new_bh); - } else if (old_bh && header == HDR(old_bh)) { - /* Keep this block. No need to lock the block as we - don't need to change the reference count. */ - new_bh = old_bh; - get_bh(new_bh); - ext2_xattr_cache_insert(new_bh); - } else { - /* We need to allocate a new block */ - ext2_fsblk_t goal = ext2_group_first_block_no(sb, - EXT2_I(inode)->i_block_group); - int block = ext2_new_block(inode, goal, &error); - if (error) - goto cleanup; - ea_idebug(inode, "creating block %d", block); - - new_bh = sb_getblk(sb, block); - if (!new_bh) { - ext2_free_blocks(inode, block, 1); - mark_inode_dirty(inode); - error = -EIO; - goto cleanup; - } - lock_buffer(new_bh); - memcpy(new_bh->b_data, header, new_bh->b_size); - set_buffer_uptodate(new_bh); - unlock_buffer(new_bh); - ext2_xattr_cache_insert(new_bh); - - ext2_xattr_update_super_block(sb); - } - mark_buffer_dirty(new_bh); - if (IS_SYNC(inode)) { - sync_dirty_buffer(new_bh); - error = -EIO; - if (buffer_req(new_bh) && !buffer_uptodate(new_bh)) - goto cleanup; - } - } - - /* Update the inode. */ - EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; - inode->i_ctime = CURRENT_TIME_SEC; - if (IS_SYNC(inode)) { - error = sync_inode_metadata(inode, 1); - /* In case sync failed due to ENOSPC the inode was actually - * written (only some dirty data were not) so we just proceed - * as if nothing happened and cleanup the unused block */ - if (error && error != -ENOSPC) { - if (new_bh && new_bh != old_bh) { - dquot_free_block_nodirty(inode, 1); - mark_inode_dirty(inode); - } - goto cleanup; - } - } else - mark_inode_dirty(inode); - - error = 0; - if (old_bh && old_bh != new_bh) { - struct mb_cache_entry *ce; - - /* - * If there was an old block and we are no longer using it, - * release the old block. - */ - ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev, - old_bh->b_blocknr); - lock_buffer(old_bh); - if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { - /* Free the old block. */ - if (ce) - mb_cache_entry_free(ce); - ea_bdebug(old_bh, "freeing"); - ext2_free_blocks(inode, old_bh->b_blocknr, 1); - mark_inode_dirty(inode); - /* We let our caller release old_bh, so we - * need to duplicate the buffer before. */ - get_bh(old_bh); - bforget(old_bh); - } else { - /* Decrement the refcount only. */ - le32_add_cpu(&HDR(old_bh)->h_refcount, -1); - if (ce) - mb_cache_entry_release(ce); - dquot_free_block_nodirty(inode, 1); - mark_inode_dirty(inode); - mark_buffer_dirty(old_bh); - ea_bdebug(old_bh, "refcount now=%d", - le32_to_cpu(HDR(old_bh)->h_refcount)); - } - unlock_buffer(old_bh); - } - -cleanup: - brelse(new_bh); - - return error; -} - -/* - * ext2_xattr_delete_inode() - * - * Free extended attribute resources associated with this inode. This - * is called immediately before an inode is freed. - */ -void -ext2_xattr_delete_inode(struct inode *inode) -{ - struct buffer_head *bh = NULL; - struct mb_cache_entry *ce; - - down_write(&EXT2_I(inode)->xattr_sem); - if (!EXT2_I(inode)->i_file_acl) - goto cleanup; - bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl); - if (!bh) { - ext2_error(inode->i_sb, "ext2_xattr_delete_inode", - "inode %ld: block %d read error", inode->i_ino, - EXT2_I(inode)->i_file_acl); - goto cleanup; - } - ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); - if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || - HDR(bh)->h_blocks != cpu_to_le32(1)) { - ext2_error(inode->i_sb, "ext2_xattr_delete_inode", - "inode %ld: bad block %d", inode->i_ino, - EXT2_I(inode)->i_file_acl); - goto cleanup; - } - ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr); - lock_buffer(bh); - if (HDR(bh)->h_refcount == cpu_to_le32(1)) { - if (ce) - mb_cache_entry_free(ce); - ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); - get_bh(bh); - bforget(bh); - unlock_buffer(bh); - } else { - le32_add_cpu(&HDR(bh)->h_refcount, -1); - if (ce) - mb_cache_entry_release(ce); - ea_bdebug(bh, "refcount now=%d", - le32_to_cpu(HDR(bh)->h_refcount)); - unlock_buffer(bh); - mark_buffer_dirty(bh); - if (IS_SYNC(inode)) - sync_dirty_buffer(bh); - dquot_free_block_nodirty(inode, 1); - } - EXT2_I(inode)->i_file_acl = 0; - -cleanup: - brelse(bh); - up_write(&EXT2_I(inode)->xattr_sem); -} - -/* - * ext2_xattr_put_super() - * - * This is called when a file system is unmounted. - */ -void -ext2_xattr_put_super(struct super_block *sb) -{ - mb_cache_shrink(sb->s_bdev); -} - - -/* - * ext2_xattr_cache_insert() - * - * Create a new entry in the extended attribute cache, and insert - * it unless such an entry is already in the cache. - * - * Returns 0, or a negative error number on failure. - */ -static int -ext2_xattr_cache_insert(struct buffer_head *bh) -{ - __u32 hash = le32_to_cpu(HDR(bh)->h_hash); - struct mb_cache_entry *ce; - int error; - - ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); - if (!ce) - return -ENOMEM; - error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); - if (error) { - mb_cache_entry_free(ce); - if (error == -EBUSY) { - ea_bdebug(bh, "already in cache (%d cache entries)", - atomic_read(&ext2_xattr_cache->c_entry_count)); - error = 0; - } - } else { - ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, - atomic_read(&ext2_xattr_cache->c_entry_count)); - mb_cache_entry_release(ce); - } - return error; -} - -/* - * ext2_xattr_cmp() - * - * Compare two extended attribute blocks for equality. - * - * Returns 0 if the blocks are equal, 1 if they differ, and - * a negative error number on errors. - */ -static int -ext2_xattr_cmp(struct ext2_xattr_header *header1, - struct ext2_xattr_header *header2) -{ - struct ext2_xattr_entry *entry1, *entry2; - - entry1 = ENTRY(header1+1); - entry2 = ENTRY(header2+1); - while (!IS_LAST_ENTRY(entry1)) { - if (IS_LAST_ENTRY(entry2)) - return 1; - if (entry1->e_hash != entry2->e_hash || - entry1->e_name_index != entry2->e_name_index || - entry1->e_name_len != entry2->e_name_len || - entry1->e_value_size != entry2->e_value_size || - memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) - return 1; - if (entry1->e_value_block != 0 || entry2->e_value_block != 0) - return -EIO; - if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), - (char *)header2 + le16_to_cpu(entry2->e_value_offs), - le32_to_cpu(entry1->e_value_size))) - return 1; - - entry1 = EXT2_XATTR_NEXT(entry1); - entry2 = EXT2_XATTR_NEXT(entry2); - } - if (!IS_LAST_ENTRY(entry2)) - return 1; - return 0; -} - -/* - * ext2_xattr_cache_find() - * - * Find an identical extended attribute block. - * - * Returns a locked buffer head to the block found, or NULL if such - * a block was not found or an error occurred. - */ -static struct buffer_head * -ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) -{ - __u32 hash = le32_to_cpu(header->h_hash); - struct mb_cache_entry *ce; - - if (!header->h_hash) - return NULL; /* never share */ - ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); -again: - ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev, - hash); - while (ce) { - struct buffer_head *bh; - - if (IS_ERR(ce)) { - if (PTR_ERR(ce) == -EAGAIN) - goto again; - break; - } - - bh = sb_bread(inode->i_sb, ce->e_block); - if (!bh) { - ext2_error(inode->i_sb, "ext2_xattr_cache_find", - "inode %ld: block %ld read error", - inode->i_ino, (unsigned long) ce->e_block); - } else { - lock_buffer(bh); - if (le32_to_cpu(HDR(bh)->h_refcount) > - EXT2_XATTR_REFCOUNT_MAX) { - ea_idebug(inode, "block %ld refcount %d>%d", - (unsigned long) ce->e_block, - le32_to_cpu(HDR(bh)->h_refcount), - EXT2_XATTR_REFCOUNT_MAX); - } else if (!ext2_xattr_cmp(header, HDR(bh))) { - ea_bdebug(bh, "b_count=%d", - atomic_read(&(bh->b_count))); - mb_cache_entry_release(ce); - return bh; - } - unlock_buffer(bh); - brelse(bh); - } - ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); - } - return NULL; -} - -#define NAME_HASH_SHIFT 5 -#define VALUE_HASH_SHIFT 16 - -/* - * ext2_xattr_hash_entry() - * - * Compute the hash of an extended attribute. - */ -static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, - struct ext2_xattr_entry *entry) -{ - __u32 hash = 0; - char *name = entry->e_name; - int n; - - for (n=0; n < entry->e_name_len; n++) { - hash = (hash << NAME_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ - *name++; - } - - if (entry->e_value_block == 0 && entry->e_value_size != 0) { - __le32 *value = (__le32 *)((char *)header + - le16_to_cpu(entry->e_value_offs)); - for (n = (le32_to_cpu(entry->e_value_size) + - EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) { - hash = (hash << VALUE_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ - le32_to_cpu(*value++); - } - } - entry->e_hash = cpu_to_le32(hash); -} - -#undef NAME_HASH_SHIFT -#undef VALUE_HASH_SHIFT - -#define BLOCK_HASH_SHIFT 16 - -/* - * ext2_xattr_rehash() - * - * Re-compute the extended attribute hash value after an entry has changed. - */ -static void ext2_xattr_rehash(struct ext2_xattr_header *header, - struct ext2_xattr_entry *entry) -{ - struct ext2_xattr_entry *here; - __u32 hash = 0; - - ext2_xattr_hash_entry(header, entry); - here = ENTRY(header+1); - while (!IS_LAST_ENTRY(here)) { - if (!here->e_hash) { - /* Block is not shared if an entry's hash value == 0 */ - hash = 0; - break; - } - hash = (hash << BLOCK_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ - le32_to_cpu(here->e_hash); - here = EXT2_XATTR_NEXT(here); - } - header->h_hash = cpu_to_le32(hash); -} - -#undef BLOCK_HASH_SHIFT - -int __init -init_ext2_xattr(void) -{ - ext2_xattr_cache = mb_cache_create("ext2_xattr", 6); - if (!ext2_xattr_cache) - return -ENOMEM; - return 0; -} - -void -exit_ext2_xattr(void) -{ - mb_cache_destroy(ext2_xattr_cache); -} diff --git a/ANDROID_3.4.5/fs/ext2/xattr.h b/ANDROID_3.4.5/fs/ext2/xattr.h deleted file mode 100644 index 5e41cccf..00000000 --- a/ANDROID_3.4.5/fs/ext2/xattr.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - File: linux/ext2_xattr.h - - On-disk format of extended attributes for the ext2 filesystem. - - (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org> -*/ - -#include <linux/init.h> -#include <linux/xattr.h> - -/* Magic value in attribute blocks */ -#define EXT2_XATTR_MAGIC 0xEA020000 - -/* Maximum number of references to one attribute block */ -#define EXT2_XATTR_REFCOUNT_MAX 1024 - -/* Name indexes */ -#define EXT2_XATTR_INDEX_USER 1 -#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 -#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 -#define EXT2_XATTR_INDEX_TRUSTED 4 -#define EXT2_XATTR_INDEX_LUSTRE 5 -#define EXT2_XATTR_INDEX_SECURITY 6 - -struct ext2_xattr_header { - __le32 h_magic; /* magic number for identification */ - __le32 h_refcount; /* reference count */ - __le32 h_blocks; /* number of disk blocks used */ - __le32 h_hash; /* hash value of all attributes */ - __u32 h_reserved[4]; /* zero right now */ -}; - -struct ext2_xattr_entry { - __u8 e_name_len; /* length of name */ - __u8 e_name_index; /* attribute name index */ - __le16 e_value_offs; /* offset in disk block of value */ - __le32 e_value_block; /* disk block attribute is stored on (n/i) */ - __le32 e_value_size; /* size of attribute value */ - __le32 e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ -}; - -#define EXT2_XATTR_PAD_BITS 2 -#define EXT2_XATTR_PAD (1<<EXT2_XATTR_PAD_BITS) -#define EXT2_XATTR_ROUND (EXT2_XATTR_PAD-1) -#define EXT2_XATTR_LEN(name_len) \ - (((name_len) + EXT2_XATTR_ROUND + \ - sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND) -#define EXT2_XATTR_NEXT(entry) \ - ( (struct ext2_xattr_entry *)( \ - (char *)(entry) + EXT2_XATTR_LEN((entry)->e_name_len)) ) -#define EXT2_XATTR_SIZE(size) \ - (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) - -# ifdef CONFIG_EXT2_FS_XATTR - -extern const struct xattr_handler ext2_xattr_user_handler; -extern const struct xattr_handler ext2_xattr_trusted_handler; -extern const struct xattr_handler ext2_xattr_acl_access_handler; -extern const struct xattr_handler ext2_xattr_acl_default_handler; -extern const struct xattr_handler ext2_xattr_security_handler; - -extern ssize_t ext2_listxattr(struct dentry *, char *, size_t); - -extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t); -extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int); - -extern void ext2_xattr_delete_inode(struct inode *); -extern void ext2_xattr_put_super(struct super_block *); - -extern int init_ext2_xattr(void); -extern void exit_ext2_xattr(void); - -extern const struct xattr_handler *ext2_xattr_handlers[]; - -# else /* CONFIG_EXT2_FS_XATTR */ - -static inline int -ext2_xattr_get(struct inode *inode, int name_index, - const char *name, void *buffer, size_t size) -{ - return -EOPNOTSUPP; -} - -static inline int -ext2_xattr_set(struct inode *inode, int name_index, const char *name, - const void *value, size_t size, int flags) -{ - return -EOPNOTSUPP; -} - -static inline void -ext2_xattr_delete_inode(struct inode *inode) -{ -} - -static inline void -ext2_xattr_put_super(struct super_block *sb) -{ -} - -static inline int -init_ext2_xattr(void) -{ - return 0; -} - -static inline void -exit_ext2_xattr(void) -{ -} - -#define ext2_xattr_handlers NULL - -# endif /* CONFIG_EXT2_FS_XATTR */ - -#ifdef CONFIG_EXT2_FS_SECURITY -extern int ext2_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr); -#else -static inline int ext2_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - return 0; -} -#endif diff --git a/ANDROID_3.4.5/fs/ext2/xattr_security.c b/ANDROID_3.4.5/fs/ext2/xattr_security.c deleted file mode 100644 index cfedb2cb..00000000 --- a/ANDROID_3.4.5/fs/ext2/xattr_security.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * linux/fs/ext2/xattr_security.c - * Handler for storing security labels as extended attributes. - */ - -#include "ext2.h" -#include <linux/security.h> -#include "xattr.h" - -static size_t -ext2_xattr_security_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const int prefix_len = XATTR_SECURITY_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - if (list && total_len <= list_size) { - memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); - memcpy(list+prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; - } - return total_len; -} - -static int -ext2_xattr_security_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name, - buffer, size); -} - -static int -ext2_xattr_security_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_SECURITY, name, - value, size, flags); -} - -int ext2_initxattrs(struct inode *inode, const struct xattr *xattr_array, - void *fs_info) -{ - const struct xattr *xattr; - int err = 0; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - err = ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY, - xattr->name, xattr->value, - xattr->value_len, 0); - if (err < 0) - break; - } - return err; -} - -int -ext2_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - return security_inode_init_security(inode, dir, qstr, - &ext2_initxattrs, NULL); -} - -const struct xattr_handler ext2_xattr_security_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .list = ext2_xattr_security_list, - .get = ext2_xattr_security_get, - .set = ext2_xattr_security_set, -}; diff --git a/ANDROID_3.4.5/fs/ext2/xattr_trusted.c b/ANDROID_3.4.5/fs/ext2/xattr_trusted.c deleted file mode 100644 index 7e192574..00000000 --- a/ANDROID_3.4.5/fs/ext2/xattr_trusted.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/fs/ext2/xattr_trusted.c - * Handler for trusted extended attributes. - * - * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher@computer.org> - */ - -#include "ext2.h" -#include "xattr.h" - -static size_t -ext2_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const int prefix_len = XATTR_TRUSTED_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - if (!capable(CAP_SYS_ADMIN)) - return 0; - - 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 -ext2_xattr_trusted_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name, - buffer, size); -} - -static int -ext2_xattr_trusted_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_TRUSTED, name, - value, size, flags); -} - -const struct xattr_handler ext2_xattr_trusted_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .list = ext2_xattr_trusted_list, - .get = ext2_xattr_trusted_get, - .set = ext2_xattr_trusted_set, -}; diff --git a/ANDROID_3.4.5/fs/ext2/xattr_user.c b/ANDROID_3.4.5/fs/ext2/xattr_user.c deleted file mode 100644 index f470e44c..00000000 --- a/ANDROID_3.4.5/fs/ext2/xattr_user.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linux/fs/ext2/xattr_user.c - * Handler for extended user attributes. - * - * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org> - */ - -#include <linux/init.h> -#include <linux/string.h> -#include "ext2.h" -#include "xattr.h" - -static size_t -ext2_xattr_user_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t prefix_len = XATTR_USER_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - if (!test_opt(dentry->d_sb, XATTR_USER)) - 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 -ext2_xattr_user_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, XATTR_USER)) - return -EOPNOTSUPP; - return ext2_xattr_get(dentry->d_inode, EXT2_XATTR_INDEX_USER, - name, buffer, size); -} - -static int -ext2_xattr_user_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, XATTR_USER)) - return -EOPNOTSUPP; - - return ext2_xattr_set(dentry->d_inode, EXT2_XATTR_INDEX_USER, - name, value, size, flags); -} - -const struct xattr_handler ext2_xattr_user_handler = { - .prefix = XATTR_USER_PREFIX, - .list = ext2_xattr_user_list, - .get = ext2_xattr_user_get, - .set = ext2_xattr_user_set, -}; diff --git a/ANDROID_3.4.5/fs/ext2/xip.c b/ANDROID_3.4.5/fs/ext2/xip.c deleted file mode 100644 index 1c331285..00000000 --- a/ANDROID_3.4.5/fs/ext2/xip.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * linux/fs/ext2/xip.c - * - * Copyright (C) 2005 IBM Corporation - * Author: Carsten Otte (cotte@de.ibm.com) - */ - -#include <linux/mm.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/buffer_head.h> -#include <linux/blkdev.h> -#include "ext2.h" -#include "xip.h" - -static inline int -__inode_direct_access(struct inode *inode, sector_t block, - void **kaddr, unsigned long *pfn) -{ - struct block_device *bdev = inode->i_sb->s_bdev; - const struct block_device_operations *ops = bdev->bd_disk->fops; - sector_t sector; - - sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */ - - BUG_ON(!ops->direct_access); - return ops->direct_access(bdev, sector, kaddr, pfn); -} - -static inline int -__ext2_get_block(struct inode *inode, pgoff_t pgoff, int create, - sector_t *result) -{ - struct buffer_head tmp; - int rc; - - memset(&tmp, 0, sizeof(struct buffer_head)); - rc = ext2_get_block(inode, pgoff, &tmp, create); - *result = tmp.b_blocknr; - - /* did we get a sparse block (hole in the file)? */ - if (!tmp.b_blocknr && !rc) { - BUG_ON(create); - rc = -ENODATA; - } - - return rc; -} - -int -ext2_clear_xip_target(struct inode *inode, sector_t block) -{ - void *kaddr; - unsigned long pfn; - int rc; - - rc = __inode_direct_access(inode, block, &kaddr, &pfn); - if (!rc) - clear_page(kaddr); - return rc; -} - -void ext2_xip_verify_sb(struct super_block *sb) -{ - struct ext2_sb_info *sbi = EXT2_SB(sb); - - if ((sbi->s_mount_opt & EXT2_MOUNT_XIP) && - !sb->s_bdev->bd_disk->fops->direct_access) { - sbi->s_mount_opt &= (~EXT2_MOUNT_XIP); - ext2_msg(sb, KERN_WARNING, - "warning: ignoring xip option - " - "not supported by bdev"); - } -} - -int ext2_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, - void **kmem, unsigned long *pfn) -{ - int rc; - sector_t block; - - /* first, retrieve the sector number */ - rc = __ext2_get_block(mapping->host, pgoff, create, &block); - if (rc) - return rc; - - /* retrieve address of the target data */ - rc = __inode_direct_access(mapping->host, block, kmem, pfn); - return rc; -} diff --git a/ANDROID_3.4.5/fs/ext2/xip.h b/ANDROID_3.4.5/fs/ext2/xip.h deleted file mode 100644 index 18b34d2f..00000000 --- a/ANDROID_3.4.5/fs/ext2/xip.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * linux/fs/ext2/xip.h - * - * Copyright (C) 2005 IBM Corporation - * Author: Carsten Otte (cotte@de.ibm.com) - */ - -#ifdef CONFIG_EXT2_FS_XIP -extern void ext2_xip_verify_sb (struct super_block *); -extern int ext2_clear_xip_target (struct inode *, sector_t); - -static inline int ext2_use_xip (struct super_block *sb) -{ - struct ext2_sb_info *sbi = EXT2_SB(sb); - return (sbi->s_mount_opt & EXT2_MOUNT_XIP); -} -int ext2_get_xip_mem(struct address_space *, pgoff_t, int, - void **, unsigned long *); -#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_mem) -#else -#define mapping_is_xip(map) 0 -#define ext2_xip_verify_sb(sb) do { } while (0) -#define ext2_use_xip(sb) 0 -#define ext2_clear_xip_target(inode, chain) 0 -#define ext2_get_xip_mem NULL -#endif |