diff options
author | Nathan Scott <nathans@bruce> | 2006-03-22 15:31:14 +1100 |
---|---|---|
committer | Nathan Scott <nathans@bruce> | 2006-03-22 15:31:14 +1100 |
commit | 4d74f423c722b8cadfabe087369200013b217b67 (patch) | |
tree | d62facddfdb0dfd89f3e61f4fc699cf2feb4b082 /fs | |
parent | bb19fba1937cb6ab2bb98ac893365f6ebf88ef1b (diff) | |
parent | e952f31bce6e9f64db01f607abc46529ba57ac9e (diff) | |
download | linux-4d74f423c722b8cadfabe087369200013b217b67.tar.gz linux-4d74f423c722b8cadfabe087369200013b217b67.tar.bz2 linux-4d74f423c722b8cadfabe087369200013b217b67.zip |
Merge HEAD from ../linux-2.6
Diffstat (limited to 'fs')
40 files changed, 585 insertions, 272 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index ae6d032b9b59..cd5eeb032d64 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -202,7 +202,6 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) filp->private_data = NULL; } - d_drop(filp->f_dentry); return 0; } diff --git a/fs/buffer.c b/fs/buffer.c index 62cfd17dc5fe..a9b399402007 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -3060,6 +3060,7 @@ int buffer_migrate_page(struct page *newpage, struct page *page) { struct address_space *mapping = page->mapping; struct buffer_head *bh, *head; + int rc; if (!mapping) return -EAGAIN; @@ -3069,8 +3070,9 @@ int buffer_migrate_page(struct page *newpage, struct page *page) head = page_buffers(page); - if (migrate_page_remove_references(newpage, page, 3)) - return -EAGAIN; + rc = migrate_page_remove_references(newpage, page, 3); + if (rc) + return rc; bh = head; do { diff --git a/fs/char_dev.c b/fs/char_dev.c index 21195c481637..5c36345c9bf7 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -19,6 +19,7 @@ #include <linux/kobject.h> #include <linux/kobj_map.h> #include <linux/cdev.h> +#include <linux/mutex.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -28,7 +29,7 @@ static struct kobj_map *cdev_map; #define MAX_PROBE_HASH 255 /* random */ -static DECLARE_MUTEX(chrdevs_lock); +static DEFINE_MUTEX(chrdevs_lock); static struct char_device_struct { struct char_device_struct *next; @@ -88,13 +89,13 @@ out: void *acquire_chrdev_list(void) { - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); return get_next_chrdev(NULL); } void release_chrdev_list(void *dev) { - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); kfree(dev); } @@ -151,7 +152,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, memset(cd, 0, sizeof(struct char_device_struct)); - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); /* temporary */ if (major == 0) { @@ -186,10 +187,10 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, } cd->next = *cp; *cp = cd; - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); return cd; out: - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); kfree(cd); return ERR_PTR(ret); } @@ -200,7 +201,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); - down(&chrdevs_lock); + mutex_lock(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && @@ -210,7 +211,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) cd = *cp; *cp = cd->next; } - up(&chrdevs_lock); + mutex_unlock(&chrdevs_lock); return cd; } diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index d575452cd9f7..40c4fc973fad 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -251,3 +251,49 @@ struct dentry *debugfs_create_bool(const char *name, mode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_bool); +static ssize_t read_file_blob(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct debugfs_blob_wrapper *blob = file->private_data; + return simple_read_from_buffer(user_buf, count, ppos, blob->data, + blob->size); +} + +static struct file_operations fops_blob = { + .read = read_file_blob, + .open = default_open, +}; + +/** + * debugfs_create_blob - create a file in the debugfs filesystem that is + * used to read and write a binary blob. + * + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this paramater is NULL, then the + * file will be created in the root of the debugfs filesystem. + * @blob: a pointer to a struct debugfs_blob_wrapper which contains a pointer + * to the blob data and the size of the data. + * + * This function creates a file in debugfs with the given name that exports + * @blob->data as a binary blob. If the @mode variable is so set it can be + * read from. Writing is not supported. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the debugfs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, NULL will be returned. + * + * If debugfs is not enabled in the kernel, the value -ENODEV will be + * returned. It is not wise to check for this value, but rather, check for + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling + * code. + */ +struct dentry *debugfs_create_blob(const char *name, mode_t mode, + struct dentry *parent, + struct debugfs_blob_wrapper *blob) +{ + return debugfs_create_file(name, mode, parent, blob, &fops_blob); +} +EXPORT_SYMBOL_GPL(debugfs_create_blob); diff --git a/fs/direct-io.c b/fs/direct-io.c index 848044af7e16..27f3e787faca 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -1155,15 +1155,16 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, * For writes, i_mutex is not held on entry; it is never taken. * * DIO_LOCKING (simple locking for regular files) - * For writes we are called under i_mutex and return with i_mutex held, even though - * it is internally dropped. + * For writes we are called under i_mutex and return with i_mutex held, even + * though it is internally dropped. * For reads, i_mutex is not held on entry, but it is taken and dropped before * returning. * * DIO_OWN_LOCKING (filesystem provides synchronisation and handling of * uninitialised data, allowing parallel direct readers and writers) * For writes we are called without i_mutex, return without it, never touch it. - * For reads, i_mutex is held on entry and will be released before returning. + * For reads we are called under i_mutex and return with i_mutex held, even + * though it may be internally dropped. * * Additional i_alloc_sem locking requirements described inline below. */ @@ -1182,7 +1183,8 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, ssize_t retval = -EINVAL; loff_t end = offset; struct dio *dio; - int reader_with_isem = (rw == READ && dio_lock_type == DIO_OWN_LOCKING); + int release_i_mutex = 0; + int acquire_i_mutex = 0; if (rw & WRITE) current->flags |= PF_SYNCWRITE; @@ -1225,7 +1227,6 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, * writers need to grab i_alloc_sem only (i_mutex is already held) * For regular files using DIO_OWN_LOCKING, * neither readers nor writers take any locks here - * (i_mutex is already held and release for writers here) */ dio->lock_type = dio_lock_type; if (dio_lock_type != DIO_NO_LOCKING) { @@ -1236,7 +1237,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, mapping = iocb->ki_filp->f_mapping; if (dio_lock_type != DIO_OWN_LOCKING) { mutex_lock(&inode->i_mutex); - reader_with_isem = 1; + release_i_mutex = 1; } retval = filemap_write_and_wait_range(mapping, offset, @@ -1248,7 +1249,7 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, if (dio_lock_type == DIO_OWN_LOCKING) { mutex_unlock(&inode->i_mutex); - reader_with_isem = 0; + acquire_i_mutex = 1; } } @@ -1269,11 +1270,13 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, nr_segs, blkbits, get_blocks, end_io, dio); if (rw == READ && dio_lock_type == DIO_LOCKING) - reader_with_isem = 0; + release_i_mutex = 0; out: - if (reader_with_isem) + if (release_i_mutex) mutex_unlock(&inode->i_mutex); + else if (acquire_i_mutex) + mutex_lock(&inode->i_mutex); if (rw & WRITE) current->flags &= ~PF_SYNCWRITE; return retval; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 7442bdd1267a..b3dbd716cd3a 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -256,11 +256,10 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) 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); - int ret; + int need_revalidate = filp->f_version != inode->i_version; if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) - goto success; + return 0; if (EXT2_HAS_INCOMPAT_FEATURE(sb, EXT2_FEATURE_INCOMPAT_FILETYPE)) types = ext2_filetype_table; @@ -275,12 +274,15 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) "bad page in #%lu", inode->i_ino); filp->f_pos += PAGE_CACHE_SIZE - offset; - ret = -EIO; - goto done; + return -EIO; } kaddr = page_address(page); - if (need_revalidate) { - offset = ext2_validate_entry(kaddr, offset, chunk_mask); + 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); @@ -289,9 +291,8 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) if (de->rec_len == 0) { ext2_error(sb, __FUNCTION__, "zero-length directory entry"); - ret = -EIO; ext2_put_page(page); - goto done; + return -EIO; } if (de->inode) { int over; @@ -306,19 +307,14 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir) le32_to_cpu(de->inode), d_type); if (over) { ext2_put_page(page); - goto success; + return 0; } } filp->f_pos += le16_to_cpu(de->rec_len); } ext2_put_page(page); } - -success: - ret = 0; -done: - filp->f_version = inode->i_version; - return ret; + return 0; } /* diff --git a/fs/jfs/Makefile b/fs/jfs/Makefile index 6f1e0e95587a..3adb6395e42d 100644 --- a/fs/jfs/Makefile +++ b/fs/jfs/Makefile @@ -8,7 +8,8 @@ jfs-y := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \ jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \ jfs_unicode.o jfs_dtree.o jfs_inode.o \ jfs_extent.o symlink.o jfs_metapage.o \ - jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o resize.o xattr.o + jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o \ + resize.o xattr.o ioctl.o jfs-$(CONFIG_JFS_POSIX_ACL) += acl.o diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 461e4934ca7c..e2281300979c 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -183,6 +183,9 @@ cleanup: posix_acl_release(acl); } else inode->i_mode &= ~current->fs->umask; + + JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) | + inode->i_mode; return rc; } @@ -207,12 +210,12 @@ static int jfs_acl_chmod(struct inode *inode) rc = posix_acl_chmod_masq(clone, inode->i_mode); if (!rc) { tid_t tid = txBegin(inode->i_sb, 0); - down(&JFS_IP(inode)->commit_sem); + mutex_lock(&JFS_IP(inode)->commit_mutex); rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, clone); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&JFS_IP(inode)->commit_sem); + mutex_unlock(&JFS_IP(inode)->commit_mutex); } posix_acl_release(clone); diff --git a/fs/jfs/file.c b/fs/jfs/file.c index c2c19c9ed9a4..e1ac6e497e2b 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -113,4 +113,5 @@ struct file_operations jfs_file_operations = { .sendfile = generic_file_sendfile, .fsync = jfs_fsync, .release = jfs_release, + .ioctl = jfs_ioctl, }; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 9f942ca8e4e3..51a5fed90cca 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -55,6 +55,7 @@ void jfs_read_inode(struct inode *inode) inode->i_op = &jfs_file_inode_operations; init_special_inode(inode, inode->i_mode, inode->i_rdev); } + jfs_set_inode_flags(inode); } /* @@ -89,16 +90,16 @@ int jfs_commit_inode(struct inode *inode, int wait) } tid = txBegin(inode->i_sb, COMMIT_INODE); - down(&JFS_IP(inode)->commit_sem); + mutex_lock(&JFS_IP(inode)->commit_mutex); /* - * Retest inode state after taking commit_sem + * Retest inode state after taking commit_mutex */ if (inode->i_nlink && test_cflag(COMMIT_Dirty, inode)) rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0); txEnd(tid); - up(&JFS_IP(inode)->commit_sem); + mutex_unlock(&JFS_IP(inode)->commit_mutex); return rc; } @@ -335,18 +336,18 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length) tid = txBegin(ip->i_sb, 0); /* - * The commit_sem cannot be taken before txBegin. + * The commit_mutex cannot be taken before txBegin. * txBegin may block and there is a chance the inode * could be marked dirty and need to be committed * before txBegin unblocks */ - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); newsize = xtTruncate(tid, ip, length, COMMIT_TRUNCATE | COMMIT_PWMAP); if (newsize < 0) { txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); break; } @@ -355,7 +356,7 @@ void jfs_truncate_nolock(struct inode *ip, loff_t length) txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); } while (newsize > length); /* Truncate isn't always atomic */ } diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c new file mode 100644 index 000000000000..67b3774820eb --- /dev/null +++ b/fs/jfs/ioctl.c @@ -0,0 +1,107 @@ +/* + * linux/fs/jfs/ioctl.c + * + * Copyright (C) 2006 Herbert Poetzl + * adapted from Remy Card's ext2/ioctl.c + */ + +#include <linux/fs.h> +#include <linux/ext2_fs.h> +#include <linux/ctype.h> +#include <linux/capability.h> +#include <linux/time.h> +#include <asm/current.h> +#include <asm/uaccess.h> + +#include "jfs_incore.h" +#include "jfs_dinode.h" +#include "jfs_inode.h" + + +static struct { + long jfs_flag; + long ext2_flag; +} jfs_map[] = { + {JFS_NOATIME_FL, EXT2_NOATIME_FL}, + {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL}, + {JFS_SYNC_FL, EXT2_SYNC_FL}, + {JFS_SECRM_FL, EXT2_SECRM_FL}, + {JFS_UNRM_FL, EXT2_UNRM_FL}, + {JFS_APPEND_FL, EXT2_APPEND_FL}, + {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL}, + {0, 0}, +}; + +static long jfs_map_ext2(unsigned long flags, int from) +{ + int index=0; + long mapped=0; + + while (jfs_map[index].jfs_flag) { + if (from) { + if (jfs_map[index].ext2_flag & flags) + mapped |= jfs_map[index].jfs_flag; + } else { + if (jfs_map[index].jfs_flag & flags) + mapped |= jfs_map[index].ext2_flag; + } + index++; + } + return mapped; +} + + +int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + struct jfs_inode_info *jfs_inode = JFS_IP(inode); + unsigned int flags; + + switch (cmd) { + case JFS_IOC_GETFLAGS: + flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE; + flags = jfs_map_ext2(flags, 0); + return put_user(flags, (int __user *) arg); + case JFS_IOC_SETFLAGS: { + unsigned int oldflags; + + if (IS_RDONLY(inode)) + return -EROFS; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EACCES; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + flags = jfs_map_ext2(flags, 1); + if (!S_ISDIR(inode->i_mode)) + flags &= ~JFS_DIRSYNC_FL; + + oldflags = jfs_inode->mode2; + + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + */ + if ((oldflags & JFS_IMMUTABLE_FL) || + ((flags ^ oldflags) & + (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } + + flags = flags & JFS_FL_USER_MODIFIABLE; + flags |= oldflags & ~JFS_FL_USER_MODIFIABLE; + jfs_inode->mode2 = flags; + + jfs_set_inode_flags(inode); + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + return 0; + } + default: + return -ENOTTY; + } +} + diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h index 580a3258449b..9f2572aea561 100644 --- a/fs/jfs/jfs_dinode.h +++ b/fs/jfs/jfs_dinode.h @@ -139,13 +139,36 @@ struct dinode { /* more extended mode bits: attributes for OS/2 */ #define IREADONLY 0x02000000 /* no write access to file */ -#define IARCHIVE 0x40000000 /* file archive bit */ -#define ISYSTEM 0x08000000 /* system file */ #define IHIDDEN 0x04000000 /* hidden file */ -#define IRASH 0x4E000000 /* mask for changeable attributes */ -#define INEWNAME 0x80000000 /* non-8.3 filename format */ +#define ISYSTEM 0x08000000 /* system file */ + #define IDIRECTORY 0x20000000 /* directory (shadow of real bit) */ +#define IARCHIVE 0x40000000 /* file archive bit */ +#define INEWNAME 0x80000000 /* non-8.3 filename format */ + +#define IRASH 0x4E000000 /* mask for changeable attributes */ #define ATTRSHIFT 25 /* bits to shift to move attribute specification to mode position */ +/* extended attributes for Linux */ + +#define JFS_NOATIME_FL 0x00080000 /* do not update atime */ + +#define JFS_DIRSYNC_FL 0x00100000 /* dirsync behaviour */ +#define JFS_SYNC_FL 0x00200000 /* Synchronous updates */ +#define JFS_SECRM_FL 0x00400000 /* Secure deletion */ +#define JFS_UNRM_FL 0x00800000 /* allow for undelete */ + +#define JFS_APPEND_FL 0x01000000 /* writes to file may only append */ +#define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */ + +#define JFS_FL_USER_VISIBLE 0x03F80000 +#define JFS_FL_USER_MODIFIABLE 0x03F80000 +#define JFS_FL_INHERIT 0x03C80000 + +/* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ +#define JFS_IOC_GETFLAGS _IOR('f', 1, long) +#define JFS_IOC_SETFLAGS _IOW('f', 2, long) + + #endif /*_H_JFS_DINODE */ diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 2967b7393415..c161c98954e0 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -64,9 +64,9 @@ * to the persistent bitmaps in dmaps) is guarded by (busy) buffers. */ -#define BMAP_LOCK_INIT(bmp) init_MUTEX(&bmp->db_bmaplock) -#define BMAP_LOCK(bmp) down(&bmp->db_bmaplock) -#define BMAP_UNLOCK(bmp) up(&bmp->db_bmaplock) +#define BMAP_LOCK_INIT(bmp) mutex_init(&bmp->db_bmaplock) +#define BMAP_LOCK(bmp) mutex_lock(&bmp->db_bmaplock) +#define BMAP_UNLOCK(bmp) mutex_unlock(&bmp->db_bmaplock) /* * forward references @@ -125,7 +125,7 @@ static int dbGetL2AGSize(s64 nblocks); * into the table, with the table elements yielding the maximum * binary buddy of free bits within the character. */ -static s8 budtab[256] = { +static const s8 budtab[256] = { 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -532,10 +532,10 @@ dbUpdatePMap(struct inode *ipbmap, lastlblkno = lblkno; + LOGSYNC_LOCK(log, flags); if (mp->lsn != 0) { /* inherit older/smaller lsn */ logdiff(diffp, mp->lsn, log); - LOGSYNC_LOCK(log, flags); if (difft < diffp) { mp->lsn = lsn; @@ -548,20 +548,17 @@ dbUpdatePMap(struct inode *ipbmap, logdiff(diffp, mp->clsn, log); if (difft > diffp) mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } else { mp->log = log; mp->lsn = lsn; /* insert bp after tblock in logsync list */ - LOGSYNC_LOCK(log, flags); - log->count++; list_add(&mp->synclist, &tblk->synclist); mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } + LOGSYNC_UNLOCK(log, flags); } /* write the last buffer. */ diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 32e25884e7e8..8b14cc8e0228 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h @@ -243,7 +243,7 @@ struct dbmap { struct bmap { struct dbmap db_bmap; /* on-disk aggregate map descriptor */ struct inode *db_ipbmap; /* ptr to aggregate map incore inode */ - struct semaphore db_bmaplock; /* aggregate map lock */ + struct mutex db_bmaplock; /* aggregate map lock */ atomic_t db_active[MAXAG]; /* count of active, open files in AG */ u32 *db_DBmap; }; diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c index 404f33eae507..6c3f08319846 100644 --- a/fs/jfs/jfs_dtree.c +++ b/fs/jfs/jfs_dtree.c @@ -1005,6 +1005,9 @@ static int dtSplitUp(tid_t tid, DT_PUTPAGE(smp); + if (!DO_INDEX(ip)) + ip->i_size = xlen << sbi->l2bsize; + goto freeKeyName; } @@ -1055,7 +1058,9 @@ static int dtSplitUp(tid_t tid, xaddr = addressPXD(pxd) + xlen; dbFree(ip, xaddr, (s64) n); } - } + } else if (!DO_INDEX(ip)) + ip->i_size = lengthPXD(pxd) << sbi->l2bsize; + extendOut: DT_PUTPAGE(smp); @@ -1098,6 +1103,9 @@ static int dtSplitUp(tid_t tid, goto splitOut; } + if (!DO_INDEX(ip)) + ip->i_size += PSIZE; + /* * propagate up the router entry for the leaf page just split * @@ -2424,6 +2432,9 @@ static int dtDeleteUp(tid_t tid, struct inode *ip, break; } + if (!DO_INDEX(ip)) + ip->i_size -= PSIZE; + return 0; } diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index 4879603daa1c..5549378358bf 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c @@ -94,7 +94,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) txBeginAnon(ip->i_sb); /* Avoid race with jfs_commit_inode() */ - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* validate extent length */ if (xlen > MAXXLEN) @@ -136,14 +136,14 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) */ nxlen = xlen; if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) { - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } /* Allocate blocks to quota. */ if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } @@ -165,7 +165,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) if (rc) { dbFree(ip, nxaddr, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } @@ -177,7 +177,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr) mark_inode_dirty(ip); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); /* * COMMIT_SyncList flags an anonymous tlock on page that is on * sync list. @@ -222,7 +222,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) /* This blocks if we are low on resources */ txBeginAnon(ip->i_sb); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* validate extent length */ if (nxlen > MAXXLEN) nxlen = MAXXLEN; @@ -258,7 +258,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) /* Allocat blocks to quota. */ if (DQUOT_ALLOC_BLOCK(ip, nxlen)) { dbFree(ip, nxaddr, (s64) nxlen); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } @@ -338,7 +338,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr) mark_inode_dirty(ip); exit: - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); } #endif /* _NOTYET */ @@ -439,12 +439,12 @@ int extRecord(struct inode *ip, xad_t * xp) txBeginAnon(ip->i_sb); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* update the extent */ rc = xtUpdate(0, ip, xp); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); return rc; } diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 31b4aa13dd4b..ccbe60aff83d 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c @@ -66,14 +66,14 @@ static HLIST_HEAD(aggregate_hash); * imap locks */ /* iag free list lock */ -#define IAGFREE_LOCK_INIT(imap) init_MUTEX(&imap->im_freelock) -#define IAGFREE_LOCK(imap) down(&imap->im_freelock) -#define IAGFREE_UNLOCK(imap) up(&imap->im_freelock) +#define IAGFREE_LOCK_INIT(imap) mutex_init(&imap->im_freelock) +#define IAGFREE_LOCK(imap) mutex_lock(&imap->im_freelock) +#define IAGFREE_UNLOCK(imap) mutex_unlock(&imap->im_freelock) /* per ag iag list locks */ -#define AG_LOCK_INIT(imap,index) init_MUTEX(&(imap->im_aglock[index])) -#define AG_LOCK(imap,agno) down(&imap->im_aglock[agno]) -#define AG_UNLOCK(imap,agno) up(&imap->im_aglock[agno]) +#define AG_LOCK_INIT(imap,index) mutex_init(&(imap->im_aglock[index])) +#define AG_LOCK(imap,agno) mutex_lock(&imap->im_aglock[agno]) +#define AG_UNLOCK(imap,agno) mutex_unlock(&imap->im_aglock[agno]) /* * forward references @@ -1261,7 +1261,7 @@ int diFree(struct inode *ip) * to be freed by the transaction; */ tid = txBegin(ipimap->i_sb, COMMIT_FORCE); - down(&JFS_IP(ipimap)->commit_sem); + mutex_lock(&JFS_IP(ipimap)->commit_mutex); /* acquire tlock of the iag page of the freed ixad * to force the page NOHOMEOK (even though no data is @@ -1294,7 +1294,7 @@ int diFree(struct inode *ip) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); /* unlock the AG inode map information */ AG_UNLOCK(imap, agno); @@ -2554,13 +2554,13 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) * addressing structure pointing to the new iag page; */ tid = txBegin(sb, COMMIT_FORCE); - down(&JFS_IP(ipimap)->commit_sem); + mutex_lock(&JFS_IP(ipimap)->commit_mutex); /* update the inode map addressing structure to point to it */ if ((rc = xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) { txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); /* Free the blocks allocated for the iag since it was * not successfully added to the inode map */ @@ -2626,7 +2626,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp) rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); txEnd(tid); - up(&JFS_IP(ipimap)->commit_sem); + mutex_unlock(&JFS_IP(ipimap)->commit_mutex); duplicateIXtree(sb, blkno, xlen, &xaddr); @@ -2844,11 +2844,11 @@ diUpdatePMap(struct inode *ipimap, */ lsn = tblk->lsn; log = JFS_SBI(tblk->sb)->log; + LOGSYNC_LOCK(log, flags); if (mp->lsn != 0) { /* inherit older/smaller lsn */ logdiff(difft, lsn, log); logdiff(diffp, mp->lsn, log); - LOGSYNC_LOCK(log, flags); if (difft < diffp) { mp->lsn = lsn; /* move mp after tblock in logsync list */ @@ -2860,17 +2860,15 @@ diUpdatePMap(struct inode *ipimap, logdiff(diffp, mp->clsn, log); if (difft > diffp) mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } else { mp->log = log; mp->lsn = lsn; /* insert mp after tblock in logsync list */ - LOGSYNC_LOCK(log, flags); log->count++; list_add(&mp->synclist, &tblk->synclist); mp->clsn = tblk->clsn; - LOGSYNC_UNLOCK(log, flags); } + LOGSYNC_UNLOCK(log, flags); write_metapage(mp); return (0); } @@ -3076,14 +3074,40 @@ static void duplicateIXtree(struct super_block *sb, s64 blkno, static int copy_from_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff; + if (sbi->umask != -1) { + ip->i_mode = (ip->i_mode & ~0777) | (0777 & ~sbi->umask); + /* For directories, add x permission if r is allowed by umask */ + if (S_ISDIR(ip->i_mode)) { + if (ip->i_mode & 0400) + ip->i_mode |= 0100; + if (ip->i_mode & 0040) + ip->i_mode |= 0010; + if (ip->i_mode & 0004) + ip->i_mode |= 0001; + } + } ip->i_nlink = le32_to_cpu(dip->di_nlink); - ip->i_uid = le32_to_cpu(dip->di_uid); - ip->i_gid = le32_to_cpu(dip->di_gid); + + jfs_ip->saved_uid = le32_to_cpu(dip->di_uid); + if (sbi->uid == -1) + ip->i_uid = jfs_ip->saved_uid; + else { + ip->i_uid = sbi->uid; + } + + jfs_ip->saved_gid = le32_to_cpu(dip->di_gid); + if (sbi->gid == -1) + ip->i_gid = jfs_ip->saved_gid; + else { + ip->i_gid = sbi->gid; + } + ip->i_size = le64_to_cpu(dip->di_size); ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec); ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec); @@ -3134,21 +3158,33 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip) static void copy_to_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); dip->di_fileset = cpu_to_le32(jfs_ip->fileset); - dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp); + dip->di_inostamp = cpu_to_le32(sbi->inostamp); dip->di_number = cpu_to_le32(ip->i_ino); dip->di_gen = cpu_to_le32(ip->i_generation); dip->di_size = cpu_to_le64(ip->i_size); dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); dip->di_nlink = cpu_to_le32(ip->i_nlink); - dip->di_uid = cpu_to_le32(ip->i_uid); - dip->di_gid = cpu_to_le32(ip->i_gid); + if (sbi->uid == -1) + dip->di_uid = cpu_to_le32(ip->i_uid); + else + dip->di_uid = cpu_to_le32(jfs_ip->saved_uid); + if (sbi->gid == -1) + dip->di_gid = cpu_to_le32(ip->i_gid); + else + dip->di_gid = cpu_to_le32(jfs_ip->saved_gid); /* * mode2 is only needed for storing the higher order bits. * Trust i_mode for the lower order ones */ - dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode); + if (sbi->umask == -1) + dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | + ip->i_mode); + else /* Leave the original permissions alone */ + dip->di_mode = cpu_to_le32(jfs_ip->mode2); + dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime.tv_sec); dip->di_atime.tv_nsec = cpu_to_le32(ip->i_atime.tv_nsec); dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime.tv_sec); diff --git a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h index 6b59adec036a..6e24465f0f98 100644 --- a/fs/jfs/jfs_imap.h +++ b/fs/jfs/jfs_imap.h @@ -140,8 +140,8 @@ struct dinomap { struct inomap { struct dinomap im_imap; /* 4096: inode allocation control */ struct inode *im_ipimap; /* 4: ptr to inode for imap */ - struct semaphore im_freelock; /* 4: iag free list lock */ - struct semaphore im_aglock[MAXAG]; /* 512: per AG locks */ + struct mutex im_freelock; /* 4: iag free list lock */ + struct mutex im_aglock[MAXAG]; /* 512: per AG locks */ u32 *im_DBGdimap; atomic_t im_numinos; /* num of backed inodes */ atomic_t im_numfree; /* num of free backed inodes */ diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index dc21a5bd54d4..54d73716ca8c 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h @@ -19,6 +19,7 @@ #ifndef _H_JFS_INCORE #define _H_JFS_INCORE +#include <linux/mutex.h> #include <linux/rwsem.h> #include <linux/slab.h> #include <linux/bitops.h> @@ -37,6 +38,8 @@ struct jfs_inode_info { int fileset; /* fileset number (always 16)*/ uint mode2; /* jfs-specific mode */ + uint saved_uid; /* saved for uid mount option */ + uint saved_gid; /* saved for gid mount option */ pxd_t ixpxd; /* inode extent descriptor */ dxd_t acl; /* dxd describing acl */ dxd_t ea; /* dxd describing ea */ @@ -62,12 +65,12 @@ struct jfs_inode_info { */ struct rw_semaphore rdwrlock; /* - * commit_sem serializes transaction processing on an inode. + * commit_mutex serializes transaction processing on an inode. * It must be taken after beginning a transaction (txBegin), since * dirty inodes may be committed while a new transaction on the * inode is blocked in txBegin or TxBeginAnon */ - struct semaphore commit_sem; + struct mutex commit_mutex; /* xattr_sem allows us to access the xattrs without taking i_mutex */ struct rw_semaphore xattr_sem; lid_t xtlid; /* lid of xtree lock on directory */ @@ -169,6 +172,9 @@ struct jfs_sb_info { uint state; /* mount/recovery state */ unsigned long flag; /* mount time flags */ uint p_state; /* state prior to going no integrity */ + uint uid; /* uid to override on-disk uid */ + uint gid; /* gid to override on-disk gid */ + uint umask; /* umask to override on-disk umask */ }; /* jfs_sb_info commit_state */ diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 2af5efbfd06f..495df402916d 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -25,6 +25,26 @@ #include "jfs_dinode.h" #include "jfs_debug.h" + +void jfs_set_inode_flags(struct inode *inode) +{ + unsigned int flags = JFS_IP(inode)->mode2; + + inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | + S_NOATIME | S_DIRSYNC | S_SYNC); + + if (flags & JFS_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & JFS_APPEND_FL) + inode->i_flags |= S_APPEND; + if (flags & JFS_NOATIME_FL) + inode->i_flags |= S_NOATIME; + if (flags & JFS_DIRSYNC_FL) + inode->i_flags |= S_DIRSYNC; + if (flags & JFS_SYNC_FL) + inode->i_flags |= S_SYNC; +} + /* * NAME: ialloc() * @@ -63,6 +83,13 @@ struct inode *ialloc(struct inode *parent, umode_t mode) inode->i_gid = current->fsgid; /* + * New inodes need to save sane values on disk when + * uid & gid mount options are used + */ + jfs_inode->saved_uid = inode->i_uid; + jfs_inode->saved_gid = inode->i_gid; + + /* * Allocate inode to quota. */ if (DQUOT_ALLOC_INODE(inode)) { @@ -74,10 +101,20 @@ struct inode *ialloc(struct inode *parent, umode_t mode) } inode->i_mode = mode; - if (S_ISDIR(mode)) - jfs_inode->mode2 = IDIRECTORY | mode; - else - jfs_inode->mode2 = INLINEEA | ISPARSE | mode; + /* inherit flags from parent */ + jfs_inode->mode2 = JFS_IP(parent)->mode2 & JFS_FL_INHERIT; + + if (S_ISDIR(mode)) { + jfs_inode->mode2 |= IDIRECTORY; + jfs_inode->mode2 &= ~JFS_DIRSYNC_FL; + } + else { + jfs_inode->mode2 |= INLINEEA | ISPARSE; + if (S_ISLNK(mode)) + jfs_inode->mode2 &= ~(JFS_IMMUTABLE_FL|JFS_APPEND_FL); + } + jfs_inode->mode2 |= mode; + inode->i_blksize = sb->s_blocksize; inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -98,6 +135,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode) jfs_inode->atlhead = 0; jfs_inode->atltail = 0; jfs_inode->xtlid = 0; + jfs_set_inode_flags(inode); jfs_info("ialloc returns inode = 0x%p\n", inode); diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index b54bac576cb3..095d471b9f9a 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -20,6 +20,8 @@ extern struct inode *ialloc(struct inode *, umode_t); extern int jfs_fsync(struct file *, struct dentry *, int); +extern int jfs_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); extern void jfs_read_inode(struct inode *); extern int jfs_commit_inode(struct inode *, int); extern int jfs_write_inode(struct inode*, int); @@ -29,6 +31,7 @@ extern void jfs_truncate(struct inode *); extern void jfs_truncate_nolock(struct inode *, loff_t); extern void jfs_free_zero_link(struct inode *); extern struct dentry *jfs_get_parent(struct dentry *dentry); +extern void jfs_set_inode_flags(struct inode *); extern struct address_space_operations jfs_aops; extern struct inode_operations jfs_dir_inode_operations; diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h index 10ad1d086685..70ac9f7d1e00 100644 --- a/fs/jfs/jfs_lock.h +++ b/fs/jfs/jfs_lock.h @@ -20,6 +20,7 @@ #define _H_JFS_LOCK #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/sched.h> /* diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index d27bac6acaa3..0b348b13b551 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -64,6 +64,7 @@ #include <linux/interrupt.h> #include <linux/smp_lock.h> #include <linux/completion.h> +#include <linux/kthread.h> #include <linux/buffer_head.h> /* for sync_blockdev() */ #include <linux/bio.h> #include <linux/suspend.h> @@ -81,15 +82,14 @@ */ static struct lbuf *log_redrive_list; static DEFINE_SPINLOCK(log_redrive_lock); -DECLARE_WAIT_QUEUE_HEAD(jfs_IO_thread_wait); /* * log read/write serialization (per log) */ -#define LOG_LOCK_INIT(log) init_MUTEX(&(log)->loglock) -#define LOG_LOCK(log) down(&((log)->loglock)) -#define LOG_UNLOCK(log) up(&((log)->loglock)) +#define LOG_LOCK_INIT(log) mutex_init(&(log)->loglock) +#define LOG_LOCK(log) mutex_lock(&((log)->loglock)) +#define LOG_UNLOCK(log) mutex_unlock(&((log)->loglock)) /* @@ -1105,11 +1105,10 @@ int lmLogOpen(struct super_block *sb) } } - if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) { + if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) { up(&jfs_log_sem); return -ENOMEM; } - memset(log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&log->sb_list); init_waitqueue_head(&log->syncwait); @@ -1181,9 +1180,8 @@ static int open_inline_log(struct super_block *sb) struct jfs_log *log; int rc; - if (!(log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL))) + if (!(log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL))) return -ENOMEM; - memset(log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&log->sb_list); init_waitqueue_head(&log->syncwait); @@ -1216,12 +1214,11 @@ static int open_dummy_log(struct super_block *sb) down(&jfs_log_sem); if (!dummy_log) { - dummy_log = kmalloc(sizeof(struct jfs_log), GFP_KERNEL); + dummy_log = kzalloc(sizeof(struct jfs_log), GFP_KERNEL); if (!dummy_log) { up(&jfs_log_sem); return -ENOMEM; } - memset(dummy_log, 0, sizeof(struct jfs_log)); INIT_LIST_HEAD(&dummy_log->sb_list); init_waitqueue_head(&dummy_log->syncwait); dummy_log->no_integrity = 1; @@ -1980,7 +1977,7 @@ static inline void lbmRedrive(struct lbuf *bp) log_redrive_list = bp; spin_unlock_irqrestore(&log_redrive_lock, flags); - wake_up(&jfs_IO_thread_wait); + wake_up_process(jfsIOthread); } @@ -2347,13 +2344,7 @@ int jfsIOWait(void *arg) { struct lbuf *bp; - daemonize("jfsIO"); - - complete(&jfsIOwait); - do { - DECLARE_WAITQUEUE(wq, current); - spin_lock_irq(&log_redrive_lock); while ((bp = log_redrive_list) != 0) { log_redrive_list = bp->l_redrive_next; @@ -2362,21 +2353,19 @@ int jfsIOWait(void *arg) lbmStartIO(bp); spin_lock_irq(&log_redrive_lock); } + spin_unlock_irq(&log_redrive_lock); + if (freezing(current)) { - spin_unlock_irq(&log_redrive_lock); refrigerator(); } else { - add_wait_queue(&jfs_IO_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&log_redrive_lock); schedule(); current->state = TASK_RUNNING; - remove_wait_queue(&jfs_IO_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); jfs_info("jfsIOWait being killed!"); - complete_and_exit(&jfsIOwait, 0); + return 0; } /* diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index e4978b5b65ee..8c6909b80014 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h @@ -389,7 +389,7 @@ struct jfs_log { int eor; /* 4: eor of last record in eol page */ struct lbuf *bp; /* 4: current log page buffer */ - struct semaphore loglock; /* 4: log write serialization lock */ + struct mutex loglock; /* 4: log write serialization lock */ /* syncpt */ int nextsync; /* 4: bytes to write before next syncpt */ diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 8a53981f9f27..5fbaeaadccd3 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -104,10 +104,9 @@ static inline int insert_metapage(struct page *page, struct metapage *mp) if (PagePrivate(page)) a = mp_anchor(page); else { - a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS); + a = kzalloc(sizeof(struct meta_anchor), GFP_NOFS); if (!a) return -ENOMEM; - memset(a, 0, sizeof(struct meta_anchor)); set_page_private(page, (unsigned long)a); SetPagePrivate(page); kmap(page); diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h index fcf781bf31cb..682cf1a68a18 100644 --- a/fs/jfs/jfs_superblock.h +++ b/fs/jfs/jfs_superblock.h @@ -113,12 +113,9 @@ extern int jfs_mount(struct super_block *); extern int jfs_mount_rw(struct super_block *, int); extern int jfs_umount(struct super_block *); extern int jfs_umount_rw(struct super_block *); - -extern int jfs_stop_threads; -extern struct completion jfsIOwait; -extern wait_queue_head_t jfs_IO_thread_wait; -extern wait_queue_head_t jfs_commit_thread_wait; -extern wait_queue_head_t jfs_sync_thread_wait; extern int jfs_extendfs(struct super_block *, s64, int); +extern struct task_struct *jfsIOthread; +extern struct task_struct *jfsSyncThread; + #endif /*_H_JFS_SUPERBLOCK */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 2ddb6b892bcf..ac3d66948e8c 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -49,6 +49,7 @@ #include <linux/suspend.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/kthread.h> #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -121,8 +122,7 @@ static DEFINE_SPINLOCK(jfsTxnLock); #define LAZY_LOCK(flags) spin_lock_irqsave(&TxAnchor.LazyLock, flags) #define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags) -DECLARE_WAIT_QUEUE_HEAD(jfs_sync_thread_wait); -DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait); +static DECLARE_WAIT_QUEUE_HEAD(jfs_commit_thread_wait); static int jfs_commit_thread_waking; /* @@ -207,7 +207,7 @@ static lid_t txLockAlloc(void) if ((++TxAnchor.tlocksInUse > TxLockHWM) && (jfs_tlocks_low == 0)) { jfs_info("txLockAlloc tlocks low"); jfs_tlocks_low = 1; - wake_up(&jfs_sync_thread_wait); + wake_up_process(jfsSyncThread); } return lid; @@ -2743,10 +2743,6 @@ int jfs_lazycommit(void *arg) unsigned long flags; struct jfs_sb_info *sbi; - daemonize("jfsCommit"); - - complete(&jfsIOwait); - do { LAZY_LOCK(flags); jfs_commit_thread_waking = 0; /* OK to wake another thread */ @@ -2806,13 +2802,13 @@ int jfs_lazycommit(void *arg) current->state = TASK_RUNNING; remove_wait_queue(&jfs_commit_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); if (!list_empty(&TxAnchor.unlock_queue)) jfs_err("jfs_lazycommit being killed w/pending transactions!"); else jfs_info("jfs_lazycommit being killed\n"); - complete_and_exit(&jfsIOwait, 0); + return 0; } void txLazyUnlock(struct tblock * tblk) @@ -2876,10 +2872,10 @@ restart: */ TXN_UNLOCK(); tid = txBegin(ip->i_sb, COMMIT_INODE | COMMIT_FORCE); - down(&jfs_ip->commit_sem); + mutex_lock(&jfs_ip->commit_mutex); txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&jfs_ip->commit_sem); + mutex_unlock(&jfs_ip->commit_mutex); /* * Just to be safe. I don't know how * long we can run without blocking @@ -2932,10 +2928,6 @@ int jfs_sync(void *arg) int rc; tid_t tid; - daemonize("jfsSync"); - - complete(&jfsIOwait); - do { /* * write each inode on the anonymous inode list @@ -2952,7 +2944,7 @@ int jfs_sync(void *arg) * Inode is being freed */ list_del_init(&jfs_ip->anon_inode_list); - } else if (! down_trylock(&jfs_ip->commit_sem)) { + } else if (! !mutex_trylock(&jfs_ip->commit_mutex)) { /* * inode will be removed from anonymous list * when it is committed @@ -2961,7 +2953,7 @@ int jfs_sync(void *arg) tid = txBegin(ip->i_sb, COMMIT_INODE); rc = txCommit(tid, 1, &ip, 0); txEnd(tid); - up(&jfs_ip->commit_sem); + mutex_unlock(&jfs_ip->commit_mutex); iput(ip); /* @@ -2971,7 +2963,7 @@ int jfs_sync(void *arg) cond_resched(); TXN_LOCK(); } else { - /* We can't get the commit semaphore. It may + /* We can't get the commit mutex. It may * be held by a thread waiting for tlock's * so let's not block here. Save it to * put back on the anon_list. @@ -2996,19 +2988,15 @@ int jfs_sync(void *arg) TXN_UNLOCK(); refrigerator(); } else { - DECLARE_WAITQUEUE(wq, current); - - add_wait_queue(&jfs_sync_thread_wait, &wq); set_current_state(TASK_INTERRUPTIBLE); TXN_UNLOCK(); schedule(); current->state = TASK_RUNNING; - remove_wait_queue(&jfs_sync_thread_wait, &wq); } - } while (!jfs_stop_threads); + } while (!kthread_should_stop()); jfs_info("jfs_sync being killed"); - complete_and_exit(&jfsIOwait, 0); + return 0; } #if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG) diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 4abbe8604302..309cee575f7d 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -165,8 +165,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dip); if (rc) @@ -300,8 +300,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode) out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -384,8 +384,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); goto out2; } @@ -422,8 +422,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); /* * Truncating the directory index table is not guaranteed. It @@ -488,8 +488,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); iplist[0] = dip; iplist[1] = ip; @@ -503,8 +503,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if (rc == -EIO) txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); IWRITE_UNLOCK(ip); goto out1; } @@ -527,8 +527,8 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) if ((new_size = commitZeroLink(tid, ip)) < 0) { txAbort(tid, 1); /* Marks FS Dirty */ txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); IWRITE_UNLOCK(ip); rc = new_size; goto out1; @@ -556,13 +556,13 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(ip)->commit_mutex); new_size = xtTruncate_pmap(tid, ip, new_size); if (new_size < 0) { txAbort(tid, 1); /* Marks FS Dirty */ @@ -570,7 +570,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) } else rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); } if (ip->i_nlink == 0) @@ -805,8 +805,8 @@ static int jfs_link(struct dentry *old_dentry, tid = txBegin(ip->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); /* * scan parent directory for entry/freespace @@ -847,8 +847,8 @@ static int jfs_link(struct dentry *old_dentry, out: txEnd(tid); - up(&JFS_IP(dir)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dir)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); jfs_info("jfs_link: rc:%d", rc); return rc; @@ -916,8 +916,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, tid = txBegin(dip->i_sb, 0); - down(&JFS_IP(dip)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dip)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_security(tid, ip, dip); if (rc) @@ -1037,8 +1037,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(dip)->commit_sem); - up(&JFS_IP(ip)->commit_sem); + mutex_unlock(&JFS_IP(dip)->commit_mutex); + mutex_unlock(&JFS_IP(ip)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -1141,13 +1141,13 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, */ tid = txBegin(new_dir->i_sb, 0); - down(&JFS_IP(new_dir)->commit_sem); - down(&JFS_IP(old_ip)->commit_sem); + mutex_lock(&JFS_IP(new_dir)->commit_mutex); + mutex_lock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - down(&JFS_IP(old_dir)->commit_sem); + mutex_lock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) { - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); /* * Change existing directory entry to new inode number */ @@ -1160,10 +1160,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, if (S_ISDIR(new_ip->i_mode)) { new_ip->i_nlink--; if (new_ip->i_nlink) { - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); if (!S_ISDIR(old_ip->i_mode) && new_ip) IWRITE_UNLOCK(new_ip); jfs_error(new_ip->i_sb, @@ -1282,16 +1282,16 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, out4: txEnd(tid); - up(&JFS_IP(new_dir)->commit_sem); - up(&JFS_IP(old_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_dir)->commit_mutex); + mutex_unlock(&JFS_IP(old_ip)->commit_mutex); if (old_dir != new_dir) - up(&JFS_IP(old_dir)->commit_sem); + mutex_unlock(&JFS_IP(old_dir)->commit_mutex); if (new_ip) - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); while (new_size && (rc == 0)) { tid = txBegin(new_ip->i_sb, 0); - down(&JFS_IP(new_ip)->commit_sem); + mutex_lock(&JFS_IP(new_ip)->commit_mutex); new_size = xtTruncate_pmap(tid, new_ip, new_size); if (new_size < 0) { txAbort(tid, 1); @@ -1299,7 +1299,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC); txEnd(tid); - up(&JFS_IP(new_ip)->commit_sem); + mutex_unlock(&JFS_IP(new_ip)->commit_mutex); } if (new_ip && (new_ip->i_nlink == 0)) set_cflag(COMMIT_Nolink, new_ip); @@ -1361,8 +1361,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, tid = txBegin(dir->i_sb, 0); - down(&JFS_IP(dir)->commit_sem); - down(&JFS_IP(ip)->commit_sem); + mutex_lock(&JFS_IP(dir)->commit_mutex); + mutex_lock(&JFS_IP(ip)->commit_mutex); rc = jfs_init_acl(tid, ip, dir); if (rc) @@ -1407,8 +1407,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, out3: txEnd(tid); - up(&JFS_IP(ip)->commit_sem); - up(&JFS_IP(dir)->commit_sem); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + mutex_unlock(&JFS_IP(dir)->commit_mutex); if (rc) { free_ea_wmap(ip); ip->i_nlink = 0; @@ -1523,6 +1523,7 @@ struct file_operations jfs_dir_operations = { .read = generic_read_dir, .readdir = jfs_readdir, .fsync = jfs_fsync, + .ioctl = jfs_ioctl, }; static int jfs_ci_hash(struct dentry *dir, struct qstr *this) diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 8d31f1336431..18f69e6aa719 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -25,6 +25,7 @@ #include <linux/vfs.h> #include <linux/mount.h> #include <linux/moduleparam.h> +#include <linux/kthread.h> #include <linux/posix_acl.h> #include <asm/uaccess.h> #include <linux/seq_file.h> @@ -54,11 +55,9 @@ static int commit_threads = 0; module_param(commit_threads, int, 0); MODULE_PARM_DESC(commit_threads, "Number of commit threads"); -int jfs_stop_threads; -static pid_t jfsIOthread; -static pid_t jfsCommitThread[MAX_COMMIT_THREADS]; -static pid_t jfsSyncThread; -DECLARE_COMPLETION(jfsIOwait); +static struct task_struct *jfsCommitThread[MAX_COMMIT_THREADS]; +struct task_struct *jfsIOthread; +struct task_struct *jfsSyncThread; #ifdef CONFIG_JFS_DEBUG int jfsloglevel = JFS_LOGLEVEL_WARN; @@ -195,7 +194,7 @@ static void jfs_put_super(struct super_block *sb) enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask }; static match_table_t tokens = { @@ -209,6 +208,9 @@ static match_table_t tokens = { {Opt_ignore, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_grpquota, "grpquota"}, + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%u"}, {Opt_err, NULL} }; @@ -313,7 +315,29 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, "JFS: quota operations not supported\n"); break; #endif - + case Opt_uid: + { + char *uid = args[0].from; + sbi->uid = simple_strtoul(uid, &uid, 0); + break; + } + case Opt_gid: + { + char *gid = args[0].from; + sbi->gid = simple_strtoul(gid, &gid, 0); + break; + } + case Opt_umask: + { + char *umask = args[0].from; + sbi->umask = simple_strtoul(umask, &umask, 8); + if (sbi->umask & ~0777) { + printk(KERN_ERR + "JFS: Invalid value of umask\n"); + goto cleanup; + } + break; + } default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -396,12 +420,12 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) if (!new_valid_dev(sb->s_bdev->bd_dev)) return -EOVERFLOW; - sbi = kmalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOSPC; - memset(sbi, 0, sizeof (struct jfs_sb_info)); sb->s_fs_info = sbi; sbi->sb = sb; + sbi->uid = sbi->gid = sbi->umask = -1; /* initialize the mount flag and determine the default error handler */ flag = JFS_ERR_REMOUNT_RO; @@ -564,10 +588,14 @@ static int jfs_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct jfs_sb_info *sbi = JFS_SBI(vfs->mnt_sb); + if (sbi->uid != -1) + seq_printf(seq, ",uid=%d", sbi->uid); + if (sbi->gid != -1) + seq_printf(seq, ",gid=%d", sbi->gid); + if (sbi->umask != -1) + seq_printf(seq, ",umask=%03o", sbi->umask); if (sbi->flag & JFS_NOINTEGRITY) seq_puts(seq, ",nointegrity"); - else - seq_puts(seq, ",integrity"); #if defined(CONFIG_QUOTA) if (sbi->flag & JFS_USRQUOTA) @@ -617,7 +645,7 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) memset(jfs_ip, 0, sizeof(struct jfs_inode_info)); INIT_LIST_HEAD(&jfs_ip->anon_inode_list); init_rwsem(&jfs_ip->rdwrlock); - init_MUTEX(&jfs_ip->commit_sem); + mutex_init(&jfs_ip->commit_mutex); init_rwsem(&jfs_ip->xattr_sem); spin_lock_init(&jfs_ip->ag_lock); jfs_ip->active_ag = -1; @@ -661,12 +689,12 @@ static int __init init_jfs_fs(void) /* * I/O completion thread (endio) */ - jfsIOthread = kernel_thread(jfsIOWait, NULL, CLONE_KERNEL); - if (jfsIOthread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsIOthread); + jfsIOthread = kthread_run(jfsIOWait, NULL, "jfsIO"); + if (IS_ERR(jfsIOthread)) { + rc = PTR_ERR(jfsIOthread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto end_txmngr; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ if (commit_threads < 1) commit_threads = num_online_cpus(); @@ -674,24 +702,21 @@ static int __init init_jfs_fs(void) commit_threads = MAX_COMMIT_THREADS; for (i = 0; i < commit_threads; i++) { - jfsCommitThread[i] = kernel_thread(jfs_lazycommit, NULL, - CLONE_KERNEL); - if (jfsCommitThread[i] < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", - jfsCommitThread[i]); + jfsCommitThread[i] = kthread_run(jfs_lazycommit, NULL, "jfsCommit"); + if (IS_ERR(jfsCommitThread[i])) { + rc = PTR_ERR(jfsCommitThread[i]); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); commit_threads = i; goto kill_committask; } - /* Wait until thread starts */ - wait_for_completion(&jfsIOwait); } - jfsSyncThread = kernel_thread(jfs_sync, NULL, CLONE_KERNEL); - if (jfsSyncThread < 0) { - jfs_err("init_jfs_fs: fork failed w/rc = %d", jfsSyncThread); + jfsSyncThread = kthread_run(jfs_sync, NULL, "jfsSync"); + if (IS_ERR(jfsSyncThread)) { + rc = PTR_ERR(jfsSyncThread); + jfs_err("init_jfs_fs: fork failed w/rc = %d", rc); goto kill_committask; } - wait_for_completion(&jfsIOwait); /* Wait until thread starts */ #ifdef PROC_FS_JFS jfs_proc_init(); @@ -700,13 +725,9 @@ static int __init init_jfs_fs(void) return register_filesystem(&jfs_fs_type); kill_committask: - jfs_stop_threads = 1; - wake_up_all(&jfs_commit_thread_wait); for (i = 0; i < commit_threads; i++) - wait_for_completion(&jfsIOwait); - - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait for thread exit */ + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsIOthread); end_txmngr: txExit(); free_metapage: @@ -722,16 +743,13 @@ static void __exit exit_jfs_fs(void) jfs_info("exit_jfs_fs called"); - jfs_stop_threads = 1; txExit(); metapage_exit(); - wake_up(&jfs_IO_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until IO thread exits */ - wake_up_all(&jfs_commit_thread_wait); + + kthread_stop(jfsIOthread); for (i = 0; i < commit_threads; i++) - wait_for_completion(&jfsIOwait); - wake_up(&jfs_sync_thread_wait); - wait_for_completion(&jfsIOwait); /* Wait until Sync thread exits */ + kthread_stop(jfsCommitThread[i]); + kthread_stop(jfsSyncThread); #ifdef PROC_FS_JFS jfs_proc_clean(); #endif diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index f23048f9471f..9bc5b7c055ce 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -934,13 +934,13 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, } tid = txBegin(inode->i_sb, 0); - down(&ji->commit_sem); + mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len, flags); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&ji->commit_sem); + mutex_unlock(&ji->commit_mutex); return rc; } @@ -1093,12 +1093,12 @@ int jfs_removexattr(struct dentry *dentry, const char *name) return rc; tid = txBegin(inode->i_sb, 0); - down(&ji->commit_sem); + mutex_lock(&ji->commit_mutex); rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE); if (!rc) rc = txCommit(tid, 1, &inode, 0); txEnd(tid); - up(&ji->commit_sem); + mutex_unlock(&ji->commit_mutex); return rc; } diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 220058d8616d..970b6a6aa337 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -662,12 +662,18 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) * reclaimed while we're stuck in the unlock call. */ fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; + /* + * Note: the server is supposed to either grant us the unlock + * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either + * case, we want to unlock. + */ + do_vfs_lock(fl); + if (req->a_flags & RPC_TASK_ASYNC) { status = nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); /* Hrmf... Do the unlock early since locks_remove_posix() * really expects us to free the lock synchronously */ - do_vfs_lock(fl); if (status < 0) { nlmclnt_release_lockargs(req); kfree(req); @@ -680,7 +686,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) return status; - do_vfs_lock(fl); if (resp->status == NLM_LCK_GRANTED) return 0; diff --git a/fs/namespace.c b/fs/namespace.c index 058a44865beb..39c81a8d6316 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1338,7 +1338,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); if (!new_ns) - goto out; + return NULL; atomic_set(&new_ns->count, 1); INIT_LIST_HEAD(&new_ns->list); @@ -1352,7 +1352,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) if (!new_ns->root) { up_write(&namespace_sem); kfree(new_ns); - goto out; + return NULL; } spin_lock(&vfsmount_lock); list_add_tail(&new_ns->list, &new_ns->root->mnt_list); @@ -1393,7 +1393,6 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) if (altrootmnt) mntput(altrootmnt); -out: return new_ns; } diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 04ab2fc360e7..4e9b3a1b36c5 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -57,6 +57,7 @@ #define NFSDBG_FACILITY NFSDBG_VFS #define MAX_DIRECTIO_SIZE (4096UL << PAGE_SHIFT) +static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty); static kmem_cache_t *nfs_direct_cachep; /* @@ -107,6 +108,15 @@ nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, page_count, (rw == READ), 0, *pages, NULL); up_read(¤t->mm->mmap_sem); + /* + * If we got fewer pages than expected from get_user_pages(), + * the user buffer runs off the end of a mapping; return EFAULT. + */ + if (result >= 0 && result < page_count) { + nfs_free_user_pages(*pages, result, 0); + *pages = NULL; + result = -EFAULT; + } } return result; } diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 984ca3454d04..f8c0066e02e1 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1430,7 +1430,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, if (status == 0) status = nfs4_do_fsinfo(server, fhandle, info); out: - return status; + return nfs4_map_errors(status); } static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 0d4cf9486068..1c72c7f85ddc 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -98,10 +98,8 @@ asmlinkage sys_nfsservctl(int cmd, struct nfsctl_arg __user *arg, void __user *r if (copy_from_user(&version, &arg->ca_version, sizeof(int))) return -EFAULT; - if (version != NFSCTL_VERSION) { - printk(KERN_WARNING "nfsd: incompatible version in syscall.\n"); + if (version != NFSCTL_VERSION) return -EINVAL; - } if (cmd < 0 || cmd >= sizeof(map)/sizeof(map[0]) || !map[cmd].name) return -EINVAL; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 49bd219275db..9ee956864445 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -50,6 +50,32 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, return sd; } +/** + * + * Return -EEXIST if there is already a sysfs element with the same name for + * the same parent. + * + * called with parent inode's i_mutex held + */ +int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, + const unsigned char *new) +{ + struct sysfs_dirent * sd; + + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + if (sd->s_element) { + const unsigned char *existing = sysfs_get_name(sd); + if (strcmp(existing, new)) + continue; + else + return -EEXIST; + } + } + + return 0; +} + + int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, void * element, umode_t mode, int type) { @@ -102,7 +128,11 @@ static int create_dir(struct kobject * k, struct dentry * p, mutex_lock(&p->d_inode->i_mutex); *d = lookup_one_len(n, p, strlen(n)); if (!IS_ERR(*d)) { - error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, SYSFS_DIR); + if (sysfs_dirent_exist(p->d_fsdata, n)) + error = -EEXIST; + else + error = sysfs_make_dirent(p->d_fsdata, *d, k, mode, + SYSFS_DIR); if (!error) { error = sysfs_create(*d, mode, init_dir); if (!error) { @@ -302,6 +332,7 @@ void sysfs_remove_dir(struct kobject * kobj) * Drop reference from dget() on entrance. */ dput(dentry); + kobj->dentry = NULL; } int sysfs_rename_dir(struct kobject * kobj, const char *new_name) @@ -479,7 +510,3 @@ struct file_operations sysfs_dir_operations = { .read = generic_read_dir, .readdir = sysfs_readdir, }; - -EXPORT_SYMBOL_GPL(sysfs_create_dir); -EXPORT_SYMBOL_GPL(sysfs_remove_dir); -EXPORT_SYMBOL_GPL(sysfs_rename_dir); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index d0e3d8495165..5e83e7246788 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -301,9 +301,8 @@ static int check_perm(struct inode * inode, struct file * file) /* No error? Great, allocate a buffer for the file, and store it * it in file->private_data for easy access. */ - buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL); + buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); if (buffer) { - memset(buffer,0,sizeof(struct sysfs_buffer)); init_MUTEX(&buffer->sem); buffer->needs_read_fill = 1; buffer->ops = ops; @@ -362,10 +361,12 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type) { struct sysfs_dirent * parent_sd = dir->d_fsdata; umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG; - int error = 0; + int error = -EEXIST; mutex_lock(&dir->d_inode->i_mutex); - error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); + if (!sysfs_dirent_exist(parent_sd, attr->name)) + error = sysfs_make_dirent(parent_sd, NULL, (void *)attr, + mode, type); mutex_unlock(&dir->d_inode->i_mutex); return error; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 689f7bcfaf30..4c29ac41ac3e 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -54,11 +54,10 @@ int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) if (!sd_iattr) { /* setting attributes for the first time, allocate now */ - sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL); + sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL); if (!sd_iattr) return -ENOMEM; /* assign default attributes */ - memset(sd_iattr, 0, sizeof(struct iattr)); sd_iattr->ia_mode = sd->s_mode; sd_iattr->ia_uid = 0; sd_iattr->ia_gid = 0; @@ -227,12 +226,16 @@ void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) void sysfs_hash_and_remove(struct dentry * dir, const char * name) { struct sysfs_dirent * sd; - struct sysfs_dirent * parent_sd = dir->d_fsdata; + struct sysfs_dirent * parent_sd; + + if (!dir) + return; if (dir->d_inode == NULL) /* no inode means this hasn't been made visible yet */ return; + parent_sd = dir->d_fsdata; mutex_lock(&dir->d_inode->i_mutex); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index e38d6338a20d..d2eac3ceed5f 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -66,6 +66,7 @@ static int sysfs_add_link(struct dentry * parent, const char * name, struct kobj if (!error) return 0; + kobject_put(target); kfree(sl->link_name); exit2: kfree(sl); @@ -82,12 +83,13 @@ exit1: int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) { struct dentry * dentry = kobj->dentry; - int error = 0; + int error = -EEXIST; BUG_ON(!kobj || !kobj->dentry || !name); mutex_lock(&dentry->d_inode->i_mutex); - error = sysfs_add_link(dentry, name, target); + if (!sysfs_dirent_exist(dentry->d_fsdata, name)) + error = sysfs_add_link(dentry, name, target); mutex_unlock(&dentry->d_inode->i_mutex); return error; } diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 3f8953e0e5d0..cf11d5b789d9 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -5,6 +5,7 @@ extern kmem_cache_t *sysfs_dir_cachep; extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); +extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *); extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *, umode_t, int); |