forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (34 commits) nfsd race fixes: jfs nfsd race fixes: reiserfs nfsd race fixes: ext4 nfsd race fixes: ext3 nfsd race fixes: ext2 nfsd/create race fixes, infrastructure filesystem notification: create fs/notify to contain all fs notification fs/block_dev.c: __read_mostly improvement and sb_is_blkdev_sb utilization kill ->dir_notify() filp_cachep can be static in fs/file_table.c fix f_count description in Documentation/filesystems/files.txt make INIT_FS use the __RW_LOCK_UNLOCKED initialization take init_fs to saner place kill vfs_permission pass a struct path * to may_open kill walk_init_root remove incorrect comment in inode_permission expand some comments (d_path / seq_path) correct wrong function name of d_put in kernel document and source comment fix switch_names() breakage in short-to-short case ...
This commit is contained in:
commit
b58602a4ba
@ -394,7 +394,6 @@ prototypes:
|
||||
unsigned long (*get_unmapped_area)(struct file *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned long);
|
||||
int (*check_flags)(int);
|
||||
int (*dir_notify)(struct file *, unsigned long);
|
||||
};
|
||||
|
||||
locking rules:
|
||||
@ -424,7 +423,6 @@ sendfile: no
|
||||
sendpage: no
|
||||
get_unmapped_area: no
|
||||
check_flags: no
|
||||
dir_notify: no
|
||||
|
||||
->llseek() locking has moved from llseek to the individual llseek
|
||||
implementations. If your fs is not using generic_file_llseek, you
|
||||
|
@ -76,13 +76,13 @@ the fdtable structure -
|
||||
5. Handling of the file structures is special. Since the look-up
|
||||
of the fd (fget()/fget_light()) are lock-free, it is possible
|
||||
that look-up may race with the last put() operation on the
|
||||
file structure. This is avoided using atomic_inc_not_zero()
|
||||
file structure. This is avoided using atomic_long_inc_not_zero()
|
||||
on ->f_count :
|
||||
|
||||
rcu_read_lock();
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
if (atomic_inc_not_zero(&file->f_count))
|
||||
if (atomic_long_inc_not_zero(&file->f_count))
|
||||
*fput_needed = 1;
|
||||
else
|
||||
/* Didn't get the reference, someone's freed */
|
||||
@ -92,7 +92,7 @@ the fdtable structure -
|
||||
....
|
||||
return file;
|
||||
|
||||
atomic_inc_not_zero() detects if refcounts is already zero or
|
||||
atomic_long_inc_not_zero() detects if refcounts is already zero or
|
||||
goes to zero during increment. If it does, we fail
|
||||
fget()/fget_light().
|
||||
|
||||
|
@ -733,7 +733,6 @@ struct file_operations {
|
||||
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
|
||||
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
|
||||
int (*check_flags)(int);
|
||||
int (*dir_notify)(struct file *filp, unsigned long arg);
|
||||
int (*flock) (struct file *, int, struct file_lock *);
|
||||
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
|
||||
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
|
||||
@ -800,8 +799,6 @@ otherwise noted.
|
||||
|
||||
check_flags: called by the fcntl(2) system call for F_SETFL command
|
||||
|
||||
dir_notify: called by the fcntl(2) system call for F_NOTIFY command
|
||||
|
||||
flock: called by the flock(2) system call
|
||||
|
||||
splice_write: called by the VFS to splice data from a pipe to a file. This
|
||||
@ -931,7 +928,7 @@ manipulate dentries:
|
||||
d_lookup: look up a dentry given its parent and path name component
|
||||
It looks up the child of that given name from the dcache
|
||||
hash table. If it is found, the reference count is incremented
|
||||
and the dentry is returned. The caller must use d_put()
|
||||
and the dentry is returned. The caller must use dput()
|
||||
to free the dentry when it finishes using it.
|
||||
|
||||
For further information on dentry locking, please refer to the document
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include <linux/mqueue.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
|
||||
|
@ -37,7 +37,6 @@
|
||||
* setup.
|
||||
*/
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -40,7 +40,6 @@
|
||||
* alignment requirements and potentially different initial
|
||||
* setup.
|
||||
*/
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <linux/mqueue.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -297,7 +297,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
|
||||
{
|
||||
unsigned long cookie;
|
||||
|
||||
if (path->dentry->d_cookie)
|
||||
if (path->dentry->d_flags & DCACHE_COOKIE)
|
||||
return (unsigned long)path->dentry;
|
||||
get_dcookie(path, &cookie);
|
||||
return cookie;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct pt_regs fake_swapper_regs;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "linux/mqueue.h"
|
||||
#include "asm/uaccess.h"
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static struct fs_struct init_fs = INIT_FS;
|
||||
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
|
||||
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
|
||||
struct mm_struct init_mm = INIT_MM(init_mm);
|
||||
|
@ -200,7 +200,7 @@ static inline unsigned long fast_get_dcookie(struct path *path)
|
||||
{
|
||||
unsigned long cookie;
|
||||
|
||||
if (path->dentry->d_cookie)
|
||||
if (path->dentry->d_flags & DCACHE_COOKIE)
|
||||
return (unsigned long)path->dentry;
|
||||
get_dcookie(path, &cookie);
|
||||
return cookie;
|
||||
|
39
fs/Kconfig
39
fs/Kconfig
@ -270,44 +270,7 @@ config OCFS2_COMPAT_JBD
|
||||
|
||||
endif # BLOCK
|
||||
|
||||
config DNOTIFY
|
||||
bool "Dnotify support"
|
||||
default y
|
||||
help
|
||||
Dnotify is a directory-based per-fd file change notification system
|
||||
that uses signals to communicate events to user-space. There exist
|
||||
superior alternatives, but some applications may still rely on
|
||||
dnotify.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config INOTIFY
|
||||
bool "Inotify file change notification support"
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable inotify support. Inotify is a file change
|
||||
notification system and a replacement for dnotify. Inotify fixes
|
||||
numerous shortcomings in dnotify and introduces several new features
|
||||
including multiple file events, one-shot support, and unmount
|
||||
notification.
|
||||
|
||||
For more information, see <file:Documentation/filesystems/inotify.txt>
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config INOTIFY_USER
|
||||
bool "Inotify support for userspace"
|
||||
depends on INOTIFY
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable inotify support for userspace, including the
|
||||
associated system calls. Inotify allows monitoring of both files and
|
||||
directories via a single open fd. Events are read from the file
|
||||
descriptor, which is also select()- and poll()-able.
|
||||
|
||||
For more information, see <file:Documentation/filesystems/inotify.txt>
|
||||
|
||||
If unsure, say Y.
|
||||
source "fs/notify/Kconfig"
|
||||
|
||||
config QUOTA
|
||||
bool "Quota support"
|
||||
|
@ -20,8 +20,7 @@ obj-y += no-block.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
|
||||
obj-$(CONFIG_INOTIFY) += inotify.o
|
||||
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
|
||||
obj-y += notify/
|
||||
obj-$(CONFIG_EPOLL) += eventpoll.o
|
||||
obj-$(CONFIG_ANON_INODES) += anon_inodes.o
|
||||
obj-$(CONFIG_SIGNALFD) += signalfd.o
|
||||
@ -57,8 +56,6 @@ obj-$(CONFIG_QFMT_V1) += quota_v1.o
|
||||
obj-$(CONFIG_QFMT_V2) += quota_v2.o
|
||||
obj-$(CONFIG_QUOTACTL) += quota.o
|
||||
|
||||
obj-$(CONFIG_DNOTIFY) += dnotify.o
|
||||
|
||||
obj-$(CONFIG_PROC_FS) += proc/
|
||||
obj-y += partitions/
|
||||
obj-$(CONFIG_SYSFS) += sysfs/
|
||||
|
@ -132,11 +132,6 @@ static int bad_file_check_flags(int flags)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_file_dir_notify(struct file *file, unsigned long arg)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bad_file_flock(struct file *filp, int cmd, struct file_lock *fl)
|
||||
{
|
||||
return -EIO;
|
||||
@ -179,7 +174,6 @@ static const struct file_operations bad_file_ops =
|
||||
.sendpage = bad_file_sendpage,
|
||||
.get_unmapped_area = bad_file_get_unmapped_area,
|
||||
.check_flags = bad_file_check_flags,
|
||||
.dir_notify = bad_file_dir_notify,
|
||||
.flock = bad_file_flock,
|
||||
.splice_write = bad_file_splice_write,
|
||||
.splice_read = bad_file_splice_read,
|
||||
|
@ -378,7 +378,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_size = 0;
|
||||
inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
|
||||
strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
|
||||
BEFS_SYMLINK_LEN);
|
||||
BEFS_SYMLINK_LEN - 1);
|
||||
befs_ino->i_data.symlink[BEFS_SYMLINK_LEN - 1] = '\0';
|
||||
} else {
|
||||
int num_blks;
|
||||
|
||||
@ -477,6 +478,8 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
kfree(link);
|
||||
befs_error(sb, "Failed to read entire long symlink");
|
||||
link = ERR_PTR(-EIO);
|
||||
} else {
|
||||
link[len - 1] = '\0';
|
||||
}
|
||||
} else {
|
||||
link = befs_ino->i_data.symlink;
|
||||
|
@ -326,12 +326,13 @@ static struct file_system_type bd_type = {
|
||||
.kill_sb = kill_anon_super,
|
||||
};
|
||||
|
||||
static struct vfsmount *bd_mnt __read_mostly;
|
||||
struct super_block *blockdev_superblock;
|
||||
struct super_block *blockdev_superblock __read_mostly;
|
||||
|
||||
void __init bdev_cache_init(void)
|
||||
{
|
||||
int err;
|
||||
struct vfsmount *bd_mnt;
|
||||
|
||||
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
|
||||
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
|
||||
SLAB_MEM_SPREAD|SLAB_PANIC),
|
||||
@ -373,7 +374,7 @@ struct block_device *bdget(dev_t dev)
|
||||
struct block_device *bdev;
|
||||
struct inode *inode;
|
||||
|
||||
inode = iget5_locked(bd_mnt->mnt_sb, hash(dev),
|
||||
inode = iget5_locked(blockdev_superblock, hash(dev),
|
||||
bdev_test, bdev_set, &dev);
|
||||
|
||||
if (!inode)
|
||||
@ -463,7 +464,7 @@ void bd_forget(struct inode *inode)
|
||||
|
||||
spin_lock(&bdev_lock);
|
||||
if (inode->i_bdev) {
|
||||
if (inode->i_sb != blockdev_superblock)
|
||||
if (!sb_is_blkdev_sb(inode->i_sb))
|
||||
bdev = inode->i_bdev;
|
||||
__bd_forget(inode);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ obj-$(CONFIG_CIFS) += cifs.o
|
||||
|
||||
cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
|
||||
link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \
|
||||
md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o \
|
||||
md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
|
||||
readdir.o ioctl.o sess.o export.o cifsacl.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||
|
@ -747,7 +747,6 @@ const struct file_operations cifs_file_ops = {
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.dir_notify = cifs_dir_notify,
|
||||
.setlease = cifs_setlease,
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
};
|
||||
@ -768,7 +767,6 @@ const struct file_operations cifs_file_direct_ops = {
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
.llseek = cifs_llseek,
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.dir_notify = cifs_dir_notify,
|
||||
.setlease = cifs_setlease,
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
};
|
||||
@ -789,7 +787,6 @@ const struct file_operations cifs_file_nobrl_ops = {
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.dir_notify = cifs_dir_notify,
|
||||
.setlease = cifs_setlease,
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
};
|
||||
@ -809,7 +806,6 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
.llseek = cifs_llseek,
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.dir_notify = cifs_dir_notify,
|
||||
.setlease = cifs_setlease,
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
};
|
||||
@ -818,9 +814,6 @@ const struct file_operations cifs_dir_ops = {
|
||||
.readdir = cifs_readdir,
|
||||
.release = cifs_closedir,
|
||||
.read = generic_read_dir,
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.dir_notify = cifs_dir_notify,
|
||||
#endif /* CONFIG_CIFS_EXPERIMENTAL */
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
@ -76,7 +76,6 @@ extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
|
||||
extern const struct file_operations cifs_dir_ops;
|
||||
extern int cifs_dir_open(struct inode *inode, struct file *file);
|
||||
extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
|
||||
extern int cifs_dir_notify(struct file *, unsigned long arg);
|
||||
|
||||
/* Functions related to dir entries */
|
||||
extern struct dentry_operations cifs_dentry_ops;
|
||||
|
118
fs/cifs/fcntl.c
118
fs/cifs/fcntl.c
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* fs/cifs/fcntl.c
|
||||
*
|
||||
* vfs operations that deal with the file control API
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2003,2004
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
* by the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_unicode.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
|
||||
static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
|
||||
{
|
||||
__u32 cifs_ntfy_flags = 0;
|
||||
|
||||
/* No way on Linux VFS to ask to monitor xattr
|
||||
changes (and no stream support either */
|
||||
if (fcntl_notify_flags & DN_ACCESS)
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
|
||||
if (fcntl_notify_flags & DN_MODIFY) {
|
||||
/* What does this mean on directories? */
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE |
|
||||
FILE_NOTIFY_CHANGE_SIZE;
|
||||
}
|
||||
if (fcntl_notify_flags & DN_CREATE) {
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_CREATION |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE;
|
||||
}
|
||||
if (fcntl_notify_flags & DN_DELETE)
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_LAST_WRITE;
|
||||
if (fcntl_notify_flags & DN_RENAME) {
|
||||
/* BB review this - checking various server behaviors */
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME;
|
||||
}
|
||||
if (fcntl_notify_flags & DN_ATTRIB) {
|
||||
cifs_ntfy_flags |= FILE_NOTIFY_CHANGE_SECURITY |
|
||||
FILE_NOTIFY_CHANGE_ATTRIBUTES;
|
||||
}
|
||||
/* if (fcntl_notify_flags & DN_MULTISHOT) {
|
||||
cifs_ntfy_flags |= ;
|
||||
} */ /* BB fixme - not sure how to handle this with CIFS yet */
|
||||
|
||||
return cifs_ntfy_flags;
|
||||
}
|
||||
|
||||
int cifs_dir_notify(struct file *file, unsigned long arg)
|
||||
{
|
||||
int xid;
|
||||
int rc = -EINVAL;
|
||||
int oplock = 0;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
char *full_path = NULL;
|
||||
__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
|
||||
__u16 netfid;
|
||||
|
||||
if (experimEnabled == 0)
|
||||
return 0;
|
||||
|
||||
xid = GetXid();
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
full_path = build_path_from_dentry(file->f_path.dentry);
|
||||
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
cFYI(1, ("dir notify on file %s Arg 0x%lx", full_path, arg));
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
|
||||
GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
|
||||
&netfid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
/* BB fixme - add this handle to a notify handle list */
|
||||
if (rc) {
|
||||
cFYI(1, ("Could not open directory for notify"));
|
||||
} else {
|
||||
filter = convert_to_cifs_notify_flags(arg);
|
||||
if (filter != 0) {
|
||||
rc = CIFSSMBNotify(xid, pTcon,
|
||||
0 /* no subdirs */, netfid,
|
||||
filter, file, arg & DN_MULTISHOT,
|
||||
cifs_sb->local_nls);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
/* BB add code to close file eventually (at unmount
|
||||
it would close automatically but may be a way
|
||||
to do it easily when inode freed or when
|
||||
notify info is cleared/changed */
|
||||
cFYI(1, ("notify rc %d", rc));
|
||||
}
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
25
fs/dcache.c
25
fs/dcache.c
@ -34,7 +34,6 @@
|
||||
#include <linux/bootmem.h>
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
int sysctl_vfs_cache_pressure __read_mostly = 100;
|
||||
EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
|
||||
|
||||
@ -948,9 +947,6 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
|
||||
dentry->d_op = NULL;
|
||||
dentry->d_fsdata = NULL;
|
||||
dentry->d_mounted = 0;
|
||||
#ifdef CONFIG_PROFILING
|
||||
dentry->d_cookie = NULL;
|
||||
#endif
|
||||
INIT_HLIST_NODE(&dentry->d_hash);
|
||||
INIT_LIST_HEAD(&dentry->d_lru);
|
||||
INIT_LIST_HEAD(&dentry->d_subdirs);
|
||||
@ -1336,7 +1332,7 @@ err_out:
|
||||
*
|
||||
* Searches the children of the parent dentry for the name in question. If
|
||||
* the dentry is found its reference count is incremented and the dentry
|
||||
* is returned. The caller must use d_put to free the entry when it has
|
||||
* is returned. The caller must use dput to free the entry when it has
|
||||
* finished using it. %NULL is returned on failure.
|
||||
*
|
||||
* __d_lookup is dcache_lock free. The hash list is protected using RCU.
|
||||
@ -1620,8 +1616,11 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
|
||||
*/
|
||||
memcpy(dentry->d_iname, target->d_name.name,
|
||||
target->d_name.len + 1);
|
||||
dentry->d_name.len = target->d_name.len;
|
||||
return;
|
||||
}
|
||||
}
|
||||
do_switch(dentry->d_name.len, target->d_name.len);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1681,7 +1680,6 @@ already_unhashed:
|
||||
|
||||
/* Switch the names.. */
|
||||
switch_names(dentry, target);
|
||||
do_switch(dentry->d_name.len, target->d_name.len);
|
||||
do_switch(dentry->d_name.hash, target->d_name.hash);
|
||||
|
||||
/* ... and switch the parents */
|
||||
@ -1791,7 +1789,6 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
|
||||
struct dentry *dparent, *aparent;
|
||||
|
||||
switch_names(dentry, anon);
|
||||
do_switch(dentry->d_name.len, anon->d_name.len);
|
||||
do_switch(dentry->d_name.hash, anon->d_name.hash);
|
||||
|
||||
dparent = dentry->d_parent;
|
||||
@ -1911,7 +1908,8 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
|
||||
* Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
* the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
*
|
||||
* Returns the buffer or an error code if the path was too long.
|
||||
* Returns a pointer into the buffer or an error code if the
|
||||
* path was too long.
|
||||
*
|
||||
* "buflen" should be positive. Caller holds the dcache_lock.
|
||||
*
|
||||
@ -1987,7 +1985,10 @@ Elong:
|
||||
* Convert a dentry into an ASCII path name. If the entry has been deleted
|
||||
* the string " (deleted)" is appended. Note that this is ambiguous.
|
||||
*
|
||||
* Returns the buffer or an error code if the path was too long.
|
||||
* Returns a pointer into the buffer or an error code if the path was
|
||||
* too long. Note: Callers should use the returned pointer, not the passed
|
||||
* in buffer, to use the name! The implementation often starts at an offset
|
||||
* into the buffer, and may leave 0 bytes at the start.
|
||||
*
|
||||
* "buflen" should be positive.
|
||||
*/
|
||||
@ -2313,9 +2314,6 @@ static void __init dcache_init(void)
|
||||
/* SLAB cache for __getname() consumers */
|
||||
struct kmem_cache *names_cachep __read_mostly;
|
||||
|
||||
/* SLAB cache for file structures */
|
||||
struct kmem_cache *filp_cachep __read_mostly;
|
||||
|
||||
EXPORT_SYMBOL(d_genocide);
|
||||
|
||||
void __init vfs_caches_init_early(void)
|
||||
@ -2337,9 +2335,6 @@ void __init vfs_caches_init(unsigned long mempages)
|
||||
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
|
||||
|
||||
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
|
||||
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
|
||||
|
||||
dcache_init();
|
||||
inode_init();
|
||||
files_init(mempages);
|
||||
|
@ -93,10 +93,15 @@ static struct dcookie_struct *alloc_dcookie(struct path *path)
|
||||
{
|
||||
struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache,
|
||||
GFP_KERNEL);
|
||||
struct dentry *d;
|
||||
if (!dcs)
|
||||
return NULL;
|
||||
|
||||
path->dentry->d_cookie = dcs;
|
||||
d = path->dentry;
|
||||
spin_lock(&d->d_lock);
|
||||
d->d_flags |= DCACHE_COOKIE;
|
||||
spin_unlock(&d->d_lock);
|
||||
|
||||
dcs->path = *path;
|
||||
path_get(path);
|
||||
hash_dcookie(dcs);
|
||||
@ -119,15 +124,15 @@ int get_dcookie(struct path *path, unsigned long *cookie)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dcs = path->dentry->d_cookie;
|
||||
|
||||
if (!dcs)
|
||||
if (path->dentry->d_flags & DCACHE_COOKIE) {
|
||||
dcs = find_dcookie((unsigned long)path->dentry);
|
||||
} else {
|
||||
dcs = alloc_dcookie(path);
|
||||
|
||||
if (!dcs) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
*cookie = dcookie_value(dcs);
|
||||
|
||||
@ -251,7 +256,12 @@ out_kmem:
|
||||
|
||||
static void free_dcookie(struct dcookie_struct * dcs)
|
||||
{
|
||||
dcs->path.dentry->d_cookie = NULL;
|
||||
struct dentry *d = dcs->path.dentry;
|
||||
|
||||
spin_lock(&d->d_lock);
|
||||
d->d_flags &= ~DCACHE_COOKIE;
|
||||
spin_unlock(&d->d_lock);
|
||||
|
||||
path_put(&dcs->path);
|
||||
kmem_cache_free(dcookie_cache, dcs);
|
||||
}
|
||||
|
@ -673,10 +673,11 @@ static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
|
||||
"dentry->d_name.name = [%s]\n", dentry->d_name.name);
|
||||
rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
|
||||
buf[rc] = '\0';
|
||||
set_fs(old_fs);
|
||||
if (rc < 0)
|
||||
goto out_free;
|
||||
else
|
||||
buf[rc] = '\0';
|
||||
rc = 0;
|
||||
nd_set_link(nd, buf);
|
||||
goto out;
|
||||
|
@ -127,7 +127,8 @@ asmlinkage long sys_uselib(const char __user * library)
|
||||
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
|
||||
goto exit;
|
||||
|
||||
error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN);
|
||||
error = inode_permission(nd.path.dentry->d_inode,
|
||||
MAY_READ | MAY_EXEC | MAY_OPEN);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
@ -680,7 +681,7 @@ struct file *open_exec(const char *name)
|
||||
if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
|
||||
goto out_path_put;
|
||||
|
||||
err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN);
|
||||
err = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_OPEN);
|
||||
if (err)
|
||||
goto out_path_put;
|
||||
|
||||
|
@ -585,7 +585,10 @@ got:
|
||||
spin_lock(&sbi->s_next_gen_lock);
|
||||
inode->i_generation = sbi->s_next_generation++;
|
||||
spin_unlock(&sbi->s_next_gen_lock);
|
||||
insert_inode_hash(inode);
|
||||
if (insert_inode_locked(inode) < 0) {
|
||||
err = -EINVAL;
|
||||
goto fail_drop;
|
||||
}
|
||||
|
||||
if (DQUOT_ALLOC_INODE(inode)) {
|
||||
err = -EDQUOT;
|
||||
@ -612,6 +615,7 @@ fail_drop:
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
inode->i_nlink = 0;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return ERR_PTR(err);
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/namei.h>
|
||||
#include "ext2.h"
|
||||
#include "acl.h"
|
||||
#include "xip.h"
|
||||
@ -1286,9 +1287,11 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
|
||||
else
|
||||
inode->i_mapping->a_ops = &ext2_aops;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (ext2_inode_is_fast_symlink(inode))
|
||||
if (ext2_inode_is_fast_symlink(inode)) {
|
||||
inode->i_op = &ext2_fast_symlink_inode_operations;
|
||||
else {
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
} else {
|
||||
inode->i_op = &ext2_symlink_inode_operations;
|
||||
if (test_opt(inode->i_sb, NOBH))
|
||||
inode->i_mapping->a_ops = &ext2_nobh_aops;
|
||||
|
@ -41,9 +41,11 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
|
||||
int err = ext2_add_link(dentry, inode);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
return 0;
|
||||
}
|
||||
inode_dec_link_count(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
@ -170,6 +172,7 @@ out:
|
||||
|
||||
out_fail:
|
||||
inode_dec_link_count(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput (inode);
|
||||
goto out;
|
||||
}
|
||||
@ -178,6 +181,7 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
int err;
|
||||
|
||||
if (inode->i_nlink >= EXT2_LINK_MAX)
|
||||
return -EMLINK;
|
||||
@ -186,7 +190,14 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir,
|
||||
inode_inc_link_count(inode);
|
||||
atomic_inc(&inode->i_count);
|
||||
|
||||
return ext2_add_nondir(dentry, inode);
|
||||
err = ext2_add_link(dentry, inode);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
}
|
||||
inode_dec_link_count(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
|
||||
@ -222,12 +233,14 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
|
||||
goto out_fail;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_fail:
|
||||
inode_dec_link_count(inode);
|
||||
inode_dec_link_count(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
out_dir:
|
||||
inode_dec_link_count(dir);
|
||||
|
@ -579,7 +579,10 @@ got:
|
||||
ext3_set_inode_flags(inode);
|
||||
if (IS_DIRSYNC(inode))
|
||||
handle->h_sync = 1;
|
||||
insert_inode_hash(inode);
|
||||
if (insert_inode_locked(inode) < 0) {
|
||||
err = -EINVAL;
|
||||
goto fail_drop;
|
||||
}
|
||||
spin_lock(&sbi->s_next_gen_lock);
|
||||
inode->i_generation = sbi->s_next_generation++;
|
||||
spin_unlock(&sbi->s_next_gen_lock);
|
||||
@ -627,6 +630,7 @@ fail_drop:
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
inode->i_nlink = 0;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
brelse(bitmap_bh);
|
||||
return ERR_PTR(err);
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/namei.h>
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
|
||||
@ -2817,9 +2818,11 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_op = &ext3_dir_inode_operations;
|
||||
inode->i_fop = &ext3_dir_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (ext3_inode_is_fast_symlink(inode))
|
||||
if (ext3_inode_is_fast_symlink(inode)) {
|
||||
inode->i_op = &ext3_fast_symlink_inode_operations;
|
||||
else {
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
} else {
|
||||
inode->i_op = &ext3_symlink_inode_operations;
|
||||
ext3_set_aops(inode);
|
||||
}
|
||||
|
@ -1652,9 +1652,11 @@ static int ext3_add_nondir(handle_t *handle,
|
||||
if (!err) {
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
return 0;
|
||||
}
|
||||
drop_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
@ -1765,6 +1767,7 @@ retry:
|
||||
dir_block = ext3_bread (handle, inode, 0, 1, &err);
|
||||
if (!dir_block) {
|
||||
drop_nlink(inode); /* is this nlink == 0? */
|
||||
unlock_new_inode(inode);
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
iput (inode);
|
||||
goto out_stop;
|
||||
@ -1792,6 +1795,7 @@ retry:
|
||||
err = ext3_add_entry (handle, dentry, inode);
|
||||
if (err) {
|
||||
inode->i_nlink = 0;
|
||||
unlock_new_inode(inode);
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
iput (inode);
|
||||
goto out_stop;
|
||||
@ -1800,6 +1804,7 @@ retry:
|
||||
ext3_update_dx_flag(dir);
|
||||
ext3_mark_inode_dirty(handle, dir);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
out_stop:
|
||||
ext3_journal_stop(handle);
|
||||
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
|
||||
@ -2174,6 +2179,7 @@ retry:
|
||||
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
|
||||
if (err) {
|
||||
drop_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
iput (inode);
|
||||
goto out_stop;
|
||||
@ -2221,7 +2227,14 @@ retry:
|
||||
inc_nlink(inode);
|
||||
atomic_inc(&inode->i_count);
|
||||
|
||||
err = ext3_add_nondir(handle, dentry, inode);
|
||||
err = ext3_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
} else {
|
||||
drop_nlink(inode);
|
||||
iput(inode);
|
||||
}
|
||||
ext3_journal_stop(handle);
|
||||
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
|
||||
goto retry;
|
||||
|
@ -826,7 +826,10 @@ got:
|
||||
ext4_set_inode_flags(inode);
|
||||
if (IS_DIRSYNC(inode))
|
||||
handle->h_sync = 1;
|
||||
insert_inode_hash(inode);
|
||||
if (insert_inode_locked(inode) < 0) {
|
||||
err = -EINVAL;
|
||||
goto fail_drop;
|
||||
}
|
||||
spin_lock(&sbi->s_next_gen_lock);
|
||||
inode->i_generation = sbi->s_next_generation++;
|
||||
spin_unlock(&sbi->s_next_gen_lock);
|
||||
@ -881,6 +884,7 @@ fail_drop:
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
inode->i_nlink = 0;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
brelse(bitmap_bh);
|
||||
return ERR_PTR(err);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/bio.h>
|
||||
#include "ext4_jbd2.h"
|
||||
@ -4164,9 +4165,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_op = &ext4_dir_inode_operations;
|
||||
inode->i_fop = &ext4_dir_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (ext4_inode_is_fast_symlink(inode))
|
||||
if (ext4_inode_is_fast_symlink(inode)) {
|
||||
inode->i_op = &ext4_fast_symlink_inode_operations;
|
||||
else {
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
} else {
|
||||
inode->i_op = &ext4_symlink_inode_operations;
|
||||
ext4_set_aops(inode);
|
||||
}
|
||||
|
@ -1693,9 +1693,11 @@ static int ext4_add_nondir(handle_t *handle,
|
||||
if (!err) {
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
return 0;
|
||||
}
|
||||
drop_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
@ -1830,6 +1832,7 @@ retry:
|
||||
if (err) {
|
||||
out_clear_inode:
|
||||
clear_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
iput(inode);
|
||||
goto out_stop;
|
||||
@ -1838,6 +1841,7 @@ out_clear_inode:
|
||||
ext4_update_dx_flag(dir);
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
out_stop:
|
||||
ext4_journal_stop(handle);
|
||||
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
|
||||
@ -2212,6 +2216,7 @@ retry:
|
||||
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
|
||||
if (err) {
|
||||
clear_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
iput(inode);
|
||||
goto out_stop;
|
||||
@ -2262,7 +2267,14 @@ retry:
|
||||
ext4_inc_count(handle, inode);
|
||||
atomic_inc(&inode->i_count);
|
||||
|
||||
err = ext4_add_nondir(handle, dentry, inode);
|
||||
err = ext4_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
} else {
|
||||
drop_nlink(inode);
|
||||
iput(inode);
|
||||
}
|
||||
ext4_journal_stop(handle);
|
||||
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
|
||||
goto retry;
|
||||
|
@ -32,6 +32,9 @@ struct files_stat_struct files_stat = {
|
||||
/* public. Not pretty! */
|
||||
__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock);
|
||||
|
||||
/* SLAB cache for file structures */
|
||||
static struct kmem_cache *filp_cachep __read_mostly;
|
||||
|
||||
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
|
||||
|
||||
static inline void file_free_rcu(struct rcu_head *head)
|
||||
@ -397,7 +400,12 @@ too_bad:
|
||||
void __init files_init(unsigned long mempages)
|
||||
{
|
||||
int n;
|
||||
/* One file with associated inode and dcache is very roughly 1K.
|
||||
|
||||
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
|
||||
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
|
||||
|
||||
/*
|
||||
* One file with associated inode and dcache is very roughly 1K.
|
||||
* Per default don't use more than 10% of our memory for files.
|
||||
*/
|
||||
|
||||
|
@ -325,8 +325,10 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
|
||||
if (!VXFS_ISIMMED(vip)) {
|
||||
ip->i_op = &page_symlink_inode_operations;
|
||||
ip->i_mapping->a_ops = &vxfs_aops;
|
||||
} else
|
||||
} else {
|
||||
ip->i_op = &vxfs_immed_symlink_iops;
|
||||
vip->vii_immed.vi_immed[ip->i_size] = '\0';
|
||||
}
|
||||
} else
|
||||
init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
|
||||
|
||||
|
59
fs/inode.c
59
fs/inode.c
@ -1032,6 +1032,65 @@ struct inode *iget_locked(struct super_block *sb, unsigned long ino)
|
||||
|
||||
EXPORT_SYMBOL(iget_locked);
|
||||
|
||||
int insert_inode_locked(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
ino_t ino = inode->i_ino;
|
||||
struct hlist_head *head = inode_hashtable + hash(sb, ino);
|
||||
struct inode *old;
|
||||
|
||||
inode->i_state |= I_LOCK|I_NEW;
|
||||
while (1) {
|
||||
spin_lock(&inode_lock);
|
||||
old = find_inode_fast(sb, head, ino);
|
||||
if (likely(!old)) {
|
||||
hlist_add_head(&inode->i_hash, head);
|
||||
spin_unlock(&inode_lock);
|
||||
return 0;
|
||||
}
|
||||
__iget(old);
|
||||
spin_unlock(&inode_lock);
|
||||
wait_on_inode(old);
|
||||
if (unlikely(!hlist_unhashed(&old->i_hash))) {
|
||||
iput(old);
|
||||
return -EBUSY;
|
||||
}
|
||||
iput(old);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(insert_inode_locked);
|
||||
|
||||
int insert_inode_locked4(struct inode *inode, unsigned long hashval,
|
||||
int (*test)(struct inode *, void *), void *data)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
|
||||
struct inode *old;
|
||||
|
||||
inode->i_state |= I_LOCK|I_NEW;
|
||||
|
||||
while (1) {
|
||||
spin_lock(&inode_lock);
|
||||
old = find_inode(sb, head, test, data);
|
||||
if (likely(!old)) {
|
||||
hlist_add_head(&inode->i_hash, head);
|
||||
spin_unlock(&inode_lock);
|
||||
return 0;
|
||||
}
|
||||
__iget(old);
|
||||
spin_unlock(&inode_lock);
|
||||
wait_on_inode(old);
|
||||
if (unlikely(!hlist_unhashed(&old->i_hash))) {
|
||||
iput(old);
|
||||
return -EBUSY;
|
||||
}
|
||||
iput(old);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(insert_inode_locked4);
|
||||
|
||||
/**
|
||||
* __insert_inode_hash - hash an inode
|
||||
* @inode: unhashed inode
|
||||
|
@ -79,7 +79,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||||
inode = new_inode(sb);
|
||||
if (!inode) {
|
||||
jfs_warn("ialloc: new_inode returned NULL!");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
rc = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
jfs_inode = JFS_IP(inode);
|
||||
@ -89,8 +90,12 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||||
jfs_warn("ialloc: diAlloc returned %d!", rc);
|
||||
if (rc == -EIO)
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
return ERR_PTR(rc);
|
||||
goto fail_put;
|
||||
}
|
||||
|
||||
if (insert_inode_locked(inode) < 0) {
|
||||
rc = -EINVAL;
|
||||
goto fail_unlock;
|
||||
}
|
||||
|
||||
inode->i_uid = current_fsuid();
|
||||
@ -112,11 +117,8 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||||
* Allocate inode to quota.
|
||||
*/
|
||||
if (DQUOT_ALLOC_INODE(inode)) {
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
inode->i_nlink = 0;
|
||||
iput(inode);
|
||||
return ERR_PTR(-EDQUOT);
|
||||
rc = -EDQUOT;
|
||||
goto fail_drop;
|
||||
}
|
||||
|
||||
inode->i_mode = mode;
|
||||
@ -158,4 +160,15 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
|
||||
jfs_info("ialloc returns inode = 0x%p\n", inode);
|
||||
|
||||
return inode;
|
||||
|
||||
fail_drop:
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
fail_unlock:
|
||||
inode->i_nlink = 0;
|
||||
unlock_new_inode(inode);
|
||||
fail_put:
|
||||
iput(inode);
|
||||
fail:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
@ -155,7 +155,6 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
|
||||
ip->i_fop = &jfs_file_operations;
|
||||
ip->i_mapping->a_ops = &jfs_aops;
|
||||
|
||||
insert_inode_hash(ip);
|
||||
mark_inode_dirty(ip);
|
||||
|
||||
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
|
||||
@ -171,9 +170,12 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
unlock_new_inode(ip);
|
||||
iput(ip);
|
||||
} else
|
||||
} else {
|
||||
d_instantiate(dentry, ip);
|
||||
unlock_new_inode(ip);
|
||||
}
|
||||
|
||||
out2:
|
||||
free_UCSname(&dname);
|
||||
@ -289,7 +291,6 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
|
||||
ip->i_op = &jfs_dir_inode_operations;
|
||||
ip->i_fop = &jfs_dir_operations;
|
||||
|
||||
insert_inode_hash(ip);
|
||||
mark_inode_dirty(ip);
|
||||
|
||||
/* update parent directory inode */
|
||||
@ -306,9 +307,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
unlock_new_inode(ip);
|
||||
iput(ip);
|
||||
} else
|
||||
} else {
|
||||
d_instantiate(dentry, ip);
|
||||
unlock_new_inode(ip);
|
||||
}
|
||||
|
||||
out2:
|
||||
free_UCSname(&dname);
|
||||
@ -1019,7 +1023,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
|
||||
goto out3;
|
||||
}
|
||||
|
||||
insert_inode_hash(ip);
|
||||
mark_inode_dirty(ip);
|
||||
|
||||
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
|
||||
@ -1039,9 +1042,12 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
unlock_new_inode(ip);
|
||||
iput(ip);
|
||||
} else
|
||||
} else {
|
||||
d_instantiate(dentry, ip);
|
||||
unlock_new_inode(ip);
|
||||
}
|
||||
|
||||
out2:
|
||||
free_UCSname(&dname);
|
||||
@ -1399,7 +1405,6 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
jfs_ip->dev = new_encode_dev(rdev);
|
||||
init_special_inode(ip, ip->i_mode, rdev);
|
||||
|
||||
insert_inode_hash(ip);
|
||||
mark_inode_dirty(ip);
|
||||
|
||||
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
|
||||
@ -1417,9 +1422,12 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
if (rc) {
|
||||
free_ea_wmap(ip);
|
||||
ip->i_nlink = 0;
|
||||
unlock_new_inode(ip);
|
||||
iput(ip);
|
||||
} else
|
||||
} else {
|
||||
d_instantiate(dentry, ip);
|
||||
unlock_new_inode(ip);
|
||||
}
|
||||
|
||||
out1:
|
||||
free_UCSname(&dname);
|
||||
|
115
fs/namei.c
115
fs/namei.c
@ -226,6 +226,16 @@ int generic_permission(struct inode *inode, int mask,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/**
|
||||
* inode_permission - check for access rights to a given inode
|
||||
* @inode: inode to check permission on
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
|
||||
*
|
||||
* Used to check for read/write/execute permissions on an inode.
|
||||
* We use "fsuid" for this, letting us set arbitrary permissions
|
||||
* for filesystem access without changing the "normal" uids which
|
||||
* are used for other things.
|
||||
*/
|
||||
int inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
int retval;
|
||||
@ -247,7 +257,6 @@ int inode_permission(struct inode *inode, int mask)
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/* Ordinary permission routines do not understand MAY_APPEND. */
|
||||
if (inode->i_op && inode->i_op->permission)
|
||||
retval = inode->i_op->permission(inode, mask);
|
||||
else
|
||||
@ -264,21 +273,6 @@ int inode_permission(struct inode *inode, int mask)
|
||||
mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND));
|
||||
}
|
||||
|
||||
/**
|
||||
* vfs_permission - check for access rights to a given path
|
||||
* @nd: lookup result that describes the path
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
|
||||
*
|
||||
* Used to check for read/write/execute permissions on a path.
|
||||
* We use "fsuid" for this, letting us set arbitrary permissions
|
||||
* for filesystem access without changing the "normal" uids which
|
||||
* are used for other things.
|
||||
*/
|
||||
int vfs_permission(struct nameidata *nd, int mask)
|
||||
{
|
||||
return inode_permission(nd->path.dentry->d_inode, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* file_permission - check for additional access rights to a given file
|
||||
* @file: file to check access rights for
|
||||
@ -289,7 +283,7 @@ int vfs_permission(struct nameidata *nd, int mask)
|
||||
*
|
||||
* Note:
|
||||
* Do not use this function in new code. All access checks should
|
||||
* be done using vfs_permission().
|
||||
* be done using inode_permission().
|
||||
*/
|
||||
int file_permission(struct file *file, int mask)
|
||||
{
|
||||
@ -527,18 +521,6 @@ out_unlock:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* SMP-safe */
|
||||
static __always_inline void
|
||||
walk_init_root(const char *name, struct nameidata *nd)
|
||||
{
|
||||
struct fs_struct *fs = current->fs;
|
||||
|
||||
read_lock(&fs->lock);
|
||||
nd->path = fs->root;
|
||||
path_get(&fs->root);
|
||||
read_unlock(&fs->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper to retry pathname resolution whenever the underlying
|
||||
* file system returns an ESTALE.
|
||||
@ -576,9 +558,16 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
|
||||
goto fail;
|
||||
|
||||
if (*link == '/') {
|
||||
struct fs_struct *fs = current->fs;
|
||||
|
||||
path_put(&nd->path);
|
||||
walk_init_root(link, nd);
|
||||
|
||||
read_lock(&fs->lock);
|
||||
nd->path = fs->root;
|
||||
path_get(&fs->root);
|
||||
read_unlock(&fs->lock);
|
||||
}
|
||||
|
||||
res = link_path_walk(link, nd);
|
||||
if (nd->depth || res || nd->last_type!=LAST_NORM)
|
||||
return res;
|
||||
@ -859,7 +848,8 @@ static int __link_path_walk(const char *name, struct nameidata *nd)
|
||||
nd->flags |= LOOKUP_CONTINUE;
|
||||
err = exec_permission_lite(inode);
|
||||
if (err == -EAGAIN)
|
||||
err = vfs_permission(nd, MAY_EXEC);
|
||||
err = inode_permission(nd->path.dentry->d_inode,
|
||||
MAY_EXEC);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@ -1493,9 +1483,9 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
return error;
|
||||
}
|
||||
|
||||
int may_open(struct nameidata *nd, int acc_mode, int flag)
|
||||
int may_open(struct path *path, int acc_mode, int flag)
|
||||
{
|
||||
struct dentry *dentry = nd->path.dentry;
|
||||
struct dentry *dentry = path->dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
||||
@ -1516,13 +1506,13 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
|
||||
if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
|
||||
flag &= ~O_TRUNC;
|
||||
} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
|
||||
if (nd->path.mnt->mnt_flags & MNT_NODEV)
|
||||
if (path->mnt->mnt_flags & MNT_NODEV)
|
||||
return -EACCES;
|
||||
|
||||
flag &= ~O_TRUNC;
|
||||
}
|
||||
|
||||
error = vfs_permission(nd, acc_mode);
|
||||
error = inode_permission(inode, acc_mode);
|
||||
if (error)
|
||||
return error;
|
||||
/*
|
||||
@ -1556,6 +1546,9 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
|
||||
* Refuse to truncate files with mandatory locks held on them.
|
||||
*/
|
||||
error = locks_verify_locked(inode);
|
||||
if (!error)
|
||||
error = security_path_truncate(path, 0,
|
||||
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
|
||||
@ -1586,14 +1579,18 @@ static int __open_namei_create(struct nameidata *nd, struct path *path,
|
||||
|
||||
if (!IS_POSIXACL(dir->d_inode))
|
||||
mode &= ~current->fs->umask;
|
||||
error = security_path_mknod(&nd->path, path->dentry, mode, 0);
|
||||
if (error)
|
||||
goto out_unlock;
|
||||
error = vfs_create(dir->d_inode, path->dentry, mode, nd);
|
||||
out_unlock:
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
dput(nd->path.dentry);
|
||||
nd->path.dentry = path->dentry;
|
||||
if (error)
|
||||
return error;
|
||||
/* Don't check for write permission, don't truncate */
|
||||
return may_open(nd, 0, flag & ~O_TRUNC);
|
||||
return may_open(&nd->path, 0, flag & ~O_TRUNC);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1779,7 +1776,7 @@ ok:
|
||||
if (error)
|
||||
goto exit;
|
||||
}
|
||||
error = may_open(&nd, acc_mode, flag);
|
||||
error = may_open(&nd.path, acc_mode, flag);
|
||||
if (error) {
|
||||
if (will_write)
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
@ -1999,6 +1996,9 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = security_path_mknod(&nd.path, dentry, mode, dev);
|
||||
if (error)
|
||||
goto out_drop_write;
|
||||
switch (mode & S_IFMT) {
|
||||
case 0: case S_IFREG:
|
||||
error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd);
|
||||
@ -2011,6 +2011,7 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
|
||||
error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0);
|
||||
break;
|
||||
}
|
||||
out_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
@ -2070,7 +2071,11 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = security_path_mkdir(&nd.path, dentry, mode);
|
||||
if (error)
|
||||
goto out_drop_write;
|
||||
error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
|
||||
out_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
@ -2180,7 +2185,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit3;
|
||||
error = security_path_rmdir(&nd.path, dentry);
|
||||
if (error)
|
||||
goto exit4;
|
||||
error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
|
||||
exit4:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit3:
|
||||
dput(dentry);
|
||||
@ -2265,7 +2274,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto exit2;
|
||||
error = security_path_unlink(&nd.path, dentry);
|
||||
if (error)
|
||||
goto exit3;
|
||||
error = vfs_unlink(nd.path.dentry->d_inode, dentry);
|
||||
exit3:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
exit2:
|
||||
dput(dentry);
|
||||
@ -2346,7 +2359,11 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = security_path_symlink(&nd.path, dentry, from);
|
||||
if (error)
|
||||
goto out_drop_write;
|
||||
error = vfs_symlink(nd.path.dentry->d_inode, dentry, from);
|
||||
out_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
@ -2443,7 +2460,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
|
||||
error = mnt_want_write(nd.path.mnt);
|
||||
if (error)
|
||||
goto out_dput;
|
||||
error = security_path_link(old_path.dentry, &nd.path, new_dentry);
|
||||
if (error)
|
||||
goto out_drop_write;
|
||||
error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry);
|
||||
out_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
out_dput:
|
||||
dput(new_dentry);
|
||||
@ -2679,8 +2700,13 @@ asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
|
||||
error = mnt_want_write(oldnd.path.mnt);
|
||||
if (error)
|
||||
goto exit5;
|
||||
error = security_path_rename(&oldnd.path, old_dentry,
|
||||
&newnd.path, new_dentry);
|
||||
if (error)
|
||||
goto exit6;
|
||||
error = vfs_rename(old_dir->d_inode, old_dentry,
|
||||
new_dir->d_inode, new_dentry);
|
||||
exit6:
|
||||
mnt_drop_write(oldnd.path.mnt);
|
||||
exit5:
|
||||
dput(new_dentry);
|
||||
@ -2750,13 +2776,16 @@ int vfs_follow_link(struct nameidata *nd, const char *link)
|
||||
/* get the link contents into pagecache */
|
||||
static char *page_getlink(struct dentry * dentry, struct page **ppage)
|
||||
{
|
||||
struct page * page;
|
||||
char *kaddr;
|
||||
struct page *page;
|
||||
struct address_space *mapping = dentry->d_inode->i_mapping;
|
||||
page = read_mapping_page(mapping, 0, NULL);
|
||||
if (IS_ERR(page))
|
||||
return (char*)page;
|
||||
*ppage = page;
|
||||
return kmap(page);
|
||||
kaddr = kmap(page);
|
||||
nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
|
||||
return kaddr;
|
||||
}
|
||||
|
||||
int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
|
||||
@ -2849,7 +2878,6 @@ EXPORT_SYMBOL(path_lookup);
|
||||
EXPORT_SYMBOL(kern_path);
|
||||
EXPORT_SYMBOL(vfs_path_lookup);
|
||||
EXPORT_SYMBOL(inode_permission);
|
||||
EXPORT_SYMBOL(vfs_permission);
|
||||
EXPORT_SYMBOL(file_permission);
|
||||
EXPORT_SYMBOL(unlock_rename);
|
||||
EXPORT_SYMBOL(vfs_create);
|
||||
@ -2865,3 +2893,10 @@ EXPORT_SYMBOL(vfs_symlink);
|
||||
EXPORT_SYMBOL(vfs_unlink);
|
||||
EXPORT_SYMBOL(dentry_unhash);
|
||||
EXPORT_SYMBOL(generic_readlink);
|
||||
|
||||
/* to be mentioned only in INIT_TASK */
|
||||
struct fs_struct init_fs = {
|
||||
.count = ATOMIC_INIT(1),
|
||||
.lock = __RW_LOCK_UNLOCKED(init_fs.lock),
|
||||
.umask = 0022,
|
||||
};
|
||||
|
@ -1990,7 +1990,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
|
||||
if (!new_ns->root) {
|
||||
up_write(&namespace_sem);
|
||||
kfree(new_ns);
|
||||
return ERR_PTR(-ENOMEM);;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
spin_lock(&vfsmount_lock);
|
||||
list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
|
||||
|
@ -38,9 +38,10 @@ static struct file *do_open(char *name, int flags)
|
||||
return ERR_PTR(error);
|
||||
|
||||
if (flags == O_RDWR)
|
||||
error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
|
||||
error = may_open(&nd.path, MAY_READ|MAY_WRITE,
|
||||
FMODE_READ|FMODE_WRITE);
|
||||
else
|
||||
error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
|
||||
error = may_open(&nd.path, MAY_WRITE, FMODE_WRITE);
|
||||
|
||||
if (!error)
|
||||
return dentry_open(nd.path.dentry, nd.path.mnt, flags,
|
||||
|
2
fs/notify/Kconfig
Normal file
2
fs/notify/Kconfig
Normal file
@ -0,0 +1,2 @@
|
||||
source "fs/notify/dnotify/Kconfig"
|
||||
source "fs/notify/inotify/Kconfig"
|
2
fs/notify/Makefile
Normal file
2
fs/notify/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-y += dnotify/
|
||||
obj-y += inotify/
|
10
fs/notify/dnotify/Kconfig
Normal file
10
fs/notify/dnotify/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
config DNOTIFY
|
||||
bool "Dnotify support"
|
||||
default y
|
||||
help
|
||||
Dnotify is a directory-based per-fd file change notification system
|
||||
that uses signals to communicate events to user-space. There exist
|
||||
superior alternatives, but some applications may still rely on
|
||||
dnotify.
|
||||
|
||||
If unsure, say Y.
|
1
fs/notify/dnotify/Makefile
Normal file
1
fs/notify/dnotify/Makefile
Normal file
@ -0,0 +1 @@
|
||||
obj-$(CONFIG_DNOTIFY) += dnotify.o
|
@ -115,9 +115,6 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
|
||||
dn->dn_next = inode->i_dnotify;
|
||||
inode->i_dnotify = dn;
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
if (filp->f_op && filp->f_op->dir_notify)
|
||||
return filp->f_op->dir_notify(filp, arg);
|
||||
return 0;
|
||||
|
||||
out_free:
|
27
fs/notify/inotify/Kconfig
Normal file
27
fs/notify/inotify/Kconfig
Normal file
@ -0,0 +1,27 @@
|
||||
config INOTIFY
|
||||
bool "Inotify file change notification support"
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable inotify support. Inotify is a file change
|
||||
notification system and a replacement for dnotify. Inotify fixes
|
||||
numerous shortcomings in dnotify and introduces several new features
|
||||
including multiple file events, one-shot support, and unmount
|
||||
notification.
|
||||
|
||||
For more information, see <file:Documentation/filesystems/inotify.txt>
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config INOTIFY_USER
|
||||
bool "Inotify support for userspace"
|
||||
depends on INOTIFY
|
||||
default y
|
||||
---help---
|
||||
Say Y here to enable inotify support for userspace, including the
|
||||
associated system calls. Inotify allows monitoring of both files and
|
||||
directories via a single open fd. Events are read from the file
|
||||
descriptor, which is also select()- and poll()-able.
|
||||
|
||||
For more information, see <file:Documentation/filesystems/inotify.txt>
|
||||
|
||||
If unsure, say Y.
|
2
fs/notify/inotify/Makefile
Normal file
2
fs/notify/inotify/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_INOTIFY) += inotify.o
|
||||
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
|
@ -76,10 +76,10 @@ struct inotify_device {
|
||||
struct mutex ev_mutex; /* protects event queue */
|
||||
struct mutex up_mutex; /* synchronizes watch updates */
|
||||
struct list_head events; /* list of queued events */
|
||||
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 */
|
||||
atomic_t count; /* reference count */
|
||||
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 */
|
@ -272,6 +272,8 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
|
||||
goto put_write_and_out;
|
||||
|
||||
error = locks_verify_truncate(inode, NULL, length);
|
||||
if (!error)
|
||||
error = security_path_truncate(&path, length, 0);
|
||||
if (!error) {
|
||||
DQUOT_INIT(inode);
|
||||
error = do_truncate(path.dentry, length, 0, NULL);
|
||||
@ -328,6 +330,9 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
|
||||
goto out_putf;
|
||||
|
||||
error = locks_verify_truncate(inode, file, length);
|
||||
if (!error)
|
||||
error = security_path_truncate(&file->f_path, length,
|
||||
ATTR_MTIME|ATTR_CTIME);
|
||||
if (!error)
|
||||
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
|
||||
out_putf:
|
||||
|
@ -1753,6 +1753,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
|
||||
struct inode *inode)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct reiserfs_iget_args args;
|
||||
INITIALIZE_PATH(path_to_key);
|
||||
struct cpu_key key;
|
||||
struct item_head ih;
|
||||
@ -1780,6 +1781,14 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
|
||||
err = -ENOMEM;
|
||||
goto out_bad_inode;
|
||||
}
|
||||
args.objectid = inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
|
||||
memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
|
||||
args.dirid = le32_to_cpu(ih.ih_key.k_dir_id);
|
||||
if (insert_inode_locked4(inode, args.objectid,
|
||||
reiserfs_find_actor, &args) < 0) {
|
||||
err = -EINVAL;
|
||||
goto out_bad_inode;
|
||||
}
|
||||
if (old_format_only(sb))
|
||||
/* not a perfect generation count, as object ids can be reused, but
|
||||
** this is as good as reiserfs can do right now.
|
||||
@ -1859,13 +1868,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
|
||||
} else {
|
||||
inode2sd(&sd, inode, inode->i_size);
|
||||
}
|
||||
// these do not go to on-disk stat data
|
||||
inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
|
||||
|
||||
// store in in-core inode the key of stat data and version all
|
||||
// object items will have (directory items will have old offset
|
||||
// format, other new objects will consist of new items)
|
||||
memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
|
||||
if (old_format_only(sb) || S_ISDIR(mode) || S_ISLNK(mode))
|
||||
set_inode_item_key_version(inode, KEY_FORMAT_3_5);
|
||||
else
|
||||
@ -1929,7 +1934,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
|
||||
reiserfs_mark_inode_private(inode);
|
||||
}
|
||||
|
||||
insert_inode_hash(inode);
|
||||
reiserfs_update_sd(th, inode);
|
||||
reiserfs_check_path(&path_to_key);
|
||||
|
||||
@ -1956,6 +1960,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
|
||||
out_inserted_sd:
|
||||
inode->i_nlink = 0;
|
||||
th->t_trans_id = 0; /* so the caller can't use this handle later */
|
||||
unlock_new_inode(inode); /* OK to do even if we hadn't locked it */
|
||||
|
||||
/* If we were inheriting an ACL, we need to release the lock so that
|
||||
* iput doesn't deadlock in reiserfs_delete_xattrs. The locking
|
||||
|
@ -646,6 +646,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
err = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
if (err)
|
||||
retval = err;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
goto out_failed;
|
||||
}
|
||||
@ -653,6 +654,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||
reiserfs_update_inode_transaction(dir);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
retval = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
|
||||
out_failed:
|
||||
@ -727,11 +729,13 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
|
||||
err = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
if (err)
|
||||
retval = err;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
retval = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
|
||||
out_failed:
|
||||
@ -812,6 +816,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
err = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
if (err)
|
||||
retval = err;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
goto out_failed;
|
||||
}
|
||||
@ -819,6 +824,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
||||
reiserfs_update_sd(&th, dir);
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
retval = journal_end(&th, dir->i_sb, jbegin_count);
|
||||
out_failed:
|
||||
if (locked)
|
||||
@ -1096,11 +1102,13 @@ static int reiserfs_symlink(struct inode *parent_dir,
|
||||
err = journal_end(&th, parent_dir->i_sb, jbegin_count);
|
||||
if (err)
|
||||
retval = err;
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
retval = journal_end(&th, parent_dir->i_sb, jbegin_count);
|
||||
out_failed:
|
||||
reiserfs_write_unlock(parent_dir->i_sb);
|
||||
|
@ -389,8 +389,14 @@ char *mangle_path(char *s, char *p, char *esc)
|
||||
}
|
||||
EXPORT_SYMBOL(mangle_path);
|
||||
|
||||
/*
|
||||
* return the absolute path of 'dentry' residing in mount 'mnt'.
|
||||
/**
|
||||
* seq_path - seq_file interface to print a pathname
|
||||
* @m: the seq_file handle
|
||||
* @path: the struct path to print
|
||||
* @esc: set of characters to escape in the output
|
||||
*
|
||||
* return the absolute path of 'path', as represented by the
|
||||
* dentry / mnt pair in the path parameter.
|
||||
*/
|
||||
int seq_path(struct seq_file *m, struct path *path, char *esc)
|
||||
{
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include "sysv.h"
|
||||
|
||||
@ -163,8 +164,11 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
|
||||
if (inode->i_blocks) {
|
||||
inode->i_op = &sysv_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &sysv_aops;
|
||||
} else
|
||||
} else {
|
||||
inode->i_op = &sysv_fast_symlink_inode_operations;
|
||||
nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
|
||||
sizeof(SYSV_I(inode)->i_data) - 1);
|
||||
}
|
||||
} else
|
||||
init_special_inode(inode, inode->i_mode, rdev);
|
||||
}
|
||||
|
@ -75,14 +75,22 @@ full_name_hash(const unsigned char *name, unsigned int len)
|
||||
return end_name_hash(hash);
|
||||
}
|
||||
|
||||
struct dcookie_struct;
|
||||
|
||||
#define DNAME_INLINE_LEN_MIN 36
|
||||
/*
|
||||
* Try to keep struct dentry aligned on 64 byte cachelines (this will
|
||||
* give reasonable cacheline footprint with larger lines without the
|
||||
* large memory footprint increase).
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
#define DNAME_INLINE_LEN_MIN 32 /* 192 bytes */
|
||||
#else
|
||||
#define DNAME_INLINE_LEN_MIN 40 /* 128 bytes */
|
||||
#endif
|
||||
|
||||
struct dentry {
|
||||
atomic_t d_count;
|
||||
unsigned int d_flags; /* protected by d_lock */
|
||||
spinlock_t d_lock; /* per dentry lock */
|
||||
int d_mounted;
|
||||
struct inode *d_inode; /* Where the name belongs to - NULL is
|
||||
* negative */
|
||||
/*
|
||||
@ -107,10 +115,7 @@ struct dentry {
|
||||
struct dentry_operations *d_op;
|
||||
struct super_block *d_sb; /* The root of the dentry tree */
|
||||
void *d_fsdata; /* fs-specific data */
|
||||
#ifdef CONFIG_PROFILING
|
||||
struct dcookie_struct *d_cookie; /* cookie, if any */
|
||||
#endif
|
||||
int d_mounted;
|
||||
|
||||
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
|
||||
};
|
||||
|
||||
@ -177,6 +182,8 @@ d_iput: no no no yes
|
||||
|
||||
#define DCACHE_INOTIFY_PARENT_WATCHED 0x0020 /* Parent inode is watched */
|
||||
|
||||
#define DCACHE_COOKIE 0x0040 /* For use by dcookie subsystem */
|
||||
|
||||
extern spinlock_t dcache_lock;
|
||||
extern seqlock_t rename_lock;
|
||||
|
||||
|
@ -57,8 +57,6 @@ struct files_struct {
|
||||
|
||||
#define files_fdtable(files) (rcu_dereference((files)->fdt))
|
||||
|
||||
extern struct kmem_cache *filp_cachep;
|
||||
|
||||
struct file_operations;
|
||||
struct vfsmount;
|
||||
struct dentry;
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
/* Fixed constants first: */
|
||||
#undef NR_OPEN
|
||||
extern int sysctl_nr_open;
|
||||
#define INR_OPEN 1024 /* Initial setting for nfile rlimits */
|
||||
|
||||
#define BLOCK_SIZE_BITS 10
|
||||
@ -38,21 +37,13 @@ struct files_stat_struct {
|
||||
int nr_free_files; /* read only */
|
||||
int max_files; /* tunable */
|
||||
};
|
||||
extern struct files_stat_struct files_stat;
|
||||
extern int get_max_files(void);
|
||||
|
||||
struct inodes_stat_t {
|
||||
int nr_inodes;
|
||||
int nr_unused;
|
||||
int dummy[5]; /* padding for sysctl ABI compatibility */
|
||||
};
|
||||
extern struct inodes_stat_t inodes_stat;
|
||||
|
||||
extern int leases_enable, lease_break_time;
|
||||
|
||||
#ifdef CONFIG_DNOTIFY
|
||||
extern int dir_notify_enable;
|
||||
#endif
|
||||
|
||||
#define NR_FILE 8192 /* this can well be larger on a larger system */
|
||||
|
||||
@ -330,6 +321,15 @@ extern void __init inode_init(void);
|
||||
extern void __init inode_init_early(void);
|
||||
extern void __init files_init(unsigned long);
|
||||
|
||||
extern struct files_stat_struct files_stat;
|
||||
extern int get_max_files(void);
|
||||
extern int sysctl_nr_open;
|
||||
extern struct inodes_stat_t inodes_stat;
|
||||
extern int leases_enable, lease_break_time;
|
||||
#ifdef CONFIG_DNOTIFY
|
||||
extern int dir_notify_enable;
|
||||
#endif
|
||||
|
||||
struct buffer_head;
|
||||
typedef int (get_block_t)(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create);
|
||||
@ -1212,7 +1212,6 @@ extern void unlock_super(struct super_block *);
|
||||
/*
|
||||
* VFS helper functions..
|
||||
*/
|
||||
extern int vfs_permission(struct nameidata *, int);
|
||||
extern int vfs_create(struct inode *, struct dentry *, int, struct nameidata *);
|
||||
extern int vfs_mkdir(struct inode *, struct dentry *, int);
|
||||
extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
|
||||
@ -1310,7 +1309,6 @@ struct file_operations {
|
||||
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
|
||||
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
|
||||
int (*check_flags)(int);
|
||||
int (*dir_notify)(struct file *filp, unsigned long arg);
|
||||
int (*flock) (struct file *, int, struct file_lock *);
|
||||
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
|
||||
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
|
||||
@ -1869,7 +1867,7 @@ extern void free_write_pipe(struct file *);
|
||||
|
||||
extern struct file *do_filp_open(int dfd, const char *pathname,
|
||||
int open_flag, int mode);
|
||||
extern int may_open(struct nameidata *, int, int);
|
||||
extern int may_open(struct path *, int, int);
|
||||
|
||||
extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
|
||||
extern struct file * open_exec(const char *);
|
||||
@ -1904,6 +1902,8 @@ extern struct inode *ilookup(struct super_block *sb, unsigned long ino);
|
||||
|
||||
extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
|
||||
extern struct inode * iget_locked(struct super_block *, unsigned long);
|
||||
extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
|
||||
extern int insert_inode_locked(struct inode *);
|
||||
extern void unlock_new_inode(struct inode *);
|
||||
|
||||
extern void __iget(struct inode * inode);
|
||||
|
@ -10,12 +10,6 @@ struct fs_struct {
|
||||
struct path root, pwd;
|
||||
};
|
||||
|
||||
#define INIT_FS { \
|
||||
.count = ATOMIC_INIT(1), \
|
||||
.lock = RW_LOCK_UNLOCKED, \
|
||||
.umask = 0022, \
|
||||
}
|
||||
|
||||
extern struct kmem_cache *fs_cachep;
|
||||
|
||||
extern void exit_fs(struct task_struct *);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
extern struct files_struct init_files;
|
||||
extern struct fs_struct init_fs;
|
||||
|
||||
#define INIT_KIOCTX(name, which_mm) \
|
||||
{ \
|
||||
|
@ -94,4 +94,9 @@ static inline char *nd_get_link(struct nameidata *nd)
|
||||
return nd->saved_names[nd->depth];
|
||||
}
|
||||
|
||||
static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
|
||||
{
|
||||
((char *) name)[min(len, maxlen)] = '\0';
|
||||
}
|
||||
|
||||
#endif /* _LINUX_NAMEI_H */
|
||||
|
@ -335,17 +335,37 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @dir contains the inode structure of the parent directory of the new link.
|
||||
* @new_dentry contains the dentry structure for the new link.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_link:
|
||||
* Check permission before creating a new hard link to a file.
|
||||
* @old_dentry contains the dentry structure for an existing link
|
||||
* to the file.
|
||||
* @new_dir contains the path structure of the parent directory of
|
||||
* the new link.
|
||||
* @new_dentry contains the dentry structure for the new link.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_unlink:
|
||||
* Check the permission to remove a hard link to a file.
|
||||
* @dir contains the inode structure of parent directory of the file.
|
||||
* @dentry contains the dentry structure for file to be unlinked.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_unlink:
|
||||
* Check the permission to remove a hard link to a file.
|
||||
* @dir contains the path structure of parent directory of the file.
|
||||
* @dentry contains the dentry structure for file to be unlinked.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_symlink:
|
||||
* Check the permission to create a symbolic link to a file.
|
||||
* @dir contains the inode structure of parent directory of the symbolic link.
|
||||
* @dentry contains the dentry structure of the symbolic link.
|
||||
* @old_name contains the pathname of file.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_symlink:
|
||||
* Check the permission to create a symbolic link to a file.
|
||||
* @dir contains the path structure of parent directory of
|
||||
* the symbolic link.
|
||||
* @dentry contains the dentry structure of the symbolic link.
|
||||
* @old_name contains the pathname of file.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_mkdir:
|
||||
* Check permissions to create a new directory in the existing directory
|
||||
* associated with inode strcture @dir.
|
||||
@ -353,11 +373,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @dentry contains the dentry structure of new directory.
|
||||
* @mode contains the mode of new directory.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_mkdir:
|
||||
* Check permissions to create a new directory in the existing directory
|
||||
* associated with path strcture @path.
|
||||
* @dir containst the path structure of parent of the directory
|
||||
* to be created.
|
||||
* @dentry contains the dentry structure of new directory.
|
||||
* @mode contains the mode of new directory.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_rmdir:
|
||||
* Check the permission to remove a directory.
|
||||
* @dir contains the inode structure of parent of the directory to be removed.
|
||||
* @dentry contains the dentry structure of directory to be removed.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_rmdir:
|
||||
* Check the permission to remove a directory.
|
||||
* @dir contains the path structure of parent of the directory to be
|
||||
* removed.
|
||||
* @dentry contains the dentry structure of directory to be removed.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_mknod:
|
||||
* Check permissions when creating a special file (or a socket or a fifo
|
||||
* file created via the mknod system call). Note that if mknod operation
|
||||
@ -368,6 +402,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @mode contains the mode of the new file.
|
||||
* @dev contains the device number.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_mknod:
|
||||
* Check permissions when creating a file. Note that this hook is called
|
||||
* even if mknod operation is being done for a regular file.
|
||||
* @dir contains the path structure of parent of the new file.
|
||||
* @dentry contains the dentry structure of the new file.
|
||||
* @mode contains the mode of the new file.
|
||||
* @dev contains the undecoded device number. Use new_decode_dev() to get
|
||||
* the decoded device number.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_rename:
|
||||
* Check for permission to rename a file or directory.
|
||||
* @old_dir contains the inode structure for parent of the old link.
|
||||
@ -375,6 +418,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @new_dir contains the inode structure for parent of the new link.
|
||||
* @new_dentry contains the dentry structure of the new link.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_rename:
|
||||
* Check for permission to rename a file or directory.
|
||||
* @old_dir contains the path structure for parent of the old link.
|
||||
* @old_dentry contains the dentry structure of the old link.
|
||||
* @new_dir contains the path structure for parent of the new link.
|
||||
* @new_dentry contains the dentry structure of the new link.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_readlink:
|
||||
* Check the permission to read the symbolic link.
|
||||
* @dentry contains the dentry structure for the file link.
|
||||
@ -403,6 +453,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @dentry contains the dentry structure for the file.
|
||||
* @attr is the iattr structure containing the new file attributes.
|
||||
* Return 0 if permission is granted.
|
||||
* @path_truncate:
|
||||
* Check permission before truncating a file.
|
||||
* @path contains the path structure for the file.
|
||||
* @length is the new length of the file.
|
||||
* @time_attrs is the flags passed to do_truncate().
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_getattr:
|
||||
* Check permission before obtaining file attributes.
|
||||
* @mnt is the vfsmount where the dentry was looked up
|
||||
@ -1331,6 +1387,22 @@ struct security_operations {
|
||||
struct super_block *newsb);
|
||||
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
|
||||
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
int (*path_unlink) (struct path *dir, struct dentry *dentry);
|
||||
int (*path_mkdir) (struct path *dir, struct dentry *dentry, int mode);
|
||||
int (*path_rmdir) (struct path *dir, struct dentry *dentry);
|
||||
int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
|
||||
unsigned int dev);
|
||||
int (*path_truncate) (struct path *path, loff_t length,
|
||||
unsigned int time_attrs);
|
||||
int (*path_symlink) (struct path *dir, struct dentry *dentry,
|
||||
const char *old_name);
|
||||
int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
|
||||
struct dentry *new_dentry);
|
||||
int (*path_rename) (struct path *old_dir, struct dentry *old_dentry,
|
||||
struct path *new_dir, struct dentry *new_dentry);
|
||||
#endif
|
||||
|
||||
int (*inode_alloc_security) (struct inode *inode);
|
||||
void (*inode_free_security) (struct inode *inode);
|
||||
int (*inode_init_security) (struct inode *inode, struct inode *dir,
|
||||
@ -2705,6 +2777,71 @@ static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi
|
||||
|
||||
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
|
||||
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
int security_path_unlink(struct path *dir, struct dentry *dentry);
|
||||
int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
|
||||
int security_path_rmdir(struct path *dir, struct dentry *dentry);
|
||||
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
|
||||
unsigned int dev);
|
||||
int security_path_truncate(struct path *path, loff_t length,
|
||||
unsigned int time_attrs);
|
||||
int security_path_symlink(struct path *dir, struct dentry *dentry,
|
||||
const char *old_name);
|
||||
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
|
||||
struct dentry *new_dentry);
|
||||
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
|
||||
struct path *new_dir, struct dentry *new_dentry);
|
||||
#else /* CONFIG_SECURITY_PATH */
|
||||
static inline int security_path_unlink(struct path *dir, struct dentry *dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_mkdir(struct path *dir, struct dentry *dentry,
|
||||
int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_rmdir(struct path *dir, struct dentry *dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
|
||||
int mode, unsigned int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_truncate(struct path *path, loff_t length,
|
||||
unsigned int time_attrs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_symlink(struct path *dir, struct dentry *dentry,
|
||||
const char *old_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_link(struct dentry *old_dentry,
|
||||
struct path *new_dir,
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_path_rename(struct path *old_dir,
|
||||
struct dentry *old_dentry,
|
||||
struct path *new_dir,
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SECURITY_PATH */
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
#ifdef CONFIG_SECURITY
|
||||
|
||||
|
@ -836,7 +836,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||
err = mnt_want_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
err = security_path_mknod(&nd.path, dentry, mode, 0);
|
||||
if (err)
|
||||
goto out_mknod_drop_write;
|
||||
err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0);
|
||||
out_mknod_drop_write:
|
||||
mnt_drop_write(nd.path.mnt);
|
||||
if (err)
|
||||
goto out_mknod_dput;
|
||||
|
@ -81,6 +81,15 @@ config SECURITY_NETWORK_XFRM
|
||||
IPSec.
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
config SECURITY_PATH
|
||||
bool "Security hooks for pathname based access control"
|
||||
depends on SECURITY
|
||||
help
|
||||
This enables the security hooks for pathname based access control.
|
||||
If enabled, a security module can use these hooks to
|
||||
implement pathname based access controls.
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
config SECURITY_FILE_CAPABILITIES
|
||||
bool "File POSIX Capabilities"
|
||||
default n
|
||||
|
@ -263,6 +263,53 @@ static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
|
||||
*secid = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
static int cap_path_mknod(struct path *dir, struct dentry *dentry, int mode,
|
||||
unsigned int dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_rmdir(struct path *dir, struct dentry *dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_unlink(struct path *dir, struct dentry *dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_symlink(struct path *dir, struct dentry *dentry,
|
||||
const char *old_name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_link(struct dentry *old_dentry, struct path *new_dir,
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
|
||||
struct path *new_path, struct dentry *new_dentry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_path_truncate(struct path *path, loff_t length,
|
||||
unsigned int time_attrs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int cap_file_permission(struct file *file, int mask)
|
||||
{
|
||||
return 0;
|
||||
@ -883,6 +930,16 @@ void security_fixup_ops(struct security_operations *ops)
|
||||
set_to_cap_if_null(ops, inode_setsecurity);
|
||||
set_to_cap_if_null(ops, inode_listsecurity);
|
||||
set_to_cap_if_null(ops, inode_getsecid);
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
set_to_cap_if_null(ops, path_mknod);
|
||||
set_to_cap_if_null(ops, path_mkdir);
|
||||
set_to_cap_if_null(ops, path_rmdir);
|
||||
set_to_cap_if_null(ops, path_unlink);
|
||||
set_to_cap_if_null(ops, path_symlink);
|
||||
set_to_cap_if_null(ops, path_link);
|
||||
set_to_cap_if_null(ops, path_rename);
|
||||
set_to_cap_if_null(ops, path_truncate);
|
||||
#endif
|
||||
set_to_cap_if_null(ops, file_permission);
|
||||
set_to_cap_if_null(ops, file_alloc_security);
|
||||
set_to_cap_if_null(ops, file_free_security);
|
||||
|
@ -355,6 +355,72 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
}
|
||||
EXPORT_SYMBOL(security_inode_init_security);
|
||||
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
int security_path_mknod(struct path *path, struct dentry *dentry, int mode,
|
||||
unsigned int dev)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_mknod(path, dentry, mode, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(security_path_mknod);
|
||||
|
||||
int security_path_mkdir(struct path *path, struct dentry *dentry, int mode)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_mkdir(path, dentry, mode);
|
||||
}
|
||||
|
||||
int security_path_rmdir(struct path *path, struct dentry *dentry)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_rmdir(path, dentry);
|
||||
}
|
||||
|
||||
int security_path_unlink(struct path *path, struct dentry *dentry)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_unlink(path, dentry);
|
||||
}
|
||||
|
||||
int security_path_symlink(struct path *path, struct dentry *dentry,
|
||||
const char *old_name)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_symlink(path, dentry, old_name);
|
||||
}
|
||||
|
||||
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
|
||||
struct dentry *new_dentry)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_link(old_dentry, new_dir, new_dentry);
|
||||
}
|
||||
|
||||
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
|
||||
struct path *new_dir, struct dentry *new_dentry)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
|
||||
(new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
|
||||
return 0;
|
||||
return security_ops->path_rename(old_dir, old_dentry, new_dir,
|
||||
new_dentry);
|
||||
}
|
||||
|
||||
int security_path_truncate(struct path *path, loff_t length,
|
||||
unsigned int time_attrs)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
|
||||
return 0;
|
||||
return security_ops->path_truncate(path, length, time_attrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(dir)))
|
||||
|
Loading…
Reference in New Issue
Block a user