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:
Linus Torvalds 2008-12-31 15:57:56 -08:00
commit b58602a4ba
81 changed files with 696 additions and 351 deletions

View File

@ -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

View File

@ -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().

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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/

View File

@ -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,

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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,
};

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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.
*/

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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,
};

View File

@ -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);

View File

@ -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
View File

@ -0,0 +1,2 @@
source "fs/notify/dnotify/Kconfig"
source "fs/notify/inotify/Kconfig"

2
fs/notify/Makefile Normal file
View File

@ -0,0 +1,2 @@
obj-y += dnotify/
obj-y += inotify/

10
fs/notify/dnotify/Kconfig Normal file
View 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.

View File

@ -0,0 +1 @@
obj-$(CONFIG_DNOTIFY) += dnotify.o

View File

@ -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
View 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.

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o

View File

@ -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 */

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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 *);

View File

@ -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) \
{ \

View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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)))