diff options
Diffstat (limited to 'fs')
60 files changed, 697 insertions, 567 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index e48a630ae266..e63067d25cdb 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -534,7 +534,6 @@ void __init bdev_cache_init(void) if (err) panic("Cannot register bdev pseudo-fs"); bd_mnt = kern_mount(&bd_type); - err = PTR_ERR(bd_mnt); if (IS_ERR(bd_mnt)) panic("Cannot create bdev pseudo-fs"); blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ diff --git a/fs/compat.c b/fs/compat.c index 69baca5ad608..ee80ff341d37 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -2083,51 +2083,6 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2) #ifdef CONFIG_EPOLL -#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT -asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, - struct compat_epoll_event __user *event) -{ - long err = 0; - struct compat_epoll_event user; - struct epoll_event __user *kernel = NULL; - - if (event) { - if (copy_from_user(&user, event, sizeof(user))) - return -EFAULT; - kernel = compat_alloc_user_space(sizeof(struct epoll_event)); - err |= __put_user(user.events, &kernel->events); - err |= __put_user(user.data, &kernel->data); - } - - return err ? err : sys_epoll_ctl(epfd, op, fd, kernel); -} - - -asmlinkage long compat_sys_epoll_wait(int epfd, - struct compat_epoll_event __user *events, - int maxevents, int timeout) -{ - long i, ret, err = 0; - struct epoll_event __user *kbuf; - struct epoll_event ev; - - if ((maxevents <= 0) || - (maxevents > (INT_MAX / sizeof(struct epoll_event)))) - return -EINVAL; - kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents); - ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); - for (i = 0; i < ret; i++) { - err |= __get_user(ev.events, &kbuf[i].events); - err |= __get_user(ev.data, &kbuf[i].data); - err |= __put_user(ev.events, &events->events); - err |= __put_user_unaligned(ev.data, &events->data); - events++; - } - - return err ? -EFAULT: ret; -} -#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */ - #ifdef TIF_RESTORE_SIGMASK asmlinkage long compat_sys_epoll_pwait(int epfd, struct compat_epoll_event __user *events, @@ -2153,11 +2108,7 @@ asmlinkage long compat_sys_epoll_pwait(int epfd, sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); } -#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT - err = compat_sys_epoll_wait(epfd, events, maxevents, timeout); -#else err = sys_epoll_wait(epfd, events, maxevents, timeout); -#endif /* * If we changed the signal mask, we need to restore the original one. diff --git a/fs/dcache.c b/fs/dcache.c index d9ca1e5ceb92..44f6cf23b70e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -89,7 +89,7 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); /* if dentry was never inserted into hash, immediate free is OK */ - if (dentry->d_hash.pprev == NULL) + if (hlist_unhashed(&dentry->d_hash)) __d_free(dentry); else call_rcu(&dentry->d_u.d_rcu, d_callback); @@ -1408,9 +1408,6 @@ void d_delete(struct dentry * dentry) if (atomic_read(&dentry->d_count) == 1) { dentry_iput(dentry); fsnotify_nameremove(dentry, isdir); - - /* remove this and other inotify debug checks after 2.6.18 */ - dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; return; } diff --git a/fs/dquot.c b/fs/dquot.c index cee7c6f428f0..def4e969df77 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type) /* This routine is guarded by dqonoff_mutex mutex */ static void add_dquot_ref(struct super_block *sb, int type) { - struct inode *inode; + struct inode *inode, *old_inode = NULL; -restart: spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { if (!atomic_read(&inode->i_writecount)) @@ -711,12 +710,18 @@ restart: __iget(inode); spin_unlock(&inode_lock); + iput(old_inode); sb->dq_op->initialize(inode, type); - iput(inode); - /* As we may have blocked we had better restart... */ - goto restart; + /* We hold a reference to 'inode' so it couldn't have been + * removed from s_inodes list while we dropped the inode_lock. + * We cannot iput the inode now as we can be holding the last + * reference and we cannot iput it under inode_lock. So we + * keep the reference and iput it later. */ + old_inode = inode; + spin_lock(&inode_lock); } spin_unlock(&inode_lock); + iput(old_inode); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f8ef0af919e7..a066e109ad9c 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -355,8 +355,11 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, } /* Consider doing this once, when the file is opened */ mutex_lock(&crypt_stat->cs_tfm_mutex); - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } if (rc) { ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", rc); @@ -376,11 +379,10 @@ out: * * Convert an eCryptfs page index into a lower byte offset */ -void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, - struct ecryptfs_crypt_stat *crypt_stat) +static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, + struct ecryptfs_crypt_stat *crypt_stat) { - (*offset) = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + (*offset) = (crypt_stat->num_header_bytes_at_front + (crypt_stat->extent_size * extent_num)); } @@ -842,15 +844,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) set_extent_mask_and_shift(crypt_stat); crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - crypt_stat->num_header_extents_at_front = 0; + crypt_stat->num_header_bytes_at_front = 0; else { if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) - crypt_stat->num_header_extents_at_front = - (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE - / crypt_stat->extent_size); + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; else - crypt_stat->num_header_extents_at_front = - (PAGE_CACHE_SIZE / crypt_stat->extent_size); + crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE; } } @@ -1128,7 +1128,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_cipher_code_str_map_elem { char cipher_str[16]; - u16 cipher_code; + u8 cipher_code; }; /* Add support for additional ciphers by adding elements here. The @@ -1152,10 +1152,10 @@ ecryptfs_cipher_code_str_map[] = { * * Returns zero on no match, or the cipher code on match */ -u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) +u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) { int i; - u16 code = 0; + u8 code = 0; struct ecryptfs_cipher_code_str_map_elem *map = ecryptfs_cipher_code_str_map; @@ -1187,7 +1187,7 @@ u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) * * Returns zero on success */ -int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) +int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code) { int rc = 0; int i; @@ -1236,7 +1236,8 @@ ecryptfs_write_header_metadata(char *virt, header_extent_size = (u32)crypt_stat->extent_size; num_header_extents_at_front = - (u16)crypt_stat->num_header_extents_at_front; + (u16)(crypt_stat->num_header_bytes_at_front + / crypt_stat->extent_size); header_extent_size = cpu_to_be32(header_extent_size); memcpy(virt, &header_extent_size, 4); virt += 4; @@ -1311,40 +1312,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, static int ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry, - char *page_virt) + char *virt) { - int current_header_page; - int header_pages; int rc; - rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, - 0, PAGE_CACHE_SIZE); - if (rc) { + rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, + 0, crypt_stat->num_header_bytes_at_front); + if (rc) printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __FUNCTION__, rc); - goto out; - } - header_pages = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) - / PAGE_CACHE_SIZE); - memset(page_virt, 0, PAGE_CACHE_SIZE); - current_header_page = 1; - while (current_header_page < header_pages) { - loff_t offset; - - offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT); - if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, - page_virt, offset, - PAGE_CACHE_SIZE))) { - printk(KERN_ERR "%s: Error attempting to write header " - "information to lower file; rc = [%d]\n", - __FUNCTION__, rc); - goto out; - } - current_header_page++; - } -out: return rc; } @@ -1370,15 +1347,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, * retrieved via a prompt. Exactly what happens at this point should * be policy-dependent. * - * TODO: Support header information spanning multiple pages - * * Returns zero on success; non-zero on error */ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; - char *page_virt; + char *virt; size_t size = 0; int rc = 0; @@ -1389,40 +1364,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) goto out; } } else { + printk(KERN_WARNING "%s: Encrypted flag not set\n", + __FUNCTION__); rc = -EINVAL; - ecryptfs_printk(KERN_WARNING, - "Called with crypt_stat->encrypted == 0\n"); goto out; } /* Released in this function */ - page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); - if (!page_virt) { - ecryptfs_printk(KERN_ERR, "Out of memory\n"); + virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL); + if (!virt) { + printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__); rc = -ENOMEM; goto out; } - rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, - ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat, + ecryptfs_dentry); if (unlikely(rc)) { - ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); - memset(page_virt, 0, PAGE_CACHE_SIZE); + printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", + __FUNCTION__, rc); goto out_free; } if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, - crypt_stat, page_virt, - size); + crypt_stat, virt, size); else rc = ecryptfs_write_metadata_to_contents(crypt_stat, - ecryptfs_dentry, - page_virt); + ecryptfs_dentry, virt); if (rc) { - printk(KERN_ERR "Error writing metadata out to lower file; " - "rc = [%d]\n", rc); + printk(KERN_ERR "%s: Error writing metadata out to lower file; " + "rc = [%d]\n", __FUNCTION__, rc); goto out_free; } out_free: - kmem_cache_free(ecryptfs_header_cache_0, page_virt); + memset(virt, 0, crypt_stat->num_header_bytes_at_front); + kfree(virt); out: return rc; } @@ -1442,16 +1416,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, virt += sizeof(u32); memcpy(&num_header_extents_at_front, virt, sizeof(u16)); num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front); - crypt_stat->num_header_extents_at_front = - (int)num_header_extents_at_front; + crypt_stat->num_header_bytes_at_front = + (((size_t)num_header_extents_at_front + * (size_t)header_extent_size)); (*bytes_read) = (sizeof(u32) + sizeof(u16)); if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) - && ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + && (crypt_stat->num_header_bytes_at_front < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { rc = -EINVAL; - printk(KERN_WARNING "Invalid number of header extents: [%zd]\n", - crypt_stat->num_header_extents_at_front); + printk(KERN_WARNING "Invalid header size: [%zd]\n", + crypt_stat->num_header_bytes_at_front); } return rc; } @@ -1466,7 +1440,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, */ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) { - crypt_stat->num_header_extents_at_front = 2; + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } /** @@ -1552,9 +1527,10 @@ int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode) size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME, page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); if (size < 0) { - printk(KERN_ERR "Error attempting to read the [%s] " - "xattr from the lower file; return value = [%zd]\n", - ECRYPTFS_XATTR_NAME, size); + if (unlikely(ecryptfs_verbosity > 0)) + printk(KERN_INFO "Error attempting to read the [%s] " + "xattr from the lower file; return value = " + "[%zd]\n", ECRYPTFS_XATTR_NAME, size); rc = -EINVAL; goto out; } @@ -1802,7 +1778,7 @@ out: } struct kmem_cache *ecryptfs_key_tfm_cache; -struct list_head key_tfm_list; +static struct list_head key_tfm_list; struct mutex key_tfm_list_mutex; int ecryptfs_init_crypto(void) @@ -1812,6 +1788,11 @@ int ecryptfs_init_crypto(void) return 0; } +/** + * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list + * + * Called only at module unload time + */ int ecryptfs_destroy_crypto(void) { struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp; @@ -1835,6 +1816,8 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, struct ecryptfs_key_tfm *tmp_tfm; int rc = 0; + BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); + tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL); if (key_tfm != NULL) (*key_tfm) = tmp_tfm; @@ -1861,13 +1844,50 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, (*key_tfm) = NULL; goto out; } - mutex_lock(&key_tfm_list_mutex); list_add(&tmp_tfm->key_tfm_list, &key_tfm_list); - mutex_unlock(&key_tfm_list_mutex); out: return rc; } +/** + * ecryptfs_tfm_exists - Search for existing tfm for cipher_name. + * @cipher_name: the name of the cipher to search for + * @key_tfm: set to corresponding tfm if found + * + * Searches for cached key_tfm matching @cipher_name + * Must be called with &key_tfm_list_mutex held + * Returns 1 if found, with @key_tfm set + * Returns 0 if not found, with @key_tfm set to NULL + */ +int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm) +{ + struct ecryptfs_key_tfm *tmp_key_tfm; + + BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); + + list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) { + if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) { + if (key_tfm) + (*key_tfm) = tmp_key_tfm; + return 1; + } + } + if (key_tfm) + (*key_tfm) = NULL; + return 0; +} + +/** + * ecryptfs_get_tfm_and_mutex_for_cipher_name + * + * @tfm: set to cached tfm found, or new tfm created + * @tfm_mutex: set to mutex for cached tfm found, or new tfm created + * @cipher_name: the name of the cipher to search for and/or add + * + * Sets pointers to @tfm & @tfm_mutex matching @cipher_name. + * Searches for cached item first, and creates new if not found. + * Returns 0 on success, non-zero if adding new cipher failed + */ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, struct mutex **tfm_mutex, char *cipher_name) @@ -1877,22 +1897,17 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, (*tfm) = NULL; (*tfm_mutex) = NULL; + mutex_lock(&key_tfm_list_mutex); - list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) { - if (strcmp(key_tfm->cipher_name, cipher_name) == 0) { - (*tfm) = key_tfm->key_tfm; - (*tfm_mutex) = &key_tfm->key_tfm_mutex; - mutex_unlock(&key_tfm_list_mutex); + if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) { + rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); + if (rc) { + printk(KERN_ERR "Error adding new key_tfm to list; " + "rc = [%d]\n", rc); goto out; } } mutex_unlock(&key_tfm_list_mutex); - rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); - if (rc) { - printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n", - rc); - goto out; - } (*tfm) = key_tfm->key_tfm; (*tfm_mutex) = &key_tfm->key_tfm_mutex; out: diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index ce7a5d4aec36..5007f788da01 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -234,10 +234,11 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_KEY_VALID 0x00000080 #define ECRYPTFS_METADATA_IN_XATTR 0x00000100 #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200 +#define ECRYPTFS_KEY_SET 0x00000400 u32 flags; unsigned int file_version; size_t iv_bytes; - size_t num_header_extents_at_front; + size_t num_header_bytes_at_front; size_t extent_size; /* Data extent size; default is 4096 */ size_t key_size; size_t extent_shift; @@ -322,7 +323,6 @@ struct ecryptfs_key_tfm { unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; }; -extern struct list_head key_tfm_list; extern struct mutex key_tfm_list_mutex; /** @@ -521,11 +521,9 @@ extern struct kmem_cache *ecryptfs_file_info_cache; extern struct kmem_cache *ecryptfs_dentry_info_cache; extern struct kmem_cache *ecryptfs_inode_info_cache; extern struct kmem_cache *ecryptfs_sb_info_cache; -extern struct kmem_cache *ecryptfs_header_cache_0; extern struct kmem_cache *ecryptfs_header_cache_1; extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_xattr_cache; -extern struct kmem_cache *ecryptfs_lower_page_cache; extern struct kmem_cache *ecryptfs_key_record_cache; extern struct kmem_cache *ecryptfs_key_sig_cache; extern struct kmem_cache *ecryptfs_global_auth_tok_cache; @@ -562,8 +560,8 @@ int ecryptfs_read_and_validate_header_region(char *data, struct inode *ecryptfs_inode); int ecryptfs_read_and_validate_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); -u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); -int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code); +u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code); void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_generate_key_packet_set(char *dest_base, struct ecryptfs_crypt_stat *crypt_stat, @@ -576,8 +574,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); int ecryptfs_inode_set(struct inode *inode, void *lower_inode); void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode); -ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, - size_t size); ssize_t ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, void *value, size_t size); @@ -623,6 +619,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, size_t key_size); int ecryptfs_init_crypto(void); int ecryptfs_destroy_crypto(void); +int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm); int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, struct mutex **tfm_mutex, char *cipher_name); @@ -631,8 +628,6 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, char *sig); int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); -void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, - struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, loff_t offset, size_t size); int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode, @@ -646,8 +641,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, pgoff_t page_index, size_t offset_in_page, size_t size, struct inode *ecryptfs_inode); -int ecryptfs_read(char *data, loff_t offset, size_t size, - struct file *ecryptfs_file); struct page *ecryptfs_get_locked_page(struct file *file, loff_t index); #endif /* #ifndef ECRYPTFS_KERNEL_H */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c98c4690a771..2b8f5ed4adea 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -209,9 +209,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; - printk(KERN_WARNING "Attempt to read file that " + printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " - "and plaintext passthrough mode is not " + "or the key could not be retrieved. " + "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_free; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5a719180983c..edd1e44e9d47 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - file_size = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + file_size = (crypt_stat->num_header_bytes_at_front + i_size_read(lower_dentry->d_inode)); else file_size = i_size_read(lower_dentry->d_inode); @@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) * @crypt_stat: Crypt_stat associated with file * @upper_size: Size of the upper file * - * Calculate the requried size of the lower file based on the + * Calculate the required size of the lower file based on the * specified size of the upper file. This calculation is based on the * number of headers in the underlying file and the extent size. * @@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, { loff_t lower_size; - lower_size = (crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front); + lower_size = crypt_stat->num_header_bytes_at_front; if (upper_size != 0) { loff_t num_extents; @@ -875,11 +873,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; - printk(KERN_WARNING "Attempt to read file that " + printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " - "and plaintext passthrough mode is not " + "or the key could not be retrieved. " + "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); - mutex_unlock(&crypt_stat->cs_mutex); goto out; } @@ -954,7 +952,7 @@ out: return rc; } -ssize_t +static ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index f458c1f35565..682b1b2482c2 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -189,7 +189,7 @@ out: } static int -parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code, +parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code, struct ecryptfs_message *msg) { size_t i = 0; @@ -275,7 +275,7 @@ out: static int -write_tag_66_packet(char *signature, size_t cipher_code, +write_tag_66_packet(char *signature, u8 cipher_code, struct ecryptfs_crypt_stat *crypt_stat, char **packet, size_t *packet_len) { @@ -428,7 +428,7 @@ static int decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat) { - u16 cipher_code = 0; + u8 cipher_code = 0; struct ecryptfs_msg_ctx *msg_ctx; struct ecryptfs_message *msg = NULL; char *auth_tok_sig; @@ -1537,7 +1537,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, struct scatterlist dst_sg; struct scatterlist src_sg; struct mutex *tfm_mutex = NULL; - size_t cipher_code; + u8 cipher_code; size_t packet_size_length; size_t max_packet_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 0249aa4ae181..778c420e4cac 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -117,7 +117,7 @@ void __ecryptfs_printk(const char *fmt, ...) * * Returns zero on success; non-zero otherwise */ -int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) +static int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) { struct ecryptfs_inode_info *inode_info = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); @@ -226,17 +226,15 @@ out: return rc; } -enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug, - ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher, - ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes, +enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, + ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher, + ecryptfs_opt_ecryptfs_key_bytes, ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, ecryptfs_opt_encrypted_view, ecryptfs_opt_err }; static match_table_t tokens = { {ecryptfs_opt_sig, "sig=%s"}, {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"}, - {ecryptfs_opt_debug, "debug=%u"}, - {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"}, {ecryptfs_opt_cipher, "cipher=%s"}, {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"}, {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"}, @@ -313,7 +311,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) substring_t args[MAX_OPT_ARGS]; int token; char *sig_src; - char *debug_src; char *cipher_name_dst; char *cipher_name_src; char *cipher_key_bytes_src; @@ -341,16 +338,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) } sig_set = 1; break; - case ecryptfs_opt_debug: - case ecryptfs_opt_ecryptfs_debug: - debug_src = args[0].from; - ecryptfs_verbosity = - (int)simple_strtol(debug_src, &debug_src, - 0); - ecryptfs_printk(KERN_DEBUG, - "Verbosity set to [%d]" "\n", - ecryptfs_verbosity); - break; case ecryptfs_opt_cipher: case ecryptfs_opt_ecryptfs_cipher: cipher_name_src = args[0].from; @@ -423,9 +410,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) if (!cipher_key_bytes_set) { mount_crypt_stat->global_default_cipher_key_size = 0; } - rc = ecryptfs_add_new_key_tfm( - NULL, mount_crypt_stat->global_default_cipher_name, - mount_crypt_stat->global_default_cipher_key_size); + mutex_lock(&key_tfm_list_mutex); + if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, + NULL)) + rc = ecryptfs_add_new_key_tfm( + NULL, mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); + mutex_unlock(&key_tfm_list_mutex); if (rc) { printk(KERN_ERR "Error attempting to initialize cipher with " "name = [%s] and key size = [%td]; rc = [%d]\n", @@ -654,11 +645,6 @@ static struct ecryptfs_cache_info { .size = sizeof(struct ecryptfs_sb_info), }, { - .cache = &ecryptfs_header_cache_0, - .name = "ecryptfs_headers_0", - .size = PAGE_CACHE_SIZE, - }, - { .cache = &ecryptfs_header_cache_1, .name = "ecryptfs_headers_1", .size = PAGE_CACHE_SIZE, @@ -821,6 +807,10 @@ static int __init ecryptfs_init(void) "rc = [%d]\n", rc); goto out_release_messaging; } + if (ecryptfs_verbosity > 0) + printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values " + "will be written to the syslog!\n", ecryptfs_verbosity); + goto out; out_release_messaging: ecryptfs_release_messaging(ecryptfs_transport); diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 0535412d8c64..dc74b186145d 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -34,8 +34,6 @@ #include <linux/scatterlist.h> #include "ecryptfs_kernel.h" -struct kmem_cache *ecryptfs_lower_page_cache; - /** * ecryptfs_get_locked_page * @@ -102,13 +100,14 @@ static void set_header_info(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat) { size_t written; - int save_num_header_extents_at_front = - crypt_stat->num_header_extents_at_front; + size_t save_num_header_bytes_at_front = + crypt_stat->num_header_bytes_at_front; - crypt_stat->num_header_extents_at_front = 1; + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); - crypt_stat->num_header_extents_at_front = - save_num_header_extents_at_front; + crypt_stat->num_header_bytes_at_front = + save_num_header_bytes_at_front; } /** @@ -134,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, loff_t view_extent_num = ((((loff_t)page->index) * num_extents_per_page) + extent_num_in_page); + size_t num_header_extents_at_front = + (crypt_stat->num_header_bytes_at_front + / crypt_stat->extent_size); - if (view_extent_num < crypt_stat->num_header_extents_at_front) { + if (view_extent_num < num_header_extents_at_front) { /* This is a header extent */ char *page_virt; @@ -157,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, } else { /* This is an encrypted data extent */ loff_t lower_offset = - ((view_extent_num - - crypt_stat->num_header_extents_at_front) - * crypt_stat->extent_size); + ((view_extent_num * crypt_stat->extent_size) + - crypt_stat->num_header_bytes_at_front); rc = ecryptfs_read_lower_page_segment( page, (lower_offset >> PAGE_CACHE_SHIFT), diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 948f57624c05..0c4928623bbc 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -293,6 +293,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, return rc; } +#if 0 /** * ecryptfs_read * @data: The virtual address into which to write the data read (and @@ -371,3 +372,4 @@ int ecryptfs_read(char *data, loff_t offset, size_t size, out: return rc; } +#endif /* 0 */ diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 4859c4eecd65..c27ac2b358a1 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -156,32 +156,38 @@ static void ecryptfs_clear_inode(struct inode *inode) /** * ecryptfs_show_options * - * Prints the directory we are currently mounted over. - * Returns zero on success; non-zero otherwise + * Prints the mount options for a given superblock. + * Returns zero; does not fail. */ static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) { struct super_block *sb = mnt->mnt_sb; - struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root); - struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root); - char *tmp_page; - char *path; - int rc = 0; - - tmp_page = (char *)__get_free_page(GFP_KERNEL); - if (!tmp_page) { - rc = -ENOMEM; - goto out; - } - path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE); - if (IS_ERR(path)) { - rc = PTR_ERR(path); - goto out; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(sb)->mount_crypt_stat; + struct ecryptfs_global_auth_tok *walker; + + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_for_each_entry(walker, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + seq_printf(m, ",ecryptfs_sig=%s", walker->sig); } - seq_printf(m, ",dir=%s", path); - free_page((unsigned long)tmp_page); -out: - return rc; + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); + + seq_printf(m, ",ecryptfs_cipher=%s", + mount_crypt_stat->global_default_cipher_name); + + if (mount_crypt_stat->global_default_cipher_key_size) + seq_printf(m, ",ecryptfs_key_bytes=%zd", + mount_crypt_stat->global_default_cipher_key_size); + if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) + seq_printf(m, ",ecryptfs_passthrough"); + if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) + seq_printf(m, ",ecryptfs_xattr_metadata"); + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + seq_printf(m, ",ecryptfs_encrypted_view"); + + return 0; } const struct super_operations ecryptfs_sops = { diff --git a/fs/eventfd.c b/fs/eventfd.c index 2ce19c000d2a..a9f130cd50ac 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -15,6 +15,7 @@ #include <linux/spinlock.h> #include <linux/anon_inodes.h> #include <linux/eventfd.h> +#include <linux/syscalls.h> struct eventfd_ctx { wait_queue_head_t wqh; diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 377ad172d74b..e7b2bafa1dd9 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -69,9 +69,53 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, 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, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %lu", + block_group, bitmap_blk); + return 0; +} + /* - * Read the bitmap for a given block_group, reading into the specified - * slot in the superblock's bitmap cache. + * 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. */ @@ -80,17 +124,36 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext2_group_desc * desc; struct buffer_head * bh = NULL; - - desc = ext2_get_group_desc (sb, block_group, NULL); + ext2_fsblk_t bitmap_blk; + + desc = ext2_get_group_desc(sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); - if (!bh) - ext2_error (sb, "read_block_bitmap", + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_getblk(sb, bitmap_blk); + if (unlikely(!bh)) { + ext2_error(sb, __FUNCTION__, + "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, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: + return NULL; + } + if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) { + brelse(bh); + return NULL; + } + return bh; } @@ -474,11 +537,13 @@ do_more: 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)) + 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), @@ -1250,8 +1315,8 @@ retry_alloc: smp_rmb(); /* - * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * 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++; @@ -1311,11 +1376,13 @@ allocated: 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_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); + goto out; + } performed_allocation = 1; @@ -1466,9 +1533,6 @@ int ext2_bg_has_super(struct super_block *sb, int group) */ unsigned long ext2_bg_num_gdb(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 EXT2_SB(sb)->s_gdb_count; + return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0; } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index d868e26c15eb..8dededd80fe2 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -703,7 +703,7 @@ const struct file_operations ext2_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = ext2_readdir, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index c87ae29c19cb..bb9948cdd50f 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -139,8 +139,7 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata); /* ioctl.c */ -extern int ext2_ioctl (struct inode *, struct file *, unsigned int, - unsigned long); +extern long ext2_ioctl(struct file *, unsigned int, unsigned long); extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); /* namei.c */ diff --git a/fs/ext2/file.c b/fs/ext2/file.c index c051798459a1..5f2fa9c36293 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -48,7 +48,7 @@ const struct file_operations ext2_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif @@ -65,7 +65,7 @@ const struct file_operations ext2_xip_file_operations = { .llseek = generic_file_llseek, .read = xip_file_read, .write = xip_file_write, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index b1ab32ab5a77..03978ec2a91c 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -286,15 +286,12 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind) * ext2_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain * * Returns preferred place for a block (the goal). */ -static inline int ext2_find_goal(struct inode *inode, - long block, - Indirect chain[4], +static inline int ext2_find_goal(struct inode *inode, long block, Indirect *partial) { struct ext2_block_alloc_info *block_i; @@ -569,7 +566,6 @@ static void ext2_splice_branch(struct inode *inode, * * `handle' can be NULL if create == 0. * - * The BKL may not be held on entry here. Be sure to take it early. * return > 0, # of blocks mapped or allocated. * return = 0, if plain lookup failed. * return < 0, error case. @@ -639,7 +635,7 @@ reread: if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext2_init_block_alloc_info(inode); - goal = ext2_find_goal(inode, iblock, chain, partial); + 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; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 320b2cb3d4d2..b8ea11fee5c6 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -17,9 +17,9 @@ #include <asm/uaccess.h> -int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, - unsigned long arg) +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; @@ -141,9 +141,6 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, #ifdef CONFIG_COMPAT long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int ret; - /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { case EXT2_IOC32_GETFLAGS: @@ -161,9 +158,6 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) default: return -ENOIOCTLCMD; } - lock_kernel(); - ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); - unlock_kernel(); - return ret; + return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); } #endif diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 6abaf75163f0..1ba18b72d43a 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -234,16 +234,16 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } - if (test_opt(sb, ERRORS_CONT)) { + 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_RO) { - seq_puts(seq, ",errors=continue"); + def_errors == EXT2_ERRORS_CONTINUE) { + seq_puts(seq, ",errors=remount-ro"); } } - if (test_opt(sb, ERRORS_RO)) - 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)) @@ -617,27 +617,24 @@ static int ext2_setup_super (struct super_block * sb, return res; } -static int ext2_check_descriptors (struct super_block * sb) +static int ext2_check_descriptors(struct super_block *sb) { int i; - int desc_block = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block); unsigned long last_block; - struct ext2_group_desc * gdp = NULL; ext2_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); + 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 ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { @@ -667,7 +664,6 @@ static int ext2_check_descriptors (struct super_block * sb) return 0; } first_block += EXT2_BLOCKS_PER_GROUP(sb); - gdp++; } return 1; } @@ -820,10 +816,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) 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_RO) - set_opt(sbi->s_mount_opt, ERRORS_RO); - else + 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); @@ -868,8 +864,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); - if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) || - (sb->s_blocksize != blocksize))) { + if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) { if (!silent) printk("XIP: Unsupported blocksize\n"); goto failed_mount; diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index a8ba7e831278..a75713031105 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -80,13 +80,57 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, return desc + offset; } +static int ext3_valid_block_bitmap(struct super_block *sb, + struct ext3_group_desc *desc, + unsigned int block_group, + struct buffer_head *bh) +{ + ext3_grpblk_t offset; + ext3_grpblk_t next_zero_bit; + ext3_fsblk_t bitmap_blk; + ext3_fsblk_t group_first_block; + + group_first_block = ext3_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 (!ext3_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 (!ext3_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 = ext3_find_next_zero_bit(bh->b_data, + offset + EXT3_SB(sb)->s_itb_per_group, + offset); + if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group) + /* good bitmap for inode tables */ + return 1; + +err_out: + ext3_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %lu", + block_group, bitmap_blk); + return 0; +} + /** * read_block_bitmap() * @sb: super block * @block_group: given block group * - * Read the bitmap for a given block_group, reading into the specified - * slot in the superblock's bitmap cache. + * 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. */ @@ -95,17 +139,35 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext3_group_desc * desc; struct buffer_head * bh = NULL; + ext3_fsblk_t bitmap_blk; - desc = ext3_get_group_desc (sb, block_group, NULL); + desc = ext3_get_group_desc(sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); - if (!bh) - ext3_error (sb, "read_block_bitmap", + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_getblk(sb, bitmap_blk); + if (unlikely(!bh)) { + ext3_error(sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: + return NULL; + } + if (likely(bh_uptodate_or_lock(bh))) + return bh; + + if (bh_submit_read(bh) < 0) { + brelse(bh); + ext3_error(sb, __FUNCTION__, + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %u", + block_group, le32_to_cpu(desc->bg_block_bitmap)); + return NULL; + } + if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) { + brelse(bh); + return NULL; + } return bh; } /* @@ -468,11 +530,13 @@ do_more: 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)) + sbi->s_itb_per_group)) { ext3_error (sb, "ext3_free_blocks", "Freeing blocks in system zones - " "Block = "E3FSBLK", count = %lu", block, count); + goto error_return; + } /* * We are about to start releasing blocks in the bitmap, @@ -1508,7 +1572,7 @@ retry_alloc: /* * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * group_no and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { group_no++; @@ -1575,11 +1639,13 @@ allocated: in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), EXT3_SB(sb)->s_itb_per_group) || in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group)) + EXT3_SB(sb)->s_itb_per_group)) { ext3_error(sb, "ext3_new_block", "Allocating block in system zone - " "blocks from "E3FSBLK", length %lu", ret_block, num); + goto out; + } performed_allocation = 1; @@ -1782,11 +1848,7 @@ static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group) static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) { - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext3_group_sparse(group)) - return 0; - return EXT3_SB(sb)->s_gdb_count; + return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0; } /** diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 077535439288..8a9ce2d09bde 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -439,16 +439,14 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) * ext3_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain - * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. + * returns it. */ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, - Indirect chain[4], Indirect *partial) + Indirect *partial) { struct ext3_block_alloc_info *block_i; @@ -884,7 +882,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext3_init_block_alloc_info(inode); - goal = ext3_find_goal(inode, iblock, chain, partial); + goal = ext3_find_goal(inode, iblock, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; @@ -941,55 +939,45 @@ out: return err; } -#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32) +/* Maximum number of blocks we map for direct IO at once. */ +#define DIO_MAX_BLOCKS 4096 +/* + * Number of credits we need for writing DIO_MAX_BLOCKS: + * We need sb + group descriptor + bitmap + inode -> 4 + * For B blocks with A block pointers per block we need: + * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect). + * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25. + */ +#define DIO_CREDITS 25 static int ext3_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { handle_t *handle = ext3_journal_current_handle(); - int ret = 0; + int ret = 0, started = 0; unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; - if (!create) - goto get_block; /* A read */ - - if (max_blocks == 1) - goto get_block; /* A single block get */ - - if (handle->h_transaction->t_state == T_LOCKED) { - /* - * Huge direct-io writes can hold off commits for long - * periods of time. Let this commit run. - */ - ext3_journal_stop(handle); - handle = ext3_journal_start(inode, DIO_CREDITS); - if (IS_ERR(handle)) + if (create && !handle) { /* Direct IO write... */ + if (max_blocks > DIO_MAX_BLOCKS) + max_blocks = DIO_MAX_BLOCKS; + handle = ext3_journal_start(inode, DIO_CREDITS + + 2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto get_block; - } - - if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { - /* - * Getting low on buffer credits... - */ - ret = ext3_journal_extend(handle, DIO_CREDITS); - if (ret > 0) { - /* - * Couldn't extend the transaction. Start a new one. - */ - ret = ext3_journal_restart(handle, DIO_CREDITS); + goto out; } + started = 1; } -get_block: - if (ret == 0) { - ret = ext3_get_blocks_handle(handle, inode, iblock, + ret = ext3_get_blocks_handle(handle, inode, iblock, max_blocks, bh_result, create, 0); - if (ret > 0) { - bh_result->b_size = (ret << inode->i_blkbits); - ret = 0; - } + if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); + ret = 0; } + if (started) + ext3_journal_stop(handle); +out: return ret; } @@ -1680,7 +1668,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * if the machine crashes during the write. * * If the O_DIRECT write is intantiating holes inside i_size and the machine - * crashes then stale disk data _may_ be exposed inside the file. + * crashes then stale disk data _may_ be exposed inside the file. But current + * VFS code falls back into buffered path in that case so we are safe. */ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, @@ -1689,7 +1678,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); - handle_t *handle = NULL; + handle_t *handle; ssize_t ret; int orphan = 0; size_t count = iov_length(iov, nr_segs); @@ -1697,17 +1686,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, if (rw == WRITE) { loff_t final_size = offset + count; - handle = ext3_journal_start(inode, DIO_CREDITS); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } if (final_size > inode->i_size) { + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } ret = ext3_orphan_add(handle, inode); - if (ret) - goto out_stop; + if (ret) { + ext3_journal_stop(handle); + goto out; + } orphan = 1; ei->i_disksize = inode->i_size; + ext3_journal_stop(handle); } } @@ -1715,18 +1708,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, ext3_get_block, NULL); - /* - * Reacquire the handle: ext3_get_block() can restart the transaction - */ - handle = ext3_journal_current_handle(); - -out_stop: - if (handle) { + if (orphan) { int err; - if (orphan && inode->i_nlink) + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + /* This is really bad luck. We've written the data + * but cannot extend i_size. Bail out and pretend + * the write failed... */ + ret = PTR_ERR(handle); + goto out; + } + if (inode->i_nlink) ext3_orphan_del(handle, inode); - if (orphan && ret > 0) { + if (ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { ei->i_disksize = end; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 4ab6f76e63d0..92b83b004dd8 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -860,14 +860,10 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, int nblocks, i, err; struct inode *dir = dentry->d_parent->d_inode; int namelen; - const u8 *name; - unsigned blocksize; *res_dir = NULL; sb = dir->i_sb; - blocksize = sb->s_blocksize; namelen = dentry->d_name.len; - name = dentry->d_name.name; if (namelen > EXT3_NAME_LEN) return NULL; if (is_dx(dir)) { diff --git a/fs/ext3/super.c b/fs/ext3/super.c index f3675cc630e9..343677e8c350 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -575,16 +575,16 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } - if (test_opt(sb, ERRORS_CONT)) { + if (test_opt(sb, ERRORS_RO)) { int def_errors = le16_to_cpu(es->s_errors); if (def_errors == EXT3_ERRORS_PANIC || - def_errors == EXT3_ERRORS_RO) { - seq_puts(seq, ",errors=continue"); + def_errors == EXT3_ERRORS_CONTINUE) { + seq_puts(seq, ",errors=remount-ro"); } } - if (test_opt(sb, ERRORS_RO)) - 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)) @@ -1252,28 +1252,24 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, } /* Called at mount-time, super-block is locked */ -static int ext3_check_descriptors (struct super_block * sb) +static int ext3_check_descriptors(struct super_block *sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext3_fsblk_t last_block; - struct ext3_group_desc * gdp = NULL; - int desc_block = 0; int i; ext3_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL); + if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext3_group_desc *) - sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { @@ -1306,7 +1302,6 @@ static int ext3_check_descriptors (struct super_block * sb) return 0; } first_block += EXT3_BLOCKS_PER_GROUP(sb); - gdp++; } sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); @@ -1583,10 +1578,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) - set_opt(sbi->s_mount_opt, ERRORS_RO); - else + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_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); diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ac75ea953d83..0737e05ba3dd 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -1700,7 +1700,7 @@ retry_alloc: /* * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * group_no and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { group_no++; @@ -2011,11 +2011,7 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, ext4_group_t group) { - if (EXT4_HAS_RO_COMPAT_FEATURE(sb, - EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext4_group_sparse(group)) - return 0; - return EXT4_SB(sb)->s_gdb_count; + return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0; } /** diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 05c4145dd27d..0e9055cf700e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -429,16 +429,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) * ext4_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain - * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. + * returns it. */ - static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, - Indirect chain[4], Indirect *partial) + Indirect *partial) { struct ext4_block_alloc_info *block_i; @@ -839,7 +836,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext4_init_block_alloc_info(inode); - goal = ext4_find_goal(inode, iblock, chain, partial); + goal = ext4_find_goal(inode, iblock, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 055a0cd0168e..c89bb8797765 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1458,7 +1458,7 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, } /* Called at mount-time, super-block is locked */ -static int ext4_check_descriptors (struct super_block * sb) +static int ext4_check_descriptors(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); @@ -1466,8 +1466,6 @@ static int ext4_check_descriptors (struct super_block * sb) ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; - struct ext4_group_desc * gdp = NULL; - int desc_block = 0; int flexbg_flag = 0; ext4_group_t i; @@ -1476,17 +1474,15 @@ static int ext4_check_descriptors (struct super_block * sb) ext4_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); + if (i == sbi->s_groups_count - 1 || flexbg_flag) last_block = ext4_blocks_count(sbi->s_es) - 1; else last_block = first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext4_group_desc *) - sbi->s_group_desc[desc_block++]->b_data; block_bitmap = ext4_block_bitmap(sb, gdp); if (block_bitmap < first_block || block_bitmap > last_block) { @@ -1524,8 +1520,6 @@ static int ext4_check_descriptors (struct super_block * sb) } if (!flexbg_flag) first_block += EXT4_BLOCKS_PER_GROUP(sb); - gdp = (struct ext4_group_desc *) - ((__u8 *)gdp + EXT4_DESC_SIZE(sb)); } ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); diff --git a/fs/fat/file.c b/fs/fat/file.c index 69a83b59dce8..c614175876e0 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -155,6 +155,42 @@ out: return err; } +static int check_mode(const struct msdos_sb_info *sbi, mode_t mode) +{ + mode_t req = mode & ~S_IFMT; + + /* + * Of the r and x bits, all (subject to umask) must be present. Of the + * w bits, either all (subject to umask) or none must be present. + */ + + if (S_ISREG(mode)) { + req &= ~sbi->options.fs_fmask; + + if ((req & (S_IRUGO | S_IXUGO)) != + ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask)) + return -EPERM; + + if ((req & S_IWUGO) != 0 && + (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask)) + return -EPERM; + } else if (S_ISDIR(mode)) { + req &= ~sbi->options.fs_dmask; + + if ((req & (S_IRUGO | S_IXUGO)) != + ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask)) + return -EPERM; + + if ((req & S_IWUGO) != 0 && + (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask)) + return -EPERM; + } else { + return -EPERM; + } + + return 0; +} + int fat_notify_change(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); @@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && - (attr->ia_gid != sbi->options.fs_gid)) || - ((attr->ia_valid & ATTR_MODE) && - (attr->ia_mode & ~MSDOS_VALID_MODE))) + (attr->ia_gid != sbi->options.fs_gid))) error = -EPERM; if (error) { @@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) error = 0; goto out; } + + if (attr->ia_valid & ATTR_MODE) { + error = check_mode(sbi, attr->ia_mode); + if (error != 0 && !sbi->options.quiet) + goto out; + } + error = inode_setattr(inode, attr); if (error) goto out; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 920a576e1c25..24c0aaa5ae80 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1295,10 +1295,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; if (!IS_FSINFO(fsinfo)) { - printk(KERN_WARNING - "FAT: Did not find valid FSINFO signature.\n" - " Found signature1 0x%08x signature2 0x%08x" - " (sector = %lu)\n", + printk(KERN_WARNING "FAT: Invalid FSINFO signature: " + "0x%08x, 0x%08x (sector = %lu)\n", le32_to_cpu(fsinfo->signature1), le32_to_cpu(fsinfo->signature2), sbi->fsinfo_sector); diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 308f2b6b5026..61f23511eacf 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -55,9 +55,8 @@ void fat_clusters_flush(struct super_block *sb) fsinfo = (struct fat_boot_fsinfo *)bh->b_data; /* Sanity check */ if (!IS_FSINFO(fsinfo)) { - printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n" - " Found signature1 0x%08x signature2 0x%08x" - " (sector = %lu)\n", + printk(KERN_ERR "FAT: Invalid FSINFO signature: " + "0x%08x, 0x%08x (sector = %lu)\n", le32_to_cpu(fsinfo->signature1), le32_to_cpu(fsinfo->signature2), sbi->fsinfo_sector); diff --git a/fs/file.c b/fs/file.c index c5575de01113..5110acb1c9ef 100644 --- a/fs/file.c +++ b/fs/file.c @@ -24,6 +24,8 @@ struct fdtable_defer { struct fdtable *next; }; +int sysctl_nr_open __read_mostly = 1024*1024; + /* * We use this list to defer free fdtables that have vmalloced * sets/arrays. By keeping a per-cpu list, we avoid having to embed @@ -147,8 +149,8 @@ static struct fdtable * alloc_fdtable(unsigned int nr) nr /= (1024 / sizeof(struct file *)); nr = roundup_pow_of_two(nr + 1); nr *= (1024 / sizeof(struct file *)); - if (nr > NR_OPEN) - nr = NR_OPEN; + if (nr > sysctl_nr_open) + nr = sysctl_nr_open; fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); if (!fdt) @@ -233,7 +235,7 @@ int expand_files(struct files_struct *files, int nr) if (nr < fdt->max_fds) return 0; /* Can we expand? */ - if (nr >= NR_OPEN) + if (nr >= sysctl_nr_open) return -EMFILE; /* All good, so we try */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 0b3064079fa5..db80ce9eb1d0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -515,8 +515,7 @@ writeback_inodes(struct writeback_control *wbc) might_sleep(); spin_lock(&sb_lock); restart: - sb = sb_entry(super_blocks.prev); - for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { + list_for_each_entry_reverse(sb, &super_blocks, s_list) { if (sb_has_dirty_inodes(sb)) { /* we're making our own get_super here */ sb->s_count++; @@ -581,10 +580,8 @@ static void set_sb_syncing(int val) { struct super_block *sb; spin_lock(&sb_lock); - sb = sb_entry(super_blocks.prev); - for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { + list_for_each_entry_reverse(sb, &super_blocks, s_list) sb->s_syncing = val; - } spin_unlock(&sb_lock); } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index db534bcde45f..af639807524e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -201,6 +201,55 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) } } +static unsigned len_args(unsigned numargs, struct fuse_arg *args) +{ + unsigned nbytes = 0; + unsigned i; + + for (i = 0; i < numargs; i++) + nbytes += args[i].size; + + return nbytes; +} + +static u64 fuse_get_unique(struct fuse_conn *fc) +{ + fc->reqctr++; + /* zero is special */ + if (fc->reqctr == 0) + fc->reqctr = 1; + + return fc->reqctr; +} + +static void queue_request(struct fuse_conn *fc, struct fuse_req *req) +{ + req->in.h.unique = fuse_get_unique(fc); + req->in.h.len = sizeof(struct fuse_in_header) + + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); + list_add_tail(&req->list, &fc->pending); + req->state = FUSE_REQ_PENDING; + if (!req->waiting) { + req->waiting = 1; + atomic_inc(&fc->num_waiting); + } + wake_up(&fc->waitq); + kill_fasync(&fc->fasync, SIGIO, POLL_IN); +} + +static void flush_bg_queue(struct fuse_conn *fc) +{ + while (fc->active_background < FUSE_MAX_BACKGROUND && + !list_empty(&fc->bg_queue)) { + struct fuse_req *req; + + req = list_entry(fc->bg_queue.next, struct fuse_req, list); + list_del(&req->list); + fc->active_background++; + queue_request(fc, req); + } +} + /* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error @@ -229,6 +278,8 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) clear_bdi_congested(&fc->bdi, WRITE); } fc->num_background--; + fc->active_background--; + flush_bg_queue(fc); } spin_unlock(&fc->lock); wake_up(&req->waitq); @@ -320,42 +371,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) } } -static unsigned len_args(unsigned numargs, struct fuse_arg *args) -{ - unsigned nbytes = 0; - unsigned i; - - for (i = 0; i < numargs; i++) - nbytes += args[i].size; - - return nbytes; -} - -static u64 fuse_get_unique(struct fuse_conn *fc) - { - fc->reqctr++; - /* zero is special */ - if (fc->reqctr == 0) - fc->reqctr = 1; - - return fc->reqctr; -} - -static void queue_request(struct fuse_conn *fc, struct fuse_req *req) -{ - req->in.h.unique = fuse_get_unique(fc); - req->in.h.len = sizeof(struct fuse_in_header) + - len_args(req->in.numargs, (struct fuse_arg *) req->in.args); - list_add_tail(&req->list, &fc->pending); - req->state = FUSE_REQ_PENDING; - if (!req->waiting) { - req->waiting = 1; - atomic_inc(&fc->num_waiting); - } - wake_up(&fc->waitq); - kill_fasync(&fc->fasync, SIGIO, POLL_IN); -} - void request_send(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; @@ -375,20 +390,26 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req) spin_unlock(&fc->lock); } +static void request_send_nowait_locked(struct fuse_conn *fc, + struct fuse_req *req) +{ + req->background = 1; + fc->num_background++; + if (fc->num_background == FUSE_MAX_BACKGROUND) + fc->blocked = 1; + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + set_bdi_congested(&fc->bdi, READ); + set_bdi_congested(&fc->bdi, WRITE); + } + list_add_tail(&req->list, &fc->bg_queue); + flush_bg_queue(fc); +} + static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); if (fc->connected) { - req->background = 1; - fc->num_background++; - if (fc->num_background == FUSE_MAX_BACKGROUND) - fc->blocked = 1; - if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { - set_bdi_congested(&fc->bdi, READ); - set_bdi_congested(&fc->bdi, WRITE); - } - - queue_request(fc, req); + request_send_nowait_locked(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 80d2f5292cf9..f56f91bd38be 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -416,6 +416,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, fuse_put_request(fc, forget_req); d_instantiate(entry, inode); fuse_change_entry_timeout(entry, &outentry); + fuse_invalidate_attr(dir); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { ff->fh = outopen.fh; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index bb05d227cf30..676b0bc8a86d 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -77,8 +77,8 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff) static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) { - dput(req->dentry); - mntput(req->vfsmount); + dput(req->misc.release.dentry); + mntput(req->misc.release.vfsmount); fuse_put_request(fc, req); } @@ -86,7 +86,8 @@ static void fuse_file_put(struct fuse_file *ff) { if (atomic_dec_and_test(&ff->count)) { struct fuse_req *req = ff->reserved_req; - struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode); + struct inode *inode = req->misc.release.dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); req->end = fuse_release_end; request_send_background(fc, req); kfree(ff); @@ -137,7 +138,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode) { struct fuse_req *req = ff->reserved_req; - struct fuse_release_in *inarg = &req->misc.release_in; + struct fuse_release_in *inarg = &req->misc.release.in; inarg->fh = ff->fh; inarg->flags = flags; @@ -153,13 +154,14 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) struct fuse_file *ff = file->private_data; if (ff) { struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = ff->reserved_req; fuse_release_fill(ff, get_node_id(inode), file->f_flags, isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); /* Hold vfsmount and dentry until release is finished */ - ff->reserved_req->vfsmount = mntget(file->f_path.mnt); - ff->reserved_req->dentry = dget(file->f_path.dentry); + req->misc.release.vfsmount = mntget(file->f_path.mnt); + req->misc.release.dentry = dget(file->f_path.dentry); spin_lock(&fc->lock); list_del(&ff->write_entry); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3ab8a3048e8b..67aaf6ee38ea 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -215,7 +215,11 @@ struct fuse_req { /** Data for asynchronous requests */ union { struct fuse_forget_in forget_in; - struct fuse_release_in release_in; + struct { + struct fuse_release_in in; + struct vfsmount *vfsmount; + struct dentry *dentry; + } release; struct fuse_init_in init_in; struct fuse_init_out init_out; struct fuse_read_in read_in; @@ -238,12 +242,6 @@ struct fuse_req { /** File used in the request (or NULL) */ struct fuse_file *ff; - /** vfsmount used in release */ - struct vfsmount *vfsmount; - - /** dentry used in release */ - struct dentry *dentry; - /** Request completion callback */ void (*end)(struct fuse_conn *, struct fuse_req *); @@ -298,6 +296,12 @@ struct fuse_conn { /** Number of requests currently in the background */ unsigned num_background; + /** Number of background requests currently queued for userspace */ + unsigned active_background; + + /** The list of background requests set aside for later queuing */ + struct list_head bg_queue; + /** Pending interrupts */ struct list_head interrupts; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e5e80d1a4687..c90f633d0b57 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -465,6 +465,7 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->io); INIT_LIST_HEAD(&fc->interrupts); + INIT_LIST_HEAD(&fc->bg_queue); atomic_set(&fc->num_waiting, 0); fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index f8452a0eab56..4129cdb3f0d8 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c @@ -52,9 +52,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) rec = (e + b) / 2; len = hfs_brec_lenoff(bnode, rec, &off); keylen = hfs_brec_keylen(bnode, rec); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; - goto done; + goto fail; } hfs_bnode_read(bnode, fd->key, off, keylen); cmpval = bnode->tree->keycmp(fd->key, fd->search_key); @@ -71,9 +71,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) if (rec != e && e >= 0) { len = hfs_brec_lenoff(bnode, e, &off); keylen = hfs_brec_keylen(bnode, e); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; - goto done; + goto fail; } hfs_bnode_read(bnode, fd->key, off, keylen); } @@ -83,6 +83,7 @@ done: fd->keylength = keylen; fd->entryoffset = off + keylen; fd->entrylength = len - keylen; +fail: return res; } @@ -206,7 +207,7 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt) len = hfs_brec_lenoff(bnode, fd->record, &off); keylen = hfs_brec_keylen(bnode, fd->record); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; goto out; } diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 8626ee375ea8..878bf25dbc6a 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -49,14 +49,14 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) if (retval > node->tree->max_key_len + 2) { printk(KERN_ERR "hfs: keylen %d too large\n", retval); - retval = HFS_BAD_KEYLEN; + retval = 0; } } else { retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1; if (retval > node->tree->max_key_len + 1) { printk(KERN_ERR "hfs: keylen %d too large\n", retval); - retval = HFS_BAD_KEYLEN; + retval = 0; } } } diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 110dd3515dc8..24cf6fc43021 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -81,15 +81,23 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke goto fail_page; if (!tree->node_count) goto fail_page; - if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) { - printk(KERN_ERR "hfs: invalid extent max_key_len %d\n", - tree->max_key_len); - goto fail_page; - } - if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) { - printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n", - tree->max_key_len); - goto fail_page; + switch (id) { + case HFS_EXT_CNID: + if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) { + printk(KERN_ERR "hfs: invalid extent max_key_len %d\n", + tree->max_key_len); + goto fail_page; + } + break; + case HFS_CAT_CNID: + if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) { + printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n", + tree->max_key_len); + goto fail_page; + } + break; + default: + BUG(); } tree->node_size_shift = ffs(size) - 1; diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index c6aae61adfe6..6f194d0768b6 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -28,8 +28,6 @@ #define HFS_MAX_NAMELEN 128 #define HFS_MAX_VALENCE 32767U -#define HFS_BAD_KEYLEN 0xFF - /* Meanings of the drAtrb field of the MDB, * Reference: _Inside Macintosh: Files_ p. 2-61 */ diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 16cbd902f8b9..32de44ed0021 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -6,7 +6,7 @@ * This file may be distributed under the terms of the GNU General Public License. * * This file contains hfs_read_super(), some of the super_ops and - * init_module() and cleanup_module(). The remaining super_ops are in + * init_hfs_fs() and exit_hfs_fs(). The remaining super_ops are in * inode.c since they deal with inodes. * * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds diff --git a/fs/inotify.c b/fs/inotify.c index 2c5b92152876..690e72595e6e 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -168,20 +168,14 @@ static void set_dentry_child_flags(struct inode *inode, int watched) struct dentry *child; list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { - if (!child->d_inode) { - WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); + if (!child->d_inode) continue; - } + spin_lock(&child->d_lock); - if (watched) { - WARN_ON(child->d_flags & - DCACHE_INOTIFY_PARENT_WATCHED); + if (watched) child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; - } else { - WARN_ON(!(child->d_flags & - DCACHE_INOTIFY_PARENT_WATCHED)); - child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED; - } + else + child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED; spin_unlock(&child->d_lock); } } @@ -253,7 +247,6 @@ void inotify_d_instantiate(struct dentry *entry, struct inode *inode) if (!inode) return; - WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); spin_lock(&entry->d_lock); parent = entry->d_parent; if (parent->d_inode && inotify_inode_watched(parent->d_inode)) @@ -627,6 +620,7 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, struct inode *inode, u32 mask) { int ret = 0; + int newly_watched; /* don't allow invalid bits: we don't want flags set */ mask &= IN_ALL_EVENTS | IN_ONESHOT; @@ -653,12 +647,18 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, */ watch->inode = igrab(inode); - if (!inotify_inode_watched(inode)) - set_dentry_child_flags(inode, 1); - /* Add the watch to the handle's and the inode's list */ + newly_watched = !inotify_inode_watched(inode); list_add(&watch->h_list, &ih->watches); list_add(&watch->i_list, &inode->inotify_watches); + /* + * Set child flags _after_ adding the watch, so there is no race + * windows where newly instantiated children could miss their parent's + * watched flag. + */ + if (newly_watched) + set_dentry_child_flags(inode, 1); + out: mutex_unlock(&ih->mutex); mutex_unlock(&inode->inotify_mutex); diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 5e009331c01f..a336c9709f3c 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -79,6 +79,7 @@ struct inotify_device { atomic_t count; /* reference count */ struct user_struct *user; /* user who opened this dev */ struct inotify_handle *ih; /* inotify handle */ + struct fasync_struct *fa; /* async notification */ unsigned int queue_size; /* size of the queue (bytes) */ unsigned int event_count; /* number of pending events */ unsigned int max_events; /* maximum number of events */ @@ -248,6 +249,19 @@ inotify_dev_get_event(struct inotify_device *dev) } /* + * inotify_dev_get_last_event - return the last event in the given dev's queue + * + * Caller must hold dev->ev_mutex. + */ +static inline struct inotify_kernel_event * +inotify_dev_get_last_event(struct inotify_device *dev) +{ + if (list_empty(&dev->events)) + return NULL; + return list_entry(dev->events.prev, struct inotify_kernel_event, list); +} + +/* * inotify_dev_queue_event - event handler registered with core inotify, adds * a new event to the given device * @@ -273,7 +287,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, put_inotify_watch(w); /* final put */ /* coalescing: drop this event if it is a dupe of the previous */ - last = inotify_dev_get_event(dev); + last = inotify_dev_get_last_event(dev); if (last && last->event.mask == mask && last->event.wd == wd && last->event.cookie == cookie) { const char *lastname = last->name; @@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, dev->queue_size += sizeof(struct inotify_event) + kevent->event.len; list_add_tail(&kevent->list, &dev->events); wake_up_interruptible(&dev->wq); + kill_fasync(&dev->fa, SIGIO, POLL_IN); out: mutex_unlock(&dev->ev_mutex); @@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, return ret; } +static int inotify_fasync(int fd, struct file *file, int on) +{ + struct inotify_device *dev = file->private_data; + + return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO; +} + static int inotify_release(struct inode *ignored, struct file *file) { struct inotify_device *dev = file->private_data; @@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file) inotify_dev_event_dequeue(dev); mutex_unlock(&dev->ev_mutex); + if (file->f_flags & FASYNC) + inotify_fasync(-1, file, 0); + /* free this device: the put matching the get in inotify_init() */ put_inotify_dev(dev); @@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, static const struct file_operations inotify_fops = { .poll = inotify_poll, .read = inotify_read, + .fasync = inotify_fasync, .release = inotify_release, .unlocked_ioctl = inotify_ioctl, .compat_ioctl = inotify_ioctl, @@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void) goto out_free_dev; } dev->ih = ih; + dev->fa = NULL; filp->f_op = &inotify_fops; filp->f_path.mnt = mntget(inotify_mnt); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 5d14243499d4..3943a8905eb2 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1457,7 +1457,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer) * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */ -void __journal_abort_hard(journal_t *journal) +static void __journal_abort_hard(journal_t *journal) { transaction_t *transaction; char b[BDEVNAME_SIZE]; diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index c5d9694b6a2f..2b8edf4d6eaa 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -354,7 +354,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * obh; struct buffer_head * nbh; - cond_resched(); /* We're under lock_kernel() */ + cond_resched(); /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 921680663fa2..d36356f7d222 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -397,7 +397,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * obh; struct buffer_head * nbh; - cond_resched(); /* We're under lock_kernel() */ + cond_resched(); /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of diff --git a/fs/namei.c b/fs/namei.c index 73e2e665817a..241cff423653 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2188,6 +2188,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { + fsnotify_link_count(dentry->d_inode); d_delete(dentry); } @@ -2360,7 +2361,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de error = dir->i_op->link(old_dentry, dir, new_dentry); mutex_unlock(&old_dentry->d_inode->i_mutex); if (!error) - fsnotify_create(dir, new_dentry); + fsnotify_link(dir, old_dentry->d_inode, new_dentry); return error; } diff --git a/fs/namespace.c b/fs/namespace.c index 61bf376e29e8..e9c10cd01e13 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -25,18 +25,21 @@ #include <linux/security.h> #include <linux/mount.h> #include <linux/ramfs.h> +#include <linux/log2.h> #include <asm/uaccess.h> #include <asm/unistd.h> #include "pnode.h" #include "internal.h" +#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) +#define HASH_SIZE (1UL << HASH_SHIFT) + /* spinlock for vfsmount related operations, inplace of dcache_lock */ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); static int event; static struct list_head *mount_hashtable __read_mostly; -static int hash_mask __read_mostly, hash_bits __read_mostly; static struct kmem_cache *mnt_cache __read_mostly; static struct rw_semaphore namespace_sem; @@ -48,8 +51,8 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); tmp += ((unsigned long)dentry / L1_CACHE_BYTES); - tmp = tmp + (tmp >> hash_bits); - return tmp & hash_mask; + tmp = tmp + (tmp >> HASH_SHIFT); + return tmp & (HASH_SIZE - 1); } struct vfsmount *alloc_vfsmnt(const char *name) @@ -1813,9 +1816,7 @@ static void __init init_mount_tree(void) void __init mnt_init(void) { - struct list_head *d; - unsigned int nr_hash; - int i; + unsigned u; int err; init_rwsem(&namespace_sem); @@ -1828,35 +1829,11 @@ void __init mnt_init(void) if (!mount_hashtable) panic("Failed to allocate mount hash table\n"); - /* - * Find the power-of-two list-heads that can fit into the allocation.. - * We don't guarantee that "sizeof(struct list_head)" is necessarily - * a power-of-two. - */ - nr_hash = PAGE_SIZE / sizeof(struct list_head); - hash_bits = 0; - do { - hash_bits++; - } while ((nr_hash >> hash_bits) != 0); - hash_bits--; + printk("Mount-cache hash table entries: %lu\n", HASH_SIZE); + + for (u = 0; u < HASH_SIZE; u++) + INIT_LIST_HEAD(&mount_hashtable[u]); - /* - * Re-calculate the actual number of entries and the mask - * from the number of bits we can fit. - */ - nr_hash = 1UL << hash_bits; - hash_mask = nr_hash - 1; - - printk("Mount-cache hash table entries: %d\n", nr_hash); - - /* And initialize the newly allocated array */ - d = mount_hashtable; - i = nr_hash; - do { - INIT_LIST_HEAD(d); - d++; - i--; - } while (i); err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index e1cb70c643f8..eff1f18d034f 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -987,7 +987,7 @@ static struct file_system_type ncp_fs_type = { static int __init init_ncp_fs(void) { int err; - DPRINTK("ncpfs: init_module called\n"); + DPRINTK("ncpfs: init_ncp_fs called\n"); err = init_inodecache(); if (err) @@ -1004,7 +1004,7 @@ out1: static void __exit exit_ncp_fs(void) { - DPRINTK("ncpfs: cleanup_module called\n"); + DPRINTK("ncpfs: exit_ncp_fs called\n"); unregister_filesystem(&ncp_fs_type); destroy_inodecache(); } diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index a99acd8de353..cb5f0a3f1b03 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig @@ -198,7 +198,7 @@ config LDM_DEBUG config SGI_PARTITION bool "SGI partition support" if PARTITION_ADVANCED - default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN)) + default y if DEFAULT_SGI_PARTITION help Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. diff --git a/fs/pnode.c b/fs/pnode.c index 89940f243fc2..05ba692bc540 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -83,6 +83,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) mnt->mnt_master = NULL; if (type == MS_UNBINDABLE) mnt->mnt_flags |= MNT_UNBINDABLE; + else + mnt->mnt_flags &= ~MNT_UNBINDABLE; } } diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 51288db37a0c..2686592dbcb2 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -29,6 +29,7 @@ #include <linux/mm.h> #include <linux/mmzone.h> #include <linux/pagemap.h> +#include <linux/interrupt.h> #include <linux/swap.h> #include <linux/slab.h> #include <linux/smp.h> @@ -64,7 +65,6 @@ */ extern int get_hardware_list(char *); extern int get_stram_list(char *); -extern int get_filesystem_list(char *); extern int get_exec_domain_list(char *); extern int get_dma_list(char *); @@ -84,10 +84,15 @@ static int loadavg_read_proc(char *page, char **start, off_t off, { int a, b, c; int len; + unsigned long seq; + + do { + seq = read_seqbegin(&xtime_lock); + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + } while (read_seqretry(&xtime_lock, seq)); - a = avenrun[0] + (FIXED_1/200); - b = avenrun[1] + (FIXED_1/200); - c = avenrun[2] + (FIXED_1/200); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), @@ -599,7 +604,6 @@ static void int_seq_stop(struct seq_file *f, void *v) } -extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */ static struct seq_operations int_seq_ops = { .start = int_seq_start, .next = int_seq_next, diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 5e7388b32d02..740bb8c0c1ae 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -575,6 +575,8 @@ void print_block(struct buffer_head *bh, ...) //int print_mode, int first, int l printk ("Block %llu contains unformatted data\n", (unsigned long long)bh->b_blocknr); + + va_end(args); } static char print_tb_buf[2048]; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 1597f6b649e0..a5bd23ce0e46 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -1084,7 +1084,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) } /* This is the implementation for the xattr plugin infrastructure */ -static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers); +static LIST_HEAD(xattr_handlers); static DEFINE_RWLOCK(handler_lock); static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char diff --git a/fs/select.c b/fs/select.c index 47f47925aea2..5633fe980781 100644 --- a/fs/select.c +++ b/fs/select.c @@ -739,7 +739,7 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, timeout_jiffies = -1; else #endif - timeout_jiffies = msecs_to_jiffies(timeout_msecs); + timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1; } else { /* Infinite (< 0) or no (0) timeout */ timeout_jiffies = timeout_msecs; diff --git a/fs/signalfd.c b/fs/signalfd.c index 2d3e107da2d3..cb2b63ae0bf4 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/anon_inodes.h> #include <linux/signalfd.h> +#include <linux/syscalls.h> struct signalfd_ctx { sigset_t sigmask; diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index e48bd8235a8e..e37fe4deebd0 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -329,9 +329,8 @@ smb_receive(struct smb_sb_info *server, struct smb_request *req) msg.msg_control = NULL; /* Dont repeat bytes and count available bufferspace */ - rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd); - if (req->rq_rlen < rlen) - rlen = req->rq_rlen; + rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd), + (req->rq_rlen - req->rq_bytes_recvd)); result = kernel_recvmsg(sock, &msg, p, num, rlen, flags); diff --git a/fs/utimes.c b/fs/utimes.c index b9912ecbee24..e5588cd8530e 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -6,6 +6,7 @@ #include <linux/sched.h> #include <linux/stat.h> #include <linux/utime.h> +#include <linux/syscalls.h> #include <asm/uaccess.h> #include <asm/unistd.h> |