dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs changes from Al Viro.
 "A lot of misc stuff.  The obvious groups:
   * Miklos' atomic_open series; kills the damn abuse of
     ->d_revalidate() by NFS, which was the major stumbling block for
     all work in that area.
   * ripping security_file_mmap() and dealing with deadlocks in the
     area; sanitizing the neighborhood of vm_mmap()/vm_munmap() in
     general.
   * ->encode_fh() switched to saner API; insane fake dentry in
     mm/cleancache.c gone.
   * assorted annotations in fs (endianness, __user)
   * parts of Artem's ->s_dirty work (jff2 and reiserfs parts)
   * ->update_time() work from Josef.
   * other bits and pieces all over the place.

  Normally it would've been in two or three pull requests, but
  signal.git stuff had eaten a lot of time during this cycle ;-/"

Fix up trivial conflicts in Documentation/filesystems/vfs.txt (the
'truncate_range' inode method was removed by the VM changes, the VFS
update adds an 'update_time()' method), and in fs/btrfs/ulist.[ch] (due
to sparse fix added twice, with other changes nearby).

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (95 commits)
  nfs: don't open in ->d_revalidate
  vfs: retry last component if opening stale dentry
  vfs: nameidata_to_filp(): don't throw away file on error
  vfs: nameidata_to_filp(): inline __dentry_open()
  vfs: do_dentry_open(): don't put filp
  vfs: split __dentry_open()
  vfs: do_last() common post lookup
  vfs: do_last(): add audit_inode before open
  vfs: do_last(): only return EISDIR for O_CREAT
  vfs: do_last(): check LOOKUP_DIRECTORY
  vfs: do_last(): make ENOENT exit RCU safe
  vfs: make follow_link check RCU safe
  vfs: do_last(): use inode variable
  vfs: do_last(): inline walk_component()
  vfs: do_last(): make exit RCU safe
  vfs: split do_lookup()
  Btrfs: move over to use ->update_time
  fs: introduce inode operation ->update_time
  reiserfs: get rid of resierfs_sync_super
  reiserfs: mark the superblock as dirty a bit later
  ...
This commit is contained in:
Linus Torvalds 2012-06-01 10:34:35 -07:00
commit 1193755ac6
148 changed files with 1497 additions and 1620 deletions

View File

@ -61,6 +61,7 @@ ata *);
ssize_t (*listxattr) (struct dentry *, char *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *); int (*removexattr) (struct dentry *, const char *);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
void (*update_time)(struct inode *, struct timespec *, int);
locking rules: locking rules:
all may block all may block
@ -87,6 +88,8 @@ getxattr: no
listxattr: no listxattr: no
removexattr: yes removexattr: yes
fiemap: no fiemap: no
update_time: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim. victim.
cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.

View File

@ -363,6 +363,7 @@ struct inode_operations {
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t); ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *); int (*removexattr) (struct dentry *, const char *);
void (*update_time)(struct inode *, struct timespec *, int);
}; };
Again, all methods are called without any locks being held, unless Again, all methods are called without any locks being held, unless
@ -471,6 +472,9 @@ otherwise noted.
removexattr: called by the VFS to remove an extended attribute from removexattr: called by the VFS to remove an extended attribute from
a file. This method is called by removexattr(2) system call. a file. This method is called by removexattr(2) system call.
update_time: called by the VFS to update a specific time or the i_version of
an inode. If this is not defined the VFS will update the inode itself
and call mark_inode_dirty_sync.
The Address Space Object The Address Space Object
======================== ========================

View File

@ -10,9 +10,6 @@
typedef unsigned int __kernel_ino_t; typedef unsigned int __kernel_ino_t;
#define __kernel_ino_t __kernel_ino_t #define __kernel_ino_t __kernel_ino_t
typedef unsigned int __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ typedef unsigned long __kernel_sigset_t; /* at least 32 bits */
#include <asm-generic/posix_types.h> #include <asm-generic/posix_types.h>

View File

@ -22,9 +22,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -17,9 +17,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned int __kernel_ipc_pid_t; typedef unsigned int __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -15,9 +15,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -1,9 +1,6 @@
#ifndef _ASM_IA64_POSIX_TYPES_H #ifndef _ASM_IA64_POSIX_TYPES_H
#define _ASM_IA64_POSIX_TYPES_H #define _ASM_IA64_POSIX_TYPES_H
typedef unsigned int __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ typedef unsigned long __kernel_sigset_t; /* at least 32 bits */
#include <asm-generic/posix_types.h> #include <asm-generic/posix_types.h>

View File

@ -604,12 +604,6 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f)
spin_unlock(&(x)->ctx_lock); spin_unlock(&(x)->ctx_lock);
} }
static inline unsigned long
pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec)
{
return get_unmapped_area(file, addr, len, pgoff, flags);
}
/* forward declaration */ /* forward declaration */
static const struct dentry_operations pfmfs_dentry_operations; static const struct dentry_operations pfmfs_dentry_operations;
@ -2333,8 +2327,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
down_write(&task->mm->mmap_sem); down_write(&task->mm->mmap_sem);
/* find some free area in address space, must have mmap sem held */ /* find some free area in address space, must have mmap sem held */
vma->vm_start = pfm_get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS, 0); vma->vm_start = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS);
if (vma->vm_start == 0UL) { if (IS_ERR_VALUE(vma->vm_start)) {
DPRINT(("Cannot find unmapped area for size %ld\n", size)); DPRINT(("Cannot find unmapped area for size %ld\n", size));
up_write(&task->mm->mmap_sem); up_write(&task->mm->mmap_sem);
goto error; goto error;

View File

@ -171,22 +171,9 @@ asmlinkage unsigned long
ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, ia64_mremap (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags,
unsigned long new_addr) unsigned long new_addr)
{ {
extern unsigned long do_mremap (unsigned long addr, addr = sys_mremap(addr, old_len, new_len, flags, new_addr);
unsigned long old_len, if (!IS_ERR((void *) addr))
unsigned long new_len, force_successful_syscall_return();
unsigned long flags,
unsigned long new_addr);
down_write(&current->mm->mmap_sem);
{
addr = do_mremap(addr, old_len, new_len, flags, new_addr);
}
up_write(&current->mm->mmap_sem);
if (IS_ERR((void *) addr))
return addr;
force_successful_syscall_return();
return addr; return addr;
} }

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -17,11 +17,6 @@
* assume GCC is being used. * assume GCC is being used.
*/ */
#if (_MIPS_SZLONG == 64)
typedef unsigned int __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
#endif
typedef long __kernel_daddr_t; typedef long __kernel_daddr_t;
#define __kernel_daddr_t __kernel_daddr_t #define __kernel_daddr_t __kernel_daddr_t

View File

@ -20,7 +20,7 @@ struct stat {
long st_pad1[3]; /* Reserved for network id */ long st_pad1[3]; /* Reserved for network id */
ino_t st_ino; ino_t st_ino;
mode_t st_mode; mode_t st_mode;
nlink_t st_nlink; __u32 st_nlink;
uid_t st_uid; uid_t st_uid;
gid_t st_gid; gid_t st_gid;
unsigned st_rdev; unsigned st_rdev;
@ -55,7 +55,7 @@ struct stat64 {
unsigned long long st_ino; unsigned long long st_ino;
mode_t st_mode; mode_t st_mode;
nlink_t st_nlink; __u32 st_nlink;
uid_t st_uid; uid_t st_uid;
gid_t st_gid; gid_t st_gid;
@ -96,7 +96,7 @@ struct stat {
unsigned long st_ino; unsigned long st_ino;
mode_t st_mode; mode_t st_mode;
nlink_t st_nlink; __u32 st_nlink;
uid_t st_uid; uid_t st_uid;
gid_t st_gid; gid_t st_gid;

View File

@ -20,9 +20,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -7,7 +7,7 @@ struct stat {
unsigned int st_dev; /* dev_t is 32 bits on parisc */ unsigned int st_dev; /* dev_t is 32 bits on parisc */
ino_t st_ino; /* 32 bits */ ino_t st_ino; /* 32 bits */
mode_t st_mode; /* 16 bits */ mode_t st_mode; /* 16 bits */
nlink_t st_nlink; /* 16 bits */ unsigned short st_nlink; /* 16 bits */
unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved1; /* old st_uid */
unsigned short st_reserved2; /* old st_gid */ unsigned short st_reserved2; /* old st_gid */
unsigned int st_rdev; unsigned int st_rdev;
@ -42,7 +42,7 @@ struct hpux_stat64 {
unsigned int st_dev; /* dev_t is 32 bits on parisc */ unsigned int st_dev; /* dev_t is 32 bits on parisc */
ino_t st_ino; /* 32 bits */ ino_t st_ino; /* 32 bits */
mode_t st_mode; /* 16 bits */ mode_t st_mode; /* 16 bits */
nlink_t st_nlink; /* 16 bits */ unsigned short st_nlink; /* 16 bits */
unsigned short st_reserved1; /* old st_uid */ unsigned short st_reserved1; /* old st_uid */
unsigned short st_reserved2; /* old st_gid */ unsigned short st_reserved2; /* old st_gid */
unsigned int st_rdev; unsigned int st_rdev;

View File

@ -16,9 +16,6 @@ typedef int __kernel_ssize_t;
typedef long __kernel_ptrdiff_t; typedef long __kernel_ptrdiff_t;
#define __kernel_size_t __kernel_size_t #define __kernel_size_t __kernel_size_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef short __kernel_ipc_pid_t; typedef short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t
#endif #endif

View File

@ -30,11 +30,11 @@ struct stat {
unsigned long st_dev; unsigned long st_dev;
ino_t st_ino; ino_t st_ino;
#ifdef __powerpc64__ #ifdef __powerpc64__
nlink_t st_nlink; unsigned short st_nlink;
mode_t st_mode; mode_t st_mode;
#else #else
mode_t st_mode; mode_t st_mode;
nlink_t st_nlink; unsigned short st_nlink;
#endif #endif
uid_t st_uid; uid_t st_uid;
gid_t st_gid; gid_t st_gid;

View File

@ -24,7 +24,6 @@ typedef unsigned short __kernel_old_dev_t;
typedef unsigned long __kernel_ino_t; typedef unsigned long __kernel_ino_t;
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
typedef unsigned short __kernel_nlink_t;
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_uid_t;
typedef unsigned short __kernel_gid_t; typedef unsigned short __kernel_gid_t;
@ -35,7 +34,6 @@ typedef int __kernel_ptrdiff_t;
typedef unsigned int __kernel_ino_t; typedef unsigned int __kernel_ino_t;
typedef unsigned int __kernel_mode_t; typedef unsigned int __kernel_mode_t;
typedef unsigned int __kernel_nlink_t;
typedef int __kernel_ipc_pid_t; typedef int __kernel_ipc_pid_t;
typedef unsigned int __kernel_uid_t; typedef unsigned int __kernel_uid_t;
typedef unsigned int __kernel_gid_t; typedef unsigned int __kernel_gid_t;
@ -47,7 +45,6 @@ typedef unsigned long __kernel_sigset_t; /* at least 32 bits */
#define __kernel_ino_t __kernel_ino_t #define __kernel_ino_t __kernel_ino_t
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
#define __kernel_nlink_t __kernel_nlink_t
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t
#define __kernel_uid_t __kernel_uid_t #define __kernel_uid_t __kernel_uid_t
#define __kernel_gid_t __kernel_gid_t #define __kernel_gid_t __kernel_gid_t

View File

@ -3,8 +3,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t
typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_uid_t;

View File

@ -3,8 +3,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t
typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_uid_t;

View File

@ -9,8 +9,6 @@
#if defined(__sparc__) && defined(__arch64__) #if defined(__sparc__) && defined(__arch64__)
/* sparc 64 bit */ /* sparc 64 bit */
typedef unsigned int __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_old_uid_t; typedef unsigned short __kernel_old_uid_t;
typedef unsigned short __kernel_old_gid_t; typedef unsigned short __kernel_old_gid_t;
@ -38,9 +36,6 @@ typedef unsigned short __kernel_gid_t;
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef long __kernel_daddr_t; typedef long __kernel_daddr_t;
#define __kernel_daddr_t __kernel_daddr_t #define __kernel_daddr_t __kernel_daddr_t

View File

@ -580,16 +580,9 @@ SYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len,
unsigned long, new_len, unsigned long, flags, unsigned long, new_len, unsigned long, flags,
unsigned long, new_addr) unsigned long, new_addr)
{ {
unsigned long ret = -EINVAL;
if (test_thread_flag(TIF_32BIT)) if (test_thread_flag(TIF_32BIT))
goto out; return -EINVAL;
return sys_mremap(addr, old_len, new_len, flags, new_addr);
down_write(&current->mm->mmap_sem);
ret = do_mremap(addr, old_len, new_len, flags, new_addr);
up_write(&current->mm->mmap_sem);
out:
return ret;
} }
/* we come to here via sys_nis_syscall so it can setup the regs argument */ /* we come to here via sys_nis_syscall so it can setup the regs argument */

View File

@ -44,7 +44,6 @@ typedef __kernel_uid32_t __compat_gid32_t;
typedef __kernel_mode_t compat_mode_t; typedef __kernel_mode_t compat_mode_t;
typedef __kernel_dev_t compat_dev_t; typedef __kernel_dev_t compat_dev_t;
typedef __kernel_loff_t compat_loff_t; typedef __kernel_loff_t compat_loff_t;
typedef __kernel_nlink_t compat_nlink_t;
typedef __kernel_ipc_pid_t compat_ipc_pid_t; typedef __kernel_ipc_pid_t compat_ipc_pid_t;
typedef __kernel_daddr_t compat_daddr_t; typedef __kernel_daddr_t compat_daddr_t;
typedef __kernel_fsid_t compat_fsid_t; typedef __kernel_fsid_t compat_fsid_t;

View File

@ -10,9 +10,6 @@
typedef unsigned short __kernel_mode_t; typedef unsigned short __kernel_mode_t;
#define __kernel_mode_t __kernel_mode_t #define __kernel_mode_t __kernel_mode_t
typedef unsigned short __kernel_nlink_t;
#define __kernel_nlink_t __kernel_nlink_t
typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_ipc_pid_t;
#define __kernel_ipc_pid_t __kernel_ipc_pid_t #define __kernel_ipc_pid_t __kernel_ipc_pid_t

View File

@ -42,7 +42,7 @@ struct device *soc_device_to_device(struct soc_device *soc_dev)
return &soc_dev->dev; return &soc_dev->dev;
} }
static mode_t soc_attribute_mode(struct kobject *kobj, static umode_t soc_attribute_mode(struct kobject *kobj,
struct attribute *attr, struct attribute *attr,
int index) int index)
{ {

View File

@ -130,11 +130,10 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
return -EINVAL; return -EINVAL;
/* This is all entirely broken */ /* This is all entirely broken */
down_write(&current->mm->mmap_sem);
old_fops = file_priv->filp->f_op; old_fops = file_priv->filp->f_op;
file_priv->filp->f_op = &i810_buffer_fops; file_priv->filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf; dev_priv->mmap_buffer = buf;
buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total, buf_priv->virtual = (void *)vm_mmap(file_priv->filp, 0, buf->total,
PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
MAP_SHARED, buf->bus_address); MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL; dev_priv->mmap_buffer = NULL;
@ -145,7 +144,6 @@ static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
retcode = PTR_ERR(buf_priv->virtual); retcode = PTR_ERR(buf_priv->virtual);
buf_priv->virtual = NULL; buf_priv->virtual = NULL;
} }
up_write(&current->mm->mmap_sem);
return retcode; return retcode;
} }

View File

@ -68,24 +68,6 @@ static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
return current_fsgid(); return current_fsgid();
} }
/**
* v9fs_dentry_from_dir_inode - helper function to get the dentry from
* dir inode.
*
*/
static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
/* Directory should have only one entry. */
BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
spin_unlock(&inode->i_lock);
return dentry;
}
static int v9fs_test_inode_dotl(struct inode *inode, void *data) static int v9fs_test_inode_dotl(struct inode *inode, void *data)
{ {
struct v9fs_inode *v9inode = V9FS_I(inode); struct v9fs_inode *v9inode = V9FS_I(inode);
@ -415,7 +397,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir,
if (dir->i_mode & S_ISGID) if (dir->i_mode & S_ISGID)
omode |= S_ISGID; omode |= S_ISGID;
dir_dentry = v9fs_dentry_from_dir_inode(dir); dir_dentry = dentry->d_parent;
dfid = v9fs_fid_lookup(dir_dentry); dfid = v9fs_fid_lookup(dir_dentry);
if (IS_ERR(dfid)) { if (IS_ERR(dfid)) {
err = PTR_ERR(dfid); err = PTR_ERR(dfid);
@ -793,7 +775,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
dir->i_ino, old_dentry->d_name.name, dentry->d_name.name); dir->i_ino, old_dentry->d_name.name, dentry->d_name.name);
v9ses = v9fs_inode2v9ses(dir); v9ses = v9fs_inode2v9ses(dir);
dir_dentry = v9fs_dentry_from_dir_inode(dir); dir_dentry = dentry->d_parent;
dfid = v9fs_fid_lookup(dir_dentry); dfid = v9fs_fid_lookup(dir_dentry);
if (IS_ERR(dfid)) if (IS_ERR(dfid))
return PTR_ERR(dfid); return PTR_ERR(dfid);
@ -858,7 +840,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
return -EINVAL; return -EINVAL;
v9ses = v9fs_inode2v9ses(dir); v9ses = v9fs_inode2v9ses(dir);
dir_dentry = v9fs_dentry_from_dir_inode(dir); dir_dentry = dentry->d_parent;
dfid = v9fs_fid_lookup(dir_dentry); dfid = v9fs_fid_lookup(dir_dentry);
if (IS_ERR(dfid)) { if (IS_ERR(dfid)) {
err = PTR_ERR(dfid); err = PTR_ERR(dfid);

View File

@ -18,14 +18,6 @@
#define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey]) #define AFFS_GET_HASHENTRY(data,hashkey) be32_to_cpu(((struct dir_front *)data)->hashtable[hashkey])
#define AFFS_BLOCK(sb, bh, blk) (AFFS_HEAD(bh)->table[AFFS_SB(sb)->s_hashsize-1-(blk)]) #define AFFS_BLOCK(sb, bh, blk) (AFFS_HEAD(bh)->table[AFFS_SB(sb)->s_hashsize-1-(blk)])
#ifdef __LITTLE_ENDIAN
#define BO_EXBITS 0x18UL
#elif defined(__BIG_ENDIAN)
#define BO_EXBITS 0x00UL
#else
#error Endianness must be known for affs to work.
#endif
#define AFFS_HEAD(bh) ((struct affs_head *)(bh)->b_data) #define AFFS_HEAD(bh) ((struct affs_head *)(bh)->b_data)
#define AFFS_TAIL(sb, bh) ((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail))) #define AFFS_TAIL(sb, bh) ((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail)))
#define AFFS_ROOT_HEAD(bh) ((struct affs_root_head *)(bh)->b_data) #define AFFS_ROOT_HEAD(bh) ((struct affs_root_head *)(bh)->b_data)

View File

@ -134,9 +134,9 @@ static int aio_setup_ring(struct kioctx *ctx)
info->mmap_size = nr_pages * PAGE_SIZE; info->mmap_size = nr_pages * PAGE_SIZE;
dprintk("attempting mmap of %lu bytes\n", info->mmap_size); dprintk("attempting mmap of %lu bytes\n", info->mmap_size);
down_write(&ctx->mm->mmap_sem); down_write(&ctx->mm->mmap_sem);
info->mmap_base = do_mmap(NULL, 0, info->mmap_size, info->mmap_base = do_mmap_pgoff(NULL, 0, info->mmap_size,
PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, PROT_READ|PROT_WRITE,
0); MAP_ANONYMOUS|MAP_PRIVATE, 0);
if (IS_ERR((void *)info->mmap_base)) { if (IS_ERR((void *)info->mmap_base)) {
up_write(&ctx->mm->mmap_sem); up_write(&ctx->mm->mmap_sem);
info->mmap_size = 0; info->mmap_size = 0;

View File

@ -176,6 +176,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
return -EPERM; return -EPERM;
} }
if ((ia_valid & ATTR_SIZE) && IS_I_VERSION(inode)) {
if (attr->ia_size != inode->i_size)
inode_inc_iversion(inode);
}
if ((ia_valid & ATTR_MODE)) { if ((ia_valid & ATTR_MODE)) {
umode_t amode = attr->ia_mode; umode_t amode = attr->ia_mode;
/* Flag setting protected by i_mutex */ /* Flag setting protected by i_mutex */

View File

@ -329,7 +329,6 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
if (!size) if (!size)
return addr; return addr;
down_write(&current->mm->mmap_sem);
/* /*
* total_size is the size of the ELF (interpreter) image. * total_size is the size of the ELF (interpreter) image.
* The _first_ mmap needs to know the full size, otherwise * The _first_ mmap needs to know the full size, otherwise
@ -340,13 +339,12 @@ static unsigned long elf_map(struct file *filep, unsigned long addr,
*/ */
if (total_size) { if (total_size) {
total_size = ELF_PAGEALIGN(total_size); total_size = ELF_PAGEALIGN(total_size);
map_addr = do_mmap(filep, addr, total_size, prot, type, off); map_addr = vm_mmap(filep, addr, total_size, prot, type, off);
if (!BAD_ADDR(map_addr)) if (!BAD_ADDR(map_addr))
do_munmap(current->mm, map_addr+size, total_size-size); vm_munmap(map_addr+size, total_size-size);
} else } else
map_addr = do_mmap(filep, addr, size, prot, type, off); map_addr = vm_mmap(filep, addr, size, prot, type, off);
up_write(&current->mm->mmap_sem);
return(map_addr); return(map_addr);
} }

View File

@ -562,7 +562,7 @@ static int load_flat_file(struct linux_binprm * bprm,
realdatastart = (unsigned long) -ENOMEM; realdatastart = (unsigned long) -ENOMEM;
printk("Unable to allocate RAM for process data, errno %d\n", printk("Unable to allocate RAM for process data, errno %d\n",
(int)-realdatastart); (int)-realdatastart);
do_munmap(current->mm, textpos, text_len); vm_munmap(textpos, text_len);
ret = realdatastart; ret = realdatastart;
goto err; goto err;
} }
@ -586,8 +586,8 @@ static int load_flat_file(struct linux_binprm * bprm,
} }
if (IS_ERR_VALUE(result)) { if (IS_ERR_VALUE(result)) {
printk("Unable to read data+bss, errno %d\n", (int)-result); printk("Unable to read data+bss, errno %d\n", (int)-result);
do_munmap(current->mm, textpos, text_len); vm_munmap(textpos, text_len);
do_munmap(current->mm, realdatastart, len); vm_munmap(realdatastart, len);
ret = result; ret = result;
goto err; goto err;
} }
@ -654,7 +654,7 @@ static int load_flat_file(struct linux_binprm * bprm,
} }
if (IS_ERR_VALUE(result)) { if (IS_ERR_VALUE(result)) {
printk("Unable to read code+data+bss, errno %d\n",(int)-result); printk("Unable to read code+data+bss, errno %d\n",(int)-result);
do_munmap(current->mm, textpos, text_len + data_len + extra + vm_munmap(textpos, text_len + data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long)); MAX_SHARED_LIBS * sizeof(unsigned long));
ret = result; ret = result;
goto err; goto err;

View File

@ -2974,7 +2974,6 @@ int btrfs_readpage(struct file *file, struct page *page);
void btrfs_evict_inode(struct inode *inode); void btrfs_evict_inode(struct inode *inode);
int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc); int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc);
int btrfs_dirty_inode(struct inode *inode); int btrfs_dirty_inode(struct inode *inode);
int btrfs_update_time(struct file *file);
struct inode *btrfs_alloc_inode(struct super_block *sb); struct inode *btrfs_alloc_inode(struct super_block *sb);
void btrfs_destroy_inode(struct inode *inode); void btrfs_destroy_inode(struct inode *inode);
int btrfs_drop_inode(struct inode *inode); int btrfs_drop_inode(struct inode *inode);

View File

@ -13,15 +13,14 @@
parent_root_objectid) / 4) parent_root_objectid) / 4)
#define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4) #define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4)
static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
int connectable) struct inode *parent)
{ {
struct btrfs_fid *fid = (struct btrfs_fid *)fh; struct btrfs_fid *fid = (struct btrfs_fid *)fh;
struct inode *inode = dentry->d_inode;
int len = *max_len; int len = *max_len;
int type; int type;
if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) { if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
*max_len = BTRFS_FID_SIZE_CONNECTABLE; *max_len = BTRFS_FID_SIZE_CONNECTABLE;
return 255; return 255;
} else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
@ -36,19 +35,13 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
fid->root_objectid = BTRFS_I(inode)->root->objectid; fid->root_objectid = BTRFS_I(inode)->root->objectid;
fid->gen = inode->i_generation; fid->gen = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) { if (parent) {
struct inode *parent;
u64 parent_root_id; u64 parent_root_id;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_objectid = BTRFS_I(parent)->location.objectid;
fid->parent_gen = parent->i_generation; fid->parent_gen = parent->i_generation;
parent_root_id = BTRFS_I(parent)->root->objectid; parent_root_id = BTRFS_I(parent)->root->objectid;
spin_unlock(&dentry->d_lock);
if (parent_root_id != fid->root_objectid) { if (parent_root_id != fid->root_objectid) {
fid->parent_root_objectid = parent_root_id; fid->parent_root_objectid = parent_root_id;
len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; len = BTRFS_FID_SIZE_CONNECTABLE_ROOT;

View File

@ -1433,7 +1433,7 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
goto out; goto out;
} }
err = btrfs_update_time(file); err = file_update_time(file);
if (err) { if (err) {
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
goto out; goto out;

View File

@ -77,7 +77,8 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
inode->i_mapping->flags &= ~__GFP_FS; mapping_set_gfp_mask(inode->i_mapping,
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
return inode; return inode;
} }
@ -367,7 +368,7 @@ static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct inode *inode,
static void io_ctl_set_generation(struct io_ctl *io_ctl, u64 generation) static void io_ctl_set_generation(struct io_ctl *io_ctl, u64 generation)
{ {
u64 *val; __le64 *val;
io_ctl_map_page(io_ctl, 1); io_ctl_map_page(io_ctl, 1);
@ -390,7 +391,7 @@ static void io_ctl_set_generation(struct io_ctl *io_ctl, u64 generation)
static int io_ctl_check_generation(struct io_ctl *io_ctl, u64 generation) static int io_ctl_check_generation(struct io_ctl *io_ctl, u64 generation)
{ {
u64 *gen; __le64 *gen;
/* /*
* Skip the crc area. If we don't check crcs then we just have a 64bit * Skip the crc area. If we don't check crcs then we just have a 64bit

View File

@ -4475,46 +4475,18 @@ int btrfs_dirty_inode(struct inode *inode)
* This is a copy of file_update_time. We need this so we can return error on * This is a copy of file_update_time. We need this so we can return error on
* ENOSPC for updating the inode in the case of file write and mmap writes. * ENOSPC for updating the inode in the case of file write and mmap writes.
*/ */
int btrfs_update_time(struct file *file) static int btrfs_update_time(struct inode *inode, struct timespec *now,
int flags)
{ {
struct inode *inode = file->f_path.dentry->d_inode; if (flags & S_VERSION)
struct timespec now;
int ret;
enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0;
/* First try to exhaust all avenues to not sync */
if (IS_NOCMTIME(inode))
return 0;
now = current_fs_time(inode->i_sb);
if (!timespec_equal(&inode->i_mtime, &now))
sync_it = S_MTIME;
if (!timespec_equal(&inode->i_ctime, &now))
sync_it |= S_CTIME;
if (IS_I_VERSION(inode))
sync_it |= S_VERSION;
if (!sync_it)
return 0;
/* Finally allowed to write? Takes lock. */
if (mnt_want_write_file(file))
return 0;
/* Only change inode inside the lock region */
if (sync_it & S_VERSION)
inode_inc_iversion(inode); inode_inc_iversion(inode);
if (sync_it & S_CTIME) if (flags & S_CTIME)
inode->i_ctime = now; inode->i_ctime = *now;
if (sync_it & S_MTIME) if (flags & S_MTIME)
inode->i_mtime = now; inode->i_mtime = *now;
ret = btrfs_dirty_inode(inode); if (flags & S_ATIME)
if (!ret) inode->i_atime = *now;
mark_inode_dirty_sync(inode); return btrfs_dirty_inode(inode);
mnt_drop_write(file->f_path.mnt);
return ret;
} }
/* /*
@ -6565,7 +6537,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
if (!ret) { if (!ret) {
ret = btrfs_update_time(vma->vm_file); ret = file_update_time(vma->vm_file);
reserved = 1; reserved = 1;
} }
if (ret) { if (ret) {
@ -7635,6 +7607,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
.permission = btrfs_permission, .permission = btrfs_permission,
.fiemap = btrfs_fiemap, .fiemap = btrfs_fiemap,
.get_acl = btrfs_get_acl, .get_acl = btrfs_get_acl,
.update_time = btrfs_update_time,
}; };
static const struct inode_operations btrfs_special_inode_operations = { static const struct inode_operations btrfs_special_inode_operations = {
.getattr = btrfs_getattr, .getattr = btrfs_getattr,
@ -7645,6 +7618,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.listxattr = btrfs_listxattr, .listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr, .removexattr = btrfs_removexattr,
.get_acl = btrfs_get_acl, .get_acl = btrfs_get_acl,
.update_time = btrfs_update_time,
}; };
static const struct inode_operations btrfs_symlink_inode_operations = { static const struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink, .readlink = generic_readlink,
@ -7658,6 +7632,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
.listxattr = btrfs_listxattr, .listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr, .removexattr = btrfs_removexattr,
.get_acl = btrfs_get_acl, .get_acl = btrfs_get_acl,
.update_time = btrfs_update_time,
}; };
const struct dentry_operations btrfs_dentry_operations = { const struct dentry_operations btrfs_dentry_operations = {

View File

@ -3152,7 +3152,7 @@ SYSCALL_DEFINE2(bdflush, int, func, long, data)
/* /*
* Buffer-head allocation * Buffer-head allocation
*/ */
static struct kmem_cache *bh_cachep; static struct kmem_cache *bh_cachep __read_mostly;
/* /*
* Once the number of bh's in the machine exceeds this level, we start * Once the number of bh's in the machine exceeds this level, we start

View File

@ -40,38 +40,49 @@ struct ceph_nfs_confh {
u32 parent_name_hash; u32 parent_name_hash;
} __attribute__ ((packed)); } __attribute__ ((packed));
static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len, /*
int connectable) * The presence of @parent_inode here tells us whether NFS wants a
* connectable file handle. However, we want to make a connectionable
* file handle unconditionally so that the MDS gets as much of a hint
* as possible. That means we only use @parent_dentry to indicate
* whether nfsd wants a connectable fh, and whether we should indicate
* failure from a too-small @max_len.
*/
static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
struct inode *parent_inode)
{ {
int type; int type;
struct ceph_nfs_fh *fh = (void *)rawfh; struct ceph_nfs_fh *fh = (void *)rawfh;
struct ceph_nfs_confh *cfh = (void *)rawfh; struct ceph_nfs_confh *cfh = (void *)rawfh;
struct dentry *parent;
struct inode *inode = dentry->d_inode;
int connected_handle_length = sizeof(*cfh)/4; int connected_handle_length = sizeof(*cfh)/4;
int handle_length = sizeof(*fh)/4; int handle_length = sizeof(*fh)/4;
struct dentry *dentry = d_find_alias(inode);
struct dentry *parent;
/* don't re-export snaps */ /* don't re-export snaps */
if (ceph_snap(inode) != CEPH_NOSNAP) if (ceph_snap(inode) != CEPH_NOSNAP)
return -EINVAL; return -EINVAL;
spin_lock(&dentry->d_lock); /* if we found an alias, generate a connectable fh */
parent = dentry->d_parent; if (*max_len >= connected_handle_length && dentry) {
if (*max_len >= connected_handle_length) {
dout("encode_fh %p connectable\n", dentry); dout("encode_fh %p connectable\n", dentry);
cfh->ino = ceph_ino(dentry->d_inode); spin_lock(&dentry->d_lock);
parent = dentry->d_parent;
cfh->ino = ceph_ino(inode);
cfh->parent_ino = ceph_ino(parent->d_inode); cfh->parent_ino = ceph_ino(parent->d_inode);
cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode, cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
dentry); dentry);
*max_len = connected_handle_length; *max_len = connected_handle_length;
type = 2; type = 2;
spin_unlock(&dentry->d_lock);
} else if (*max_len >= handle_length) { } else if (*max_len >= handle_length) {
if (connectable) { if (parent_inode) {
/* nfsd wants connectable */
*max_len = connected_handle_length; *max_len = connected_handle_length;
type = 255; type = 255;
} else { } else {
dout("encode_fh %p\n", dentry); dout("encode_fh %p\n", dentry);
fh->ino = ceph_ino(dentry->d_inode); fh->ino = ceph_ino(inode);
*max_len = handle_length; *max_len = handle_length;
type = 1; type = 1;
} }
@ -79,7 +90,6 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
*max_len = handle_length; *max_len = handle_length;
type = 255; type = 255;
} }
spin_unlock(&dentry->d_lock);
return type; return type;
} }

View File

@ -871,12 +871,12 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
{ {
int error; int error;
struct file *file; struct file *file;
int fput_needed;
struct compat_readdir_callback buf; struct compat_readdir_callback buf;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.result = 0; buf.result = 0;
buf.dirent = dirent; buf.dirent = dirent;
@ -885,8 +885,7 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
if (buf.result) if (buf.result)
error = buf.result; error = buf.result;
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }
@ -953,16 +952,15 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
struct file * file; struct file * file;
struct compat_linux_dirent __user * lastdirent; struct compat_linux_dirent __user * lastdirent;
struct compat_getdents_callback buf; struct compat_getdents_callback buf;
int fput_needed;
int error; int error;
error = -EFAULT;
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
goto out; return -EFAULT;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.current_dir = dirent; buf.current_dir = dirent;
buf.previous = NULL; buf.previous = NULL;
@ -979,8 +977,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }
@ -1041,16 +1038,15 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
struct file * file; struct file * file;
struct linux_dirent64 __user * lastdirent; struct linux_dirent64 __user * lastdirent;
struct compat_getdents_callback64 buf; struct compat_getdents_callback64 buf;
int fput_needed;
int error; int error;
error = -EFAULT;
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
goto out; return -EFAULT;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.current_dir = dirent; buf.current_dir = dirent;
buf.previous = NULL; buf.previous = NULL;
@ -1068,8 +1064,7 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }
#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */ #endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */

View File

@ -683,8 +683,6 @@ EXPORT_SYMBOL(dget_parent);
/** /**
* d_find_alias - grab a hashed alias of inode * d_find_alias - grab a hashed alias of inode
* @inode: inode in question * @inode: inode in question
* @want_discon: flag, used by d_splice_alias, to request
* that only a DISCONNECTED alias be returned.
* *
* If inode has a hashed alias, or is a directory and has any alias, * If inode has a hashed alias, or is a directory and has any alias,
* acquire the reference to alias and return it. Otherwise return NULL. * acquire the reference to alias and return it. Otherwise return NULL.
@ -693,10 +691,9 @@ EXPORT_SYMBOL(dget_parent);
* of a filesystem. * of a filesystem.
* *
* If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
* any other hashed alias over that one unless @want_discon is set, * any other hashed alias over that.
* in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
*/ */
static struct dentry *__d_find_alias(struct inode *inode, int want_discon) static struct dentry *__d_find_alias(struct inode *inode)
{ {
struct dentry *alias, *discon_alias; struct dentry *alias, *discon_alias;
@ -708,7 +705,7 @@ again:
if (IS_ROOT(alias) && if (IS_ROOT(alias) &&
(alias->d_flags & DCACHE_DISCONNECTED)) { (alias->d_flags & DCACHE_DISCONNECTED)) {
discon_alias = alias; discon_alias = alias;
} else if (!want_discon) { } else {
__dget_dlock(alias); __dget_dlock(alias);
spin_unlock(&alias->d_lock); spin_unlock(&alias->d_lock);
return alias; return alias;
@ -739,7 +736,7 @@ struct dentry *d_find_alias(struct inode *inode)
if (!list_empty(&inode->i_dentry)) { if (!list_empty(&inode->i_dentry)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
de = __d_find_alias(inode, 0); de = __d_find_alias(inode);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
return de; return de;
@ -1650,9 +1647,8 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
if (inode && S_ISDIR(inode->i_mode)) { if (inode && S_ISDIR(inode->i_mode)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
new = __d_find_alias(inode, 1); new = __d_find_any_alias(inode);
if (new) { if (new) {
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
security_d_instantiate(new, inode); security_d_instantiate(new, inode);
d_move(new, dentry); d_move(new, dentry);
@ -2482,7 +2478,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
struct dentry *alias; struct dentry *alias;
/* Does an aliased dentry already exist? */ /* Does an aliased dentry already exist? */
alias = __d_find_alias(inode, 0); alias = __d_find_alias(inode);
if (alias) { if (alias) {
actual = alias; actual = alias;
write_seqlock(&rename_lock); write_seqlock(&rename_lock);
@ -2575,7 +2571,7 @@ static int prepend_path(const struct path *path,
bool slash = false; bool slash = false;
int error = 0; int error = 0;
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
while (dentry != root->dentry || vfsmnt != root->mnt) { while (dentry != root->dentry || vfsmnt != root->mnt) {
struct dentry * parent; struct dentry * parent;
@ -2606,7 +2602,7 @@ static int prepend_path(const struct path *path,
error = prepend(buffer, buflen, "/", 1); error = prepend(buffer, buflen, "/", 1);
out: out:
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return error; return error;
global_root: global_root:

View File

@ -660,11 +660,10 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
{ {
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
char *lower_buf; char *lower_buf;
size_t lower_bufsiz = PATH_MAX;
mm_segment_t old_fs; mm_segment_t old_fs;
int rc; int rc;
lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); lower_buf = kmalloc(PATH_MAX, GFP_KERNEL);
if (!lower_buf) { if (!lower_buf) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
@ -673,58 +672,29 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
set_fs(get_ds()); set_fs(get_ds());
rc = lower_dentry->d_inode->i_op->readlink(lower_dentry, rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
(char __user *)lower_buf, (char __user *)lower_buf,
lower_bufsiz); PATH_MAX);
set_fs(old_fs); set_fs(old_fs);
if (rc < 0) if (rc < 0)
goto out; goto out;
lower_bufsiz = rc;
rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry, rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
lower_buf, lower_bufsiz); lower_buf, rc);
out: out:
kfree(lower_buf); kfree(lower_buf);
return rc; return rc;
} }
static int
ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
{
char *kbuf;
size_t kbufsiz, copied;
int rc;
rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz);
if (rc)
goto out;
copied = min_t(size_t, bufsiz, kbufsiz);
rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied;
kfree(kbuf);
fsstack_copy_attr_atime(dentry->d_inode,
ecryptfs_dentry_to_lower(dentry)->d_inode);
out:
return rc;
}
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd) static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
char *buf; char *buf;
int len = PAGE_SIZE, rc; size_t len = PATH_MAX;
mm_segment_t old_fs; int rc;
/* Released in ecryptfs_put_link(); only release here on error */ rc = ecryptfs_readlink_lower(dentry, &buf, &len);
buf = kmalloc(len, GFP_KERNEL); if (rc)
if (!buf) {
buf = ERR_PTR(-ENOMEM);
goto out; goto out;
} fsstack_copy_attr_atime(dentry->d_inode,
old_fs = get_fs(); ecryptfs_dentry_to_lower(dentry)->d_inode);
set_fs(get_ds()); buf[len] = '\0';
rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
set_fs(old_fs);
if (rc < 0) {
kfree(buf);
buf = ERR_PTR(rc);
} else
buf[rc] = '\0';
out: out:
nd_set_link(nd, buf); nd_set_link(nd, buf);
return NULL; return NULL;
@ -1153,7 +1123,7 @@ out:
} }
const struct inode_operations ecryptfs_symlink_iops = { const struct inode_operations ecryptfs_symlink_iops = {
.readlink = ecryptfs_readlink, .readlink = generic_readlink,
.follow_link = ecryptfs_follow_link, .follow_link = ecryptfs_follow_link,
.put_link = ecryptfs_put_link, .put_link = ecryptfs_put_link,
.permission = ecryptfs_permission, .permission = ecryptfs_permission,

View File

@ -280,10 +280,6 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
INIT_LIST_HEAD(&vma->anon_vma_chain); INIT_LIST_HEAD(&vma->anon_vma_chain);
err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1);
if (err)
goto err;
err = insert_vm_struct(mm, vma); err = insert_vm_struct(mm, vma);
if (err) if (err)
goto err; goto err;

View File

@ -304,24 +304,23 @@ out:
/** /**
* export_encode_fh - default export_operations->encode_fh function * export_encode_fh - default export_operations->encode_fh function
* @dentry: the dentry to encode * @inode: the object to encode
* @fh: where to store the file handle fragment * @fh: where to store the file handle fragment
* @max_len: maximum length to store there * @max_len: maximum length to store there
* @connectable: whether to store parent information * @parent: parent directory inode, if wanted
* *
* This default encode_fh function assumes that the 32 inode number * This default encode_fh function assumes that the 32 inode number
* is suitable for locating an inode, and that the generation number * is suitable for locating an inode, and that the generation number
* can be used to check that it is still valid. It places them in the * can be used to check that it is still valid. It places them in the
* filehandle fragment where export_decode_fh expects to find them. * filehandle fragment where export_decode_fh expects to find them.
*/ */
static int export_encode_fh(struct dentry *dentry, struct fid *fid, static int export_encode_fh(struct inode *inode, struct fid *fid,
int *max_len, int connectable) int *max_len, struct inode *parent)
{ {
struct inode * inode = dentry->d_inode;
int len = *max_len; int len = *max_len;
int type = FILEID_INO32_GEN; int type = FILEID_INO32_GEN;
if (connectable && (len < 4)) { if (parent && (len < 4)) {
*max_len = 4; *max_len = 4;
return 255; return 255;
} else if (len < 2) { } else if (len < 2) {
@ -332,14 +331,9 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid,
len = 2; len = 2;
fid->i32.ino = inode->i_ino; fid->i32.ino = inode->i_ino;
fid->i32.gen = inode->i_generation; fid->i32.gen = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) { if (parent) {
struct inode *parent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
fid->i32.parent_ino = parent->i_ino; fid->i32.parent_ino = parent->i_ino;
fid->i32.parent_gen = parent->i_generation; fid->i32.parent_gen = parent->i_generation;
spin_unlock(&dentry->d_lock);
len = 4; len = 4;
type = FILEID_INO32_GEN_PARENT; type = FILEID_INO32_GEN_PARENT;
} }
@ -352,11 +346,22 @@ int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
{ {
const struct export_operations *nop = dentry->d_sb->s_export_op; const struct export_operations *nop = dentry->d_sb->s_export_op;
int error; int error;
struct dentry *p = NULL;
struct inode *inode = dentry->d_inode, *parent = NULL;
if (connectable && !S_ISDIR(inode->i_mode)) {
p = dget_parent(dentry);
/*
* note that while p might've ceased to be our parent already,
* it's still pinned by and still positive.
*/
parent = p->d_inode;
}
if (nop->encode_fh) if (nop->encode_fh)
error = nop->encode_fh(dentry, fid->raw, max_len, connectable); error = nop->encode_fh(inode, fid->raw, max_len, parent);
else else
error = export_encode_fh(dentry, fid, max_len, connectable); error = export_encode_fh(inode, fid, max_len, parent);
dput(p);
return error; return error;
} }

View File

@ -735,10 +735,9 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb,
} }
static int static int
fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable) fat_encode_fh(struct inode *inode, __u32 *fh, int *lenp, struct inode *parent)
{ {
int len = *lenp; int len = *lenp;
struct inode *inode = de->d_inode;
u32 ipos_h, ipos_m, ipos_l; u32 ipos_h, ipos_m, ipos_l;
if (len < 5) { if (len < 5) {
@ -754,9 +753,9 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
fh[1] = inode->i_generation; fh[1] = inode->i_generation;
fh[2] = ipos_h; fh[2] = ipos_h;
fh[3] = ipos_m | MSDOS_I(inode)->i_logstart; fh[3] = ipos_m | MSDOS_I(inode)->i_logstart;
spin_lock(&de->d_lock); fh[4] = ipos_l;
fh[4] = ipos_l | MSDOS_I(de->d_parent->d_inode)->i_logstart; if (parent)
spin_unlock(&de->d_lock); fh[4] |= MSDOS_I(parent)->i_logstart;
return 3; return 3;
} }

View File

@ -442,28 +442,24 @@ static int check_fcntl_cmd(unsigned cmd)
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{ {
struct file *filp; struct file *filp;
int fput_needed;
long err = -EBADF; long err = -EBADF;
filp = fget_raw(fd); filp = fget_raw_light(fd, &fput_needed);
if (!filp) if (!filp)
goto out; goto out;
if (unlikely(filp->f_mode & FMODE_PATH)) { if (unlikely(filp->f_mode & FMODE_PATH)) {
if (!check_fcntl_cmd(cmd)) { if (!check_fcntl_cmd(cmd))
fput(filp); goto out1;
goto out;
}
} }
err = security_file_fcntl(filp, cmd, arg); err = security_file_fcntl(filp, cmd, arg);
if (err) { if (!err)
fput(filp); err = do_fcntl(fd, cmd, arg, filp);
return err;
}
err = do_fcntl(fd, cmd, arg, filp); out1:
fput_light(filp, fput_needed);
fput(filp);
out: out:
return err; return err;
} }
@ -473,26 +469,21 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
unsigned long, arg) unsigned long, arg)
{ {
struct file * filp; struct file * filp;
long err; long err = -EBADF;
int fput_needed;
err = -EBADF; filp = fget_raw_light(fd, &fput_needed);
filp = fget_raw(fd);
if (!filp) if (!filp)
goto out; goto out;
if (unlikely(filp->f_mode & FMODE_PATH)) { if (unlikely(filp->f_mode & FMODE_PATH)) {
if (!check_fcntl_cmd(cmd)) { if (!check_fcntl_cmd(cmd))
fput(filp); goto out1;
goto out;
}
} }
err = security_file_fcntl(filp, cmd, arg); err = security_file_fcntl(filp, cmd, arg);
if (err) { if (err)
fput(filp); goto out1;
return err;
}
err = -EBADF;
switch (cmd) { switch (cmd) {
case F_GETLK64: case F_GETLK64:
@ -507,7 +498,8 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
err = do_fcntl(fd, cmd, arg, filp); err = do_fcntl(fd, cmd, arg, filp);
break; break;
} }
fput(filp); out1:
fput_light(filp, fput_needed);
out: out:
return err; return err;
} }

View File

@ -34,7 +34,6 @@ struct files_stat_struct files_stat = {
.max_files = NR_FILE .max_files = NR_FILE
}; };
DECLARE_LGLOCK(files_lglock);
DEFINE_LGLOCK(files_lglock); DEFINE_LGLOCK(files_lglock);
/* SLAB cache for file structures */ /* SLAB cache for file structures */
@ -421,9 +420,9 @@ static inline void __file_sb_list_add(struct file *file, struct super_block *sb)
*/ */
void file_sb_list_add(struct file *file, struct super_block *sb) void file_sb_list_add(struct file *file, struct super_block *sb)
{ {
lg_local_lock(files_lglock); lg_local_lock(&files_lglock);
__file_sb_list_add(file, sb); __file_sb_list_add(file, sb);
lg_local_unlock(files_lglock); lg_local_unlock(&files_lglock);
} }
/** /**
@ -436,9 +435,9 @@ void file_sb_list_add(struct file *file, struct super_block *sb)
void file_sb_list_del(struct file *file) void file_sb_list_del(struct file *file)
{ {
if (!list_empty(&file->f_u.fu_list)) { if (!list_empty(&file->f_u.fu_list)) {
lg_local_lock_cpu(files_lglock, file_list_cpu(file)); lg_local_lock_cpu(&files_lglock, file_list_cpu(file));
list_del_init(&file->f_u.fu_list); list_del_init(&file->f_u.fu_list);
lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); lg_local_unlock_cpu(&files_lglock, file_list_cpu(file));
} }
} }
@ -485,7 +484,7 @@ void mark_files_ro(struct super_block *sb)
struct file *f; struct file *f;
retry: retry:
lg_global_lock(files_lglock); lg_global_lock(&files_lglock);
do_file_list_for_each_entry(sb, f) { do_file_list_for_each_entry(sb, f) {
struct vfsmount *mnt; struct vfsmount *mnt;
if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
@ -502,12 +501,12 @@ retry:
file_release_write(f); file_release_write(f);
mnt = mntget(f->f_path.mnt); mnt = mntget(f->f_path.mnt);
/* This can sleep, so we can't hold the spinlock. */ /* This can sleep, so we can't hold the spinlock. */
lg_global_unlock(files_lglock); lg_global_unlock(&files_lglock);
mnt_drop_write(mnt); mnt_drop_write(mnt);
mntput(mnt); mntput(mnt);
goto retry; goto retry;
} while_file_list_for_each_entry; } while_file_list_for_each_entry;
lg_global_unlock(files_lglock); lg_global_unlock(&files_lglock);
} }
void __init files_init(unsigned long mempages) void __init files_init(unsigned long mempages)
@ -525,6 +524,6 @@ void __init files_init(unsigned long mempages)
n = (mempages * (PAGE_SIZE / 1024)) / 10; n = (mempages * (PAGE_SIZE / 1024)) / 10;
files_stat.max_files = max_t(unsigned long, n, NR_FILE); files_stat.max_files = max_t(unsigned long, n, NR_FILE);
files_defer_init(); files_defer_init();
lg_lock_init(files_lglock); lg_lock_init(&files_lglock, "files_lglock");
percpu_counter_init(&nr_files, 0); percpu_counter_init(&nr_files, 0);
} }

View File

@ -962,7 +962,9 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (err) if (err)
goto out; goto out;
file_update_time(file); err = file_update_time(file);
if (err)
goto out;
if (file->f_flags & O_DIRECT) { if (file->f_flags & O_DIRECT) {
written = generic_file_direct_write(iocb, iov, &nr_segs, written = generic_file_direct_write(iocb, iov, &nr_segs,

View File

@ -627,12 +627,10 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
return ERR_PTR(err); return ERR_PTR(err);
} }
static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, static int fuse_encode_fh(struct inode *inode, u32 *fh, int *max_len,
int connectable) struct inode *parent)
{ {
struct inode *inode = dentry->d_inode; int len = parent ? 6 : 3;
bool encode_parent = connectable && !S_ISDIR(inode->i_mode);
int len = encode_parent ? 6 : 3;
u64 nodeid; u64 nodeid;
u32 generation; u32 generation;
@ -648,14 +646,9 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
fh[1] = (u32)(nodeid & 0xffffffff); fh[1] = (u32)(nodeid & 0xffffffff);
fh[2] = generation; fh[2] = generation;
if (encode_parent) { if (parent) {
struct inode *parent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
nodeid = get_fuse_inode(parent)->nodeid; nodeid = get_fuse_inode(parent)->nodeid;
generation = parent->i_generation; generation = parent->i_generation;
spin_unlock(&dentry->d_lock);
fh[3] = (u32)(nodeid >> 32); fh[3] = (u32)(nodeid >> 32);
fh[4] = (u32)(nodeid & 0xffffffff); fh[4] = (u32)(nodeid & 0xffffffff);
@ -663,7 +656,7 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
} }
*max_len = len; *max_len = len;
return encode_parent ? 0x82 : 0x81; return parent ? 0x82 : 0x81;
} }
static struct dentry *fuse_fh_to_dentry(struct super_block *sb, static struct dentry *fuse_fh_to_dentry(struct super_block *sb,

View File

@ -28,15 +28,14 @@
#define GFS2_LARGE_FH_SIZE 8 #define GFS2_LARGE_FH_SIZE 8
#define GFS2_OLD_FH_SIZE 10 #define GFS2_OLD_FH_SIZE 10
static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len, static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len,
int connectable) struct inode *parent)
{ {
__be32 *fh = (__force __be32 *)p; __be32 *fh = (__force __be32 *)p;
struct inode *inode = dentry->d_inode;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_inode *ip = GFS2_I(inode);
if (connectable && (*len < GFS2_LARGE_FH_SIZE)) { if (parent && (*len < GFS2_LARGE_FH_SIZE)) {
*len = GFS2_LARGE_FH_SIZE; *len = GFS2_LARGE_FH_SIZE;
return 255; return 255;
} else if (*len < GFS2_SMALL_FH_SIZE) { } else if (*len < GFS2_SMALL_FH_SIZE) {
@ -50,14 +49,10 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF); fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
*len = GFS2_SMALL_FH_SIZE; *len = GFS2_SMALL_FH_SIZE;
if (!connectable || inode == sb->s_root->d_inode) if (!parent || inode == sb->s_root->d_inode)
return *len; return *len;
spin_lock(&dentry->d_lock); ip = GFS2_I(parent);
inode = dentry->d_parent->d_inode;
ip = GFS2_I(inode);
igrab(inode);
spin_unlock(&dentry->d_lock);
fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32); fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF); fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
@ -65,8 +60,6 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF); fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
*len = GFS2_LARGE_FH_SIZE; *len = GFS2_LARGE_FH_SIZE;
iput(inode);
return *len; return *len;
} }

View File

@ -16,9 +16,9 @@
static int chk_if_allocated(struct super_block *s, secno sec, char *msg) static int chk_if_allocated(struct super_block *s, secno sec, char *msg)
{ {
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
u32 *bmp; __le32 *bmp;
if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail; if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail;
if ((cpu_to_le32(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f)) & 1) { if ((le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) >> (sec & 0x1f)) & 1) {
hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec); hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec);
goto fail1; goto fail1;
} }
@ -62,7 +62,7 @@ int hpfs_chk_sectors(struct super_block *s, secno start, int len, char *msg)
static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigned forward) static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigned forward)
{ {
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
unsigned *bmp; __le32 *bmp;
unsigned bs = near & ~0x3fff; unsigned bs = near & ~0x3fff;
unsigned nr = (near & 0x3fff) & ~(n - 1); unsigned nr = (near & 0x3fff) & ~(n - 1);
/*unsigned mnr;*/ /*unsigned mnr;*/
@ -236,7 +236,7 @@ static secno alloc_in_dirband(struct super_block *s, secno near)
int hpfs_alloc_if_possible(struct super_block *s, secno sec) int hpfs_alloc_if_possible(struct super_block *s, secno sec)
{ {
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
u32 *bmp; __le32 *bmp;
if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end; if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end;
if (le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) & (1 << (sec & 0x1f))) { if (le32_to_cpu(bmp[(sec & 0x3fff) >> 5]) & (1 << (sec & 0x1f))) {
bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f))); bmp[(sec & 0x3fff) >> 5] &= cpu_to_le32(~(1 << (sec & 0x1f)));
@ -254,7 +254,7 @@ int hpfs_alloc_if_possible(struct super_block *s, secno sec)
void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n)
{ {
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
u32 *bmp; __le32 *bmp;
struct hpfs_sb_info *sbi = hpfs_sb(s); struct hpfs_sb_info *sbi = hpfs_sb(s);
/*printk("2 - ");*/ /*printk("2 - ");*/
if (!n) return; if (!n) return;
@ -299,7 +299,7 @@ int hpfs_check_free_dnodes(struct super_block *s, int n)
int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14; int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14;
int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff; int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff;
int i, j; int i, j;
u32 *bmp; __le32 *bmp;
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) { if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
for (j = 0; j < 512; j++) { for (j = 0; j < 512; j++) {
@ -351,7 +351,7 @@ void hpfs_free_dnode(struct super_block *s, dnode_secno dno)
hpfs_free_sectors(s, dno, 4); hpfs_free_sectors(s, dno, 4);
} else { } else {
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
u32 *bmp; __le32 *bmp;
unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4; unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4;
if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) { if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) {
return; return;

View File

@ -20,7 +20,7 @@ secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
int c1, c2 = 0; int c1, c2 = 0;
go_down: go_down:
if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1; if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1;
if (btree->internal) { if (bp_internal(btree)) {
for (i = 0; i < btree->n_used_nodes; i++) for (i = 0; i < btree->n_used_nodes; i++)
if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) { if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) {
a = le32_to_cpu(btree->u.internal[i].down); a = le32_to_cpu(btree->u.internal[i].down);
@ -82,7 +82,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
brelse(bh); brelse(bh);
return -1; return -1;
} }
if (btree->internal) { if (bp_internal(btree)) {
a = le32_to_cpu(btree->u.internal[n].down); a = le32_to_cpu(btree->u.internal[n].down);
btree->u.internal[n].file_secno = cpu_to_le32(-1); btree->u.internal[n].file_secno = cpu_to_le32(-1);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
@ -129,12 +129,12 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
} }
if (a == node && fnod) { if (a == node && fnod) {
anode->up = cpu_to_le32(node); anode->up = cpu_to_le32(node);
anode->btree.fnode_parent = 1; anode->btree.flags |= BP_fnode_parent;
anode->btree.n_used_nodes = btree->n_used_nodes; anode->btree.n_used_nodes = btree->n_used_nodes;
anode->btree.first_free = btree->first_free; anode->btree.first_free = btree->first_free;
anode->btree.n_free_nodes = 40 - anode->btree.n_used_nodes; anode->btree.n_free_nodes = 40 - anode->btree.n_used_nodes;
memcpy(&anode->u, &btree->u, btree->n_used_nodes * 12); memcpy(&anode->u, &btree->u, btree->n_used_nodes * 12);
btree->internal = 1; btree->flags |= BP_internal;
btree->n_free_nodes = 11; btree->n_free_nodes = 11;
btree->n_used_nodes = 1; btree->n_used_nodes = 1;
btree->first_free = cpu_to_le16((char *)&(btree->u.internal[1]) - (char *)btree); btree->first_free = cpu_to_le16((char *)&(btree->u.internal[1]) - (char *)btree);
@ -184,7 +184,10 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
hpfs_free_sectors(s, ra, 1); hpfs_free_sectors(s, ra, 1);
if ((anode = hpfs_map_anode(s, na, &bh))) { if ((anode = hpfs_map_anode(s, na, &bh))) {
anode->up = cpu_to_le32(up); anode->up = cpu_to_le32(up);
anode->btree.fnode_parent = up == node && fnod; if (up == node && fnod)
anode->btree.flags |= BP_fnode_parent;
else
anode->btree.flags &= ~BP_fnode_parent;
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
} }
@ -198,7 +201,7 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) { if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) {
anode = new_anode; anode = new_anode;
/*anode->up = cpu_to_le32(up != -1 ? up : ra);*/ /*anode->up = cpu_to_le32(up != -1 ? up : ra);*/
anode->btree.internal = 1; anode->btree.flags |= BP_internal;
anode->btree.n_used_nodes = 1; anode->btree.n_used_nodes = 1;
anode->btree.n_free_nodes = 59; anode->btree.n_free_nodes = 59;
anode->btree.first_free = cpu_to_le16(16); anode->btree.first_free = cpu_to_le16(16);
@ -215,7 +218,8 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
} }
if ((anode = hpfs_map_anode(s, na, &bh))) { if ((anode = hpfs_map_anode(s, na, &bh))) {
anode->up = cpu_to_le32(node); anode->up = cpu_to_le32(node);
if (fnod) anode->btree.fnode_parent = 1; if (fnod)
anode->btree.flags |= BP_fnode_parent;
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
} }
@ -234,18 +238,19 @@ secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsi
} }
ranode->up = cpu_to_le32(node); ranode->up = cpu_to_le32(node);
memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free)); memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free));
if (fnod) ranode->btree.fnode_parent = 1; if (fnod)
ranode->btree.n_free_nodes = (ranode->btree.internal ? 60 : 40) - ranode->btree.n_used_nodes; ranode->btree.flags |= BP_fnode_parent;
if (ranode->btree.internal) for (n = 0; n < ranode->btree.n_used_nodes; n++) { ranode->btree.n_free_nodes = (bp_internal(&ranode->btree) ? 60 : 40) - ranode->btree.n_used_nodes;
if (bp_internal(&ranode->btree)) for (n = 0; n < ranode->btree.n_used_nodes; n++) {
struct anode *unode; struct anode *unode;
if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) { if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) {
unode->up = cpu_to_le32(ra); unode->up = cpu_to_le32(ra);
unode->btree.fnode_parent = 0; unode->btree.flags &= ~BP_fnode_parent;
mark_buffer_dirty(bh1); mark_buffer_dirty(bh1);
brelse(bh1); brelse(bh1);
} }
} }
btree->internal = 1; btree->flags |= BP_internal;
btree->n_free_nodes = fnod ? 10 : 58; btree->n_free_nodes = fnod ? 10 : 58;
btree->n_used_nodes = 2; btree->n_used_nodes = 2;
btree->first_free = cpu_to_le16((char *)&btree->u.internal[2] - (char *)btree); btree->first_free = cpu_to_le16((char *)&btree->u.internal[2] - (char *)btree);
@ -278,7 +283,7 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
int d1, d2; int d1, d2;
go_down: go_down:
d2 = 0; d2 = 0;
while (btree1->internal) { while (bp_internal(btree1)) {
ano = le32_to_cpu(btree1->u.internal[pos].down); ano = le32_to_cpu(btree1->u.internal[pos].down);
if (level) brelse(bh); if (level) brelse(bh);
if (hpfs_sb(s)->sb_chk) if (hpfs_sb(s)->sb_chk)
@ -412,13 +417,13 @@ void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
btree->n_free_nodes = 8; btree->n_free_nodes = 8;
btree->n_used_nodes = 0; btree->n_used_nodes = 0;
btree->first_free = cpu_to_le16(8); btree->first_free = cpu_to_le16(8);
btree->internal = 0; btree->flags &= ~BP_internal;
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
} else hpfs_free_sectors(s, f, 1); } else hpfs_free_sectors(s, f, 1);
brelse(bh); brelse(bh);
return; return;
} }
while (btree->internal) { while (bp_internal(btree)) {
nodes = btree->n_used_nodes + btree->n_free_nodes; nodes = btree->n_used_nodes + btree->n_free_nodes;
for (i = 0; i < btree->n_used_nodes; i++) for (i = 0; i < btree->n_used_nodes; i++)
if (le32_to_cpu(btree->u.internal[i].file_secno) >= secs) goto f; if (le32_to_cpu(btree->u.internal[i].file_secno) >= secs) goto f;
@ -479,13 +484,13 @@ void hpfs_remove_fnode(struct super_block *s, fnode_secno fno)
struct extended_attribute *ea; struct extended_attribute *ea;
struct extended_attribute *ea_end; struct extended_attribute *ea_end;
if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return; if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return;
if (!fnode->dirflag) hpfs_remove_btree(s, &fnode->btree); if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, &fnode->btree);
else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno)); else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno));
ea_end = fnode_end_ea(fnode); ea_end = fnode_end_ea(fnode);
for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
if (ea->indirect) if (ea_indirect(ea))
hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); hpfs_ea_remove(s, ea_sec(ea), ea_in_anode(ea), ea_len(ea));
hpfs_ea_ext_remove(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l)); hpfs_ea_ext_remove(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l));
brelse(bh); brelse(bh);
hpfs_free_sectors(s, fno, 1); hpfs_free_sectors(s, fno, 1);
} }

View File

@ -87,7 +87,7 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
ret = -EIOERROR; ret = -EIOERROR;
goto out; goto out;
} }
if (!fno->dirflag) { if (!fnode_is_dir(fno)) {
e = 1; e = 1;
hpfs_error(inode->i_sb, "not a directory, fnode %08lx", hpfs_error(inode->i_sb, "not a directory, fnode %08lx",
(unsigned long)inode->i_ino); (unsigned long)inode->i_ino);

View File

@ -153,7 +153,7 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno
} }
de->length = cpu_to_le16(36); de->length = cpu_to_le16(36);
de->down = 1; de->down = 1;
*(dnode_secno *)((char *)de + 32) = cpu_to_le32(ptr); *(__le32 *)((char *)de + 32) = cpu_to_le32(ptr);
} }
} }
@ -177,7 +177,7 @@ struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
memmove((char *)de + d_size, de, (char *)de_end - (char *)de); memmove((char *)de + d_size, de, (char *)de_end - (char *)de);
memset(de, 0, d_size); memset(de, 0, d_size);
if (down_ptr) { if (down_ptr) {
*(dnode_secno *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr); *(__le32 *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr);
de->down = 1; de->down = 1;
} }
de->length = cpu_to_le16(d_size); de->length = cpu_to_le16(d_size);
@ -656,7 +656,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
del->down = 0; del->down = 0;
d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4); d1->first_free = cpu_to_le32(le32_to_cpu(d1->first_free) - 4);
} else if (down) } else if (down)
*(dnode_secno *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down); *(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down);
} else goto endm; } else goto endm;
if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) { if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) {
printk("HPFS: out of memory for dtree balancing\n"); printk("HPFS: out of memory for dtree balancing\n");
@ -672,7 +672,7 @@ static void delete_empty_dnode(struct inode *i, dnode_secno dno)
de_prev->down = 1; de_prev->down = 1;
dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4); dnode->first_free = cpu_to_le32(le32_to_cpu(dnode->first_free) + 4);
} }
*(dnode_secno *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown); *(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown);
hpfs_mark_4buffers_dirty(&qbh); hpfs_mark_4buffers_dirty(&qbh);
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4); for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4);
@ -1015,7 +1015,7 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
kfree(name2); kfree(name2);
return NULL; return NULL;
} }
if (!upf->dirflag) { if (!fnode_is_dir(upf)) {
brelse(bh); brelse(bh);
hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up)); hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up));
kfree(name2); kfree(name2);

View File

@ -23,15 +23,15 @@ void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len)
return; return;
} }
if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return;
if (ea->indirect) { if (ea_indirect(ea)) {
if (ea_valuelen(ea) != 8) { if (ea_valuelen(ea) != 8) {
hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x", hpfs_error(s, "ea_indirect(ea) set while ea->valuelen!=8, %s %08x, pos %08x",
ano ? "anode" : "sectors", a, pos); ano ? "anode" : "sectors", a, pos);
return; return;
} }
if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 9, ex+4)) if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 9, ex+4))
return; return;
hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); hpfs_ea_remove(s, ea_sec(ea), ea_in_anode(ea), ea_len(ea));
} }
pos += ea->namelen + ea_valuelen(ea) + 5; pos += ea->namelen + ea_valuelen(ea) + 5;
} }
@ -81,7 +81,7 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
struct extended_attribute *ea_end = fnode_end_ea(fnode); struct extended_attribute *ea_end = fnode_end_ea(fnode);
for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) if (ea_indirect(ea))
goto indirect; goto indirect;
if (ea_valuelen(ea) >= size) if (ea_valuelen(ea) >= size)
return -EINVAL; return -EINVAL;
@ -91,7 +91,7 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
} }
a = le32_to_cpu(fnode->ea_secno); a = le32_to_cpu(fnode->ea_secno);
len = le32_to_cpu(fnode->ea_size_l); len = le32_to_cpu(fnode->ea_size_l);
ano = fnode->ea_anode; ano = fnode_in_anode(fnode);
pos = 0; pos = 0;
while (pos < len) { while (pos < len) {
ea = (struct extended_attribute *)ex; ea = (struct extended_attribute *)ex;
@ -101,10 +101,10 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
return -EIO; return -EIO;
} }
if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return -EIO; if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return -EIO;
if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4))
return -EIO; return -EIO;
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) if (ea_indirect(ea))
goto indirect; goto indirect;
if (ea_valuelen(ea) >= size) if (ea_valuelen(ea) >= size)
return -EINVAL; return -EINVAL;
@ -119,7 +119,7 @@ int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key,
indirect: indirect:
if (ea_len(ea) >= size) if (ea_len(ea) >= size)
return -EINVAL; return -EINVAL;
if (hpfs_ea_read(s, ea_sec(ea), ea->anode, 0, ea_len(ea), buf)) if (hpfs_ea_read(s, ea_sec(ea), ea_in_anode(ea), 0, ea_len(ea), buf))
return -EIO; return -EIO;
buf[ea_len(ea)] = 0; buf[ea_len(ea)] = 0;
return 0; return 0;
@ -136,8 +136,8 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
struct extended_attribute *ea_end = fnode_end_ea(fnode); struct extended_attribute *ea_end = fnode_end_ea(fnode);
for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) if (ea_indirect(ea))
return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); return get_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), *size = ea_len(ea));
if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) {
printk("HPFS: out of memory for EA\n"); printk("HPFS: out of memory for EA\n");
return NULL; return NULL;
@ -148,7 +148,7 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
} }
a = le32_to_cpu(fnode->ea_secno); a = le32_to_cpu(fnode->ea_secno);
len = le32_to_cpu(fnode->ea_size_l); len = le32_to_cpu(fnode->ea_size_l);
ano = fnode->ea_anode; ano = fnode_in_anode(fnode);
pos = 0; pos = 0;
while (pos < len) { while (pos < len) {
char ex[4 + 255 + 1 + 8]; char ex[4 + 255 + 1 + 8];
@ -159,11 +159,11 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
return NULL; return NULL;
} }
if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return NULL; if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return NULL;
if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4))
return NULL; return NULL;
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) if (ea_indirect(ea))
return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); return get_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), *size = ea_len(ea));
if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) { if (!(ret = kmalloc((*size = ea_valuelen(ea)) + 1, GFP_NOFS))) {
printk("HPFS: out of memory for EA\n"); printk("HPFS: out of memory for EA\n");
return NULL; return NULL;
@ -199,9 +199,9 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
struct extended_attribute *ea_end = fnode_end_ea(fnode); struct extended_attribute *ea_end = fnode_end_ea(fnode);
for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) { if (ea_indirect(ea)) {
if (ea_len(ea) == size) if (ea_len(ea) == size)
set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); set_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), data, size);
} else if (ea_valuelen(ea) == size) { } else if (ea_valuelen(ea) == size) {
memcpy(ea_data(ea), data, size); memcpy(ea_data(ea), data, size);
} }
@ -209,7 +209,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
} }
a = le32_to_cpu(fnode->ea_secno); a = le32_to_cpu(fnode->ea_secno);
len = le32_to_cpu(fnode->ea_size_l); len = le32_to_cpu(fnode->ea_size_l);
ano = fnode->ea_anode; ano = fnode_in_anode(fnode);
pos = 0; pos = 0;
while (pos < len) { while (pos < len) {
char ex[4 + 255 + 1 + 8]; char ex[4 + 255 + 1 + 8];
@ -220,12 +220,12 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
return; return;
} }
if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return;
if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea_indirect(ea) ? 8 : 0), ex + 4))
return; return;
if (!strcmp(ea->name, key)) { if (!strcmp(ea->name, key)) {
if (ea->indirect) { if (ea_indirect(ea)) {
if (ea_len(ea) == size) if (ea_len(ea) == size)
set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); set_indirect_ea(s, ea_in_anode(ea), ea_sec(ea), data, size);
} }
else { else {
if (ea_valuelen(ea) == size) if (ea_valuelen(ea) == size)
@ -246,7 +246,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
if (le16_to_cpu(fnode->ea_offs) < 0xc4 || le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200) { if (le16_to_cpu(fnode->ea_offs) < 0xc4 || le16_to_cpu(fnode->ea_offs) + le16_to_cpu(fnode->acl_size_s) + le16_to_cpu(fnode->ea_size_s) > 0x200) {
hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x", hpfs_error(s, "fnode %08lx: ea_offs == %03x, ea_size_s == %03x",
(unsigned long)inode->i_ino, (unsigned long)inode->i_ino,
le32_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s)); le16_to_cpu(fnode->ea_offs), le16_to_cpu(fnode->ea_size_s));
return; return;
} }
if ((le16_to_cpu(fnode->ea_size_s) || !le32_to_cpu(fnode->ea_size_l)) && if ((le16_to_cpu(fnode->ea_size_s) || !le32_to_cpu(fnode->ea_size_l)) &&
@ -276,7 +276,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
fnode->ea_size_l = cpu_to_le32(le16_to_cpu(fnode->ea_size_s)); fnode->ea_size_l = cpu_to_le32(le16_to_cpu(fnode->ea_size_s));
fnode->ea_size_s = cpu_to_le16(0); fnode->ea_size_s = cpu_to_le16(0);
fnode->ea_secno = cpu_to_le32(n); fnode->ea_secno = cpu_to_le32(n);
fnode->ea_anode = cpu_to_le32(0); fnode->flags &= ~FNODE_anode;
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
} }
@ -288,9 +288,9 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
secno q = hpfs_alloc_sector(s, fno, 1, 0); secno q = hpfs_alloc_sector(s, fno, 1, 0);
if (!q) goto bail; if (!q) goto bail;
fnode->ea_secno = cpu_to_le32(q); fnode->ea_secno = cpu_to_le32(q);
fnode->ea_anode = 0; fnode->flags &= ~FNODE_anode;
len++; len++;
} else if (!fnode->ea_anode) { } else if (!fnode_in_anode(fnode)) {
if (hpfs_alloc_if_possible(s, le32_to_cpu(fnode->ea_secno) + len)) { if (hpfs_alloc_if_possible(s, le32_to_cpu(fnode->ea_secno) + len)) {
len++; len++;
} else { } else {
@ -310,7 +310,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
anode->u.external[0].length = cpu_to_le32(len); anode->u.external[0].length = cpu_to_le32(len);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
fnode->ea_anode = 1; fnode->flags |= FNODE_anode;
fnode->ea_secno = cpu_to_le32(a_s);*/ fnode->ea_secno = cpu_to_le32(a_s);*/
secno new_sec; secno new_sec;
int i; int i;
@ -338,7 +338,7 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
len = (pos + 511) >> 9; len = (pos + 511) >> 9;
} }
} }
if (fnode->ea_anode) { if (fnode_in_anode(fnode)) {
if (hpfs_add_sector_to_btree(s, le32_to_cpu(fnode->ea_secno), if (hpfs_add_sector_to_btree(s, le32_to_cpu(fnode->ea_secno),
0, len) != -1) { 0, len) != -1) {
len++; len++;
@ -351,16 +351,16 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
h[1] = strlen(key); h[1] = strlen(key);
h[2] = size & 0xff; h[2] = size & 0xff;
h[3] = size >> 8; h[3] = size >> 8;
if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l), 4, h)) goto bail; if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l), 4, h)) goto bail;
if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 4, h[1] + 1, key)) goto bail; if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l) + 4, h[1] + 1, key)) goto bail;
if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode->ea_anode, le32_to_cpu(fnode->ea_size_l) + 5 + h[1], size, data)) goto bail; if (hpfs_ea_write(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l) + 5 + h[1], size, data)) goto bail;
fnode->ea_size_l = cpu_to_le32(pos); fnode->ea_size_l = cpu_to_le32(pos);
ret: ret:
hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size;
return; return;
bail: bail:
if (le32_to_cpu(fnode->ea_secno)) if (le32_to_cpu(fnode->ea_secno))
if (fnode->ea_anode) hpfs_truncate_btree(s, le32_to_cpu(fnode->ea_secno), 1, (le32_to_cpu(fnode->ea_size_l) + 511) >> 9); if (fnode_in_anode(fnode)) hpfs_truncate_btree(s, le32_to_cpu(fnode->ea_secno), 1, (le32_to_cpu(fnode->ea_size_l) + 511) >> 9);
else hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno) + ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9), len - ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9)); else hpfs_free_sectors(s, le32_to_cpu(fnode->ea_secno) + ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9), len - ((le32_to_cpu(fnode->ea_size_l) + 511) >> 9));
else fnode->ea_secno = fnode->ea_size_l = cpu_to_le32(0); else fnode->ea_secno = fnode->ea_size_l = cpu_to_le32(0);
} }

View File

@ -51,11 +51,11 @@ struct hpfs_boot_block
u8 n_rootdir_entries[2]; u8 n_rootdir_entries[2];
u8 n_sectors_s[2]; u8 n_sectors_s[2];
u8 media_byte; u8 media_byte;
u16 sectors_per_fat; __le16 sectors_per_fat;
u16 sectors_per_track; __le16 sectors_per_track;
u16 heads_per_cyl; __le16 heads_per_cyl;
u32 n_hidden_sectors; __le32 n_hidden_sectors;
u32 n_sectors_l; /* size of partition */ __le32 n_sectors_l; /* size of partition */
u8 drive_number; u8 drive_number;
u8 mbz; u8 mbz;
u8 sig_28h; /* 28h */ u8 sig_28h; /* 28h */
@ -63,7 +63,7 @@ struct hpfs_boot_block
u8 vol_label[11]; u8 vol_label[11];
u8 sig_hpfs[8]; /* "HPFS " */ u8 sig_hpfs[8]; /* "HPFS " */
u8 pad[448]; u8 pad[448];
u16 magic; /* aa55 */ __le16 magic; /* aa55 */
}; };
@ -75,28 +75,28 @@ struct hpfs_boot_block
struct hpfs_super_block struct hpfs_super_block
{ {
u32 magic; /* f995 e849 */ __le32 magic; /* f995 e849 */
u32 magic1; /* fa53 e9c5, more magic? */ __le32 magic1; /* fa53 e9c5, more magic? */
u8 version; /* version of a filesystem usually 2 */ u8 version; /* version of a filesystem usually 2 */
u8 funcversion; /* functional version - oldest version u8 funcversion; /* functional version - oldest version
of filesystem that can understand of filesystem that can understand
this disk */ this disk */
u16 zero; /* 0 */ __le16 zero; /* 0 */
fnode_secno root; /* fnode of root directory */ __le32 root; /* fnode of root directory */
secno n_sectors; /* size of filesystem */ __le32 n_sectors; /* size of filesystem */
u32 n_badblocks; /* number of bad blocks */ __le32 n_badblocks; /* number of bad blocks */
secno bitmaps; /* pointers to free space bit maps */ __le32 bitmaps; /* pointers to free space bit maps */
u32 zero1; /* 0 */ __le32 zero1; /* 0 */
secno badblocks; /* bad block list */ __le32 badblocks; /* bad block list */
u32 zero3; /* 0 */ __le32 zero3; /* 0 */
time32_t last_chkdsk; /* date last checked, 0 if never */ __le32 last_chkdsk; /* date last checked, 0 if never */
time32_t last_optimize; /* date last optimized, 0 if never */ __le32 last_optimize; /* date last optimized, 0 if never */
secno n_dir_band; /* number of sectors in dir band */ __le32 n_dir_band; /* number of sectors in dir band */
secno dir_band_start; /* first sector in dir band */ __le32 dir_band_start; /* first sector in dir band */
secno dir_band_end; /* last sector in dir band */ __le32 dir_band_end; /* last sector in dir band */
secno dir_band_bitmap; /* free space map, 1 dnode per bit */ __le32 dir_band_bitmap; /* free space map, 1 dnode per bit */
u8 volume_name[32]; /* not used */ u8 volume_name[32]; /* not used */
secno user_id_table; /* 8 preallocated sectors - user id */ __le32 user_id_table; /* 8 preallocated sectors - user id */
u32 zero6[103]; /* 0 */ u32 zero6[103]; /* 0 */
}; };
@ -109,8 +109,8 @@ struct hpfs_super_block
struct hpfs_spare_block struct hpfs_spare_block
{ {
u32 magic; /* f991 1849 */ __le32 magic; /* f991 1849 */
u32 magic1; /* fa52 29c5, more magic? */ __le32 magic1; /* fa52 29c5, more magic? */
#ifdef __LITTLE_ENDIAN #ifdef __LITTLE_ENDIAN
u8 dirty: 1; /* 0 clean, 1 "improperly stopped" */ u8 dirty: 1; /* 0 clean, 1 "improperly stopped" */
@ -153,21 +153,21 @@ struct hpfs_spare_block
u8 mm_contlgulty; u8 mm_contlgulty;
u8 unused; u8 unused;
secno hotfix_map; /* info about remapped bad sectors */ __le32 hotfix_map; /* info about remapped bad sectors */
u32 n_spares_used; /* number of hotfixes */ __le32 n_spares_used; /* number of hotfixes */
u32 n_spares; /* number of spares in hotfix map */ __le32 n_spares; /* number of spares in hotfix map */
u32 n_dnode_spares_free; /* spare dnodes unused */ __le32 n_dnode_spares_free; /* spare dnodes unused */
u32 n_dnode_spares; /* length of spare_dnodes[] list, __le32 n_dnode_spares; /* length of spare_dnodes[] list,
follows in this block*/ follows in this block*/
secno code_page_dir; /* code page directory block */ __le32 code_page_dir; /* code page directory block */
u32 n_code_pages; /* number of code pages */ __le32 n_code_pages; /* number of code pages */
u32 super_crc; /* on HPFS386 and LAN Server this is __le32 super_crc; /* on HPFS386 and LAN Server this is
checksum of superblock, on normal checksum of superblock, on normal
OS/2 unused */ OS/2 unused */
u32 spare_crc; /* on HPFS386 checksum of spareblock */ __le32 spare_crc; /* on HPFS386 checksum of spareblock */
u32 zero1[15]; /* unused */ __le32 zero1[15]; /* unused */
dnode_secno spare_dnodes[100]; /* emergency free dnode list */ __le32 spare_dnodes[100]; /* emergency free dnode list */
u32 zero2[1]; /* room for more? */ __le32 zero2[1]; /* room for more? */
}; };
/* The bad block list is 4 sectors long. The first word must be zero, /* The bad block list is 4 sectors long. The first word must be zero,
@ -202,18 +202,18 @@ struct hpfs_spare_block
struct code_page_directory struct code_page_directory
{ {
u32 magic; /* 4945 21f7 */ __le32 magic; /* 4945 21f7 */
u32 n_code_pages; /* number of pointers following */ __le32 n_code_pages; /* number of pointers following */
u32 zero1[2]; __le32 zero1[2];
struct { struct {
u16 ix; /* index */ __le16 ix; /* index */
u16 code_page_number; /* code page number */ __le16 code_page_number; /* code page number */
u32 bounds; /* matches corresponding word __le32 bounds; /* matches corresponding word
in data block */ in data block */
secno code_page_data; /* sector number of a code_page_data __le32 code_page_data; /* sector number of a code_page_data
containing c.p. array */ containing c.p. array */
u16 index; /* index in c.p. array in that sector*/ __le16 index; /* index in c.p. array in that sector*/
u16 unknown; /* some unknown value; usually 0; __le16 unknown; /* some unknown value; usually 0;
2 in Japanese version */ 2 in Japanese version */
} array[31]; /* unknown length */ } array[31]; /* unknown length */
}; };
@ -224,19 +224,19 @@ struct code_page_directory
struct code_page_data struct code_page_data
{ {
u32 magic; /* 8945 21f7 */ __le32 magic; /* 8945 21f7 */
u32 n_used; /* # elements used in c_p_data[] */ __le32 n_used; /* # elements used in c_p_data[] */
u32 bounds[3]; /* looks a bit like __le32 bounds[3]; /* looks a bit like
(beg1,end1), (beg2,end2) (beg1,end1), (beg2,end2)
one byte each */ one byte each */
u16 offs[3]; /* offsets from start of sector __le16 offs[3]; /* offsets from start of sector
to start of c_p_data[ix] */ to start of c_p_data[ix] */
struct { struct {
u16 ix; /* index */ __le16 ix; /* index */
u16 code_page_number; /* code page number */ __le16 code_page_number; /* code page number */
u16 unknown; /* the same as in cp directory */ __le16 unknown; /* the same as in cp directory */
u8 map[128]; /* upcase table for chars 80..ff */ u8 map[128]; /* upcase table for chars 80..ff */
u16 zero2; __le16 zero2;
} code_page[3]; } code_page[3];
u8 incognita[78]; u8 incognita[78];
}; };
@ -278,8 +278,8 @@ struct code_page_data
#define DNODE_MAGIC 0x77e40aae #define DNODE_MAGIC 0x77e40aae
struct dnode { struct dnode {
u32 magic; /* 77e4 0aae */ __le32 magic; /* 77e4 0aae */
u32 first_free; /* offset from start of dnode to __le32 first_free; /* offset from start of dnode to
first free dir entry */ first free dir entry */
#ifdef __LITTLE_ENDIAN #ifdef __LITTLE_ENDIAN
u8 root_dnode: 1; /* Is it root dnode? */ u8 root_dnode: 1; /* Is it root dnode? */
@ -293,14 +293,14 @@ struct dnode {
u8 root_dnode: 1; /* Is it root dnode? */ u8 root_dnode: 1; /* Is it root dnode? */
#endif #endif
u8 increment_me2[3]; u8 increment_me2[3];
secno up; /* (root dnode) directory's fnode __le32 up; /* (root dnode) directory's fnode
(nonroot) parent dnode */ (nonroot) parent dnode */
dnode_secno self; /* pointer to this dnode */ __le32 self; /* pointer to this dnode */
u8 dirent[2028]; /* one or more dirents */ u8 dirent[2028]; /* one or more dirents */
}; };
struct hpfs_dirent { struct hpfs_dirent {
u16 length; /* offset to next dirent */ __le16 length; /* offset to next dirent */
#ifdef __LITTLE_ENDIAN #ifdef __LITTLE_ENDIAN
u8 first: 1; /* set on phony ^A^A (".") entry */ u8 first: 1; /* set on phony ^A^A (".") entry */
@ -346,12 +346,12 @@ struct hpfs_dirent {
u8 read_only: 1; /* dos attrib */ u8 read_only: 1; /* dos attrib */
#endif #endif
fnode_secno fnode; /* fnode giving allocation info */ __le32 fnode; /* fnode giving allocation info */
time32_t write_date; /* mtime */ __le32 write_date; /* mtime */
u32 file_size; /* file length, bytes */ __le32 file_size; /* file length, bytes */
time32_t read_date; /* atime */ __le32 read_date; /* atime */
time32_t creation_date; /* ctime */ __le32 creation_date; /* ctime */
u32 ea_size; /* total EA length, bytes */ __le32 ea_size; /* total EA length, bytes */
u8 no_of_acls; /* number of ACL's (low 3 bits) */ u8 no_of_acls; /* number of ACL's (low 3 bits) */
u8 ix; /* code page index (of filename), see u8 ix; /* code page index (of filename), see
struct code_page_data */ struct code_page_data */
@ -375,50 +375,36 @@ struct hpfs_dirent {
struct bplus_leaf_node struct bplus_leaf_node
{ {
u32 file_secno; /* first file sector in extent */ __le32 file_secno; /* first file sector in extent */
u32 length; /* length, sectors */ __le32 length; /* length, sectors */
secno disk_secno; /* first corresponding disk sector */ __le32 disk_secno; /* first corresponding disk sector */
}; };
struct bplus_internal_node struct bplus_internal_node
{ {
u32 file_secno; /* subtree maps sectors < this */ __le32 file_secno; /* subtree maps sectors < this */
anode_secno down; /* pointer to subtree */ __le32 down; /* pointer to subtree */
}; };
enum {
BP_hbff = 1,
BP_fnode_parent = 0x20,
BP_binary_search = 0x40,
BP_internal = 0x80
};
struct bplus_header struct bplus_header
{ {
#ifdef __LITTLE_ENDIAN u8 flags; /* bit 0 - high bit of first free entry offset
u8 hbff: 1; /* high bit of first free entry offset */ bit 5 - we're pointed to by an fnode,
u8 flag1234: 4;
u8 fnode_parent: 1; /* ? we're pointed to by an fnode,
the data btree or some ea or the the data btree or some ea or the
main ea bootage pointer ea_secno */ main ea bootage pointer ea_secno
/* also can get set in fnodes, which bit 6 - suggest binary search (unused)
may be a chkdsk glitch or may mean bit 7 - 1 -> (internal) tree of anodes
this bit is irrelevant in fnodes, 0 -> (leaf) list of extents */
or this interpretation is all wet */
u8 binary_search: 1; /* suggest binary search (unused) */
u8 internal: 1; /* 1 -> (internal) tree of anodes
0 -> (leaf) list of extents */
#else
u8 internal: 1; /* 1 -> (internal) tree of anodes
0 -> (leaf) list of extents */
u8 binary_search: 1; /* suggest binary search (unused) */
u8 fnode_parent: 1; /* ? we're pointed to by an fnode,
the data btree or some ea or the
main ea bootage pointer ea_secno */
/* also can get set in fnodes, which
may be a chkdsk glitch or may mean
this bit is irrelevant in fnodes,
or this interpretation is all wet */
u8 flag1234: 4;
u8 hbff: 1; /* high bit of first free entry offset */
#endif
u8 fill[3]; u8 fill[3];
u8 n_free_nodes; /* free nodes in following array */ u8 n_free_nodes; /* free nodes in following array */
u8 n_used_nodes; /* used nodes in following array */ u8 n_used_nodes; /* used nodes in following array */
u16 first_free; /* offset from start of header to __le16 first_free; /* offset from start of header to
first free node in array */ first free node in array */
union { union {
struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving
@ -428,6 +414,16 @@ struct bplus_header
} u; } u;
}; };
static inline bool bp_internal(struct bplus_header *bp)
{
return bp->flags & BP_internal;
}
static inline bool bp_fnode_parent(struct bplus_header *bp)
{
return bp->flags & BP_fnode_parent;
}
/* fnode: root of allocation b+ tree, and EA's */ /* fnode: root of allocation b+ tree, and EA's */
/* Every file and every directory has one fnode, pointed to by the directory /* Every file and every directory has one fnode, pointed to by the directory
@ -436,62 +432,56 @@ struct bplus_header
#define FNODE_MAGIC 0xf7e40aae #define FNODE_MAGIC 0xf7e40aae
enum {FNODE_anode = cpu_to_le16(2), FNODE_dir = cpu_to_le16(256)};
struct fnode struct fnode
{ {
u32 magic; /* f7e4 0aae */ __le32 magic; /* f7e4 0aae */
u32 zero1[2]; /* read history */ __le32 zero1[2]; /* read history */
u8 len, name[15]; /* true length, truncated name */ u8 len, name[15]; /* true length, truncated name */
fnode_secno up; /* pointer to file's directory fnode */ __le32 up; /* pointer to file's directory fnode */
secno acl_size_l; __le32 acl_size_l;
secno acl_secno; __le32 acl_secno;
u16 acl_size_s; __le16 acl_size_s;
u8 acl_anode; u8 acl_anode;
u8 zero2; /* history bit count */ u8 zero2; /* history bit count */
u32 ea_size_l; /* length of disk-resident ea's */ __le32 ea_size_l; /* length of disk-resident ea's */
secno ea_secno; /* first sector of disk-resident ea's*/ __le32 ea_secno; /* first sector of disk-resident ea's*/
u16 ea_size_s; /* length of fnode-resident ea's */ __le16 ea_size_s; /* length of fnode-resident ea's */
#ifdef __LITTLE_ENDIAN __le16 flags; /* bit 1 set -> ea_secno is an anode */
u8 flag0: 1; /* bit 8 set -> directory. first & only extent
u8 ea_anode: 1; /* 1 -> ea_secno is an anode */
u8 flag234567: 6;
#else
u8 flag234567: 6;
u8 ea_anode: 1; /* 1 -> ea_secno is an anode */
u8 flag0: 1;
#endif
#ifdef __LITTLE_ENDIAN
u8 dirflag: 1; /* 1 -> directory. first & only extent
points to dnode. */ points to dnode. */
u8 flag9012345: 7;
#else
u8 flag9012345: 7;
u8 dirflag: 1; /* 1 -> directory. first & only extent
points to dnode. */
#endif
struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */ struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */
union { union {
struct bplus_leaf_node external[8]; struct bplus_leaf_node external[8];
struct bplus_internal_node internal[12]; struct bplus_internal_node internal[12];
} u; } u;
u32 file_size; /* file length, bytes */ __le32 file_size; /* file length, bytes */
u32 n_needea; /* number of EA's with NEEDEA set */ __le32 n_needea; /* number of EA's with NEEDEA set */
u8 user_id[16]; /* unused */ u8 user_id[16]; /* unused */
u16 ea_offs; /* offset from start of fnode __le16 ea_offs; /* offset from start of fnode
to first fnode-resident ea */ to first fnode-resident ea */
u8 dasd_limit_treshhold; u8 dasd_limit_treshhold;
u8 dasd_limit_delta; u8 dasd_limit_delta;
u32 dasd_limit; __le32 dasd_limit;
u32 dasd_usage; __le32 dasd_usage;
u8 ea[316]; /* zero or more EA's, packed together u8 ea[316]; /* zero or more EA's, packed together
with no alignment padding. with no alignment padding.
(Do not use this name, get here (Do not use this name, get here
via fnode + ea_offs. I think.) */ via fnode + ea_offs. I think.) */
}; };
static inline bool fnode_in_anode(struct fnode *p)
{
return (p->flags & FNODE_anode) != 0;
}
static inline bool fnode_is_dir(struct fnode *p)
{
return (p->flags & FNODE_dir) != 0;
}
/* anode: 99.44% pure allocation tree */ /* anode: 99.44% pure allocation tree */
@ -499,9 +489,9 @@ struct fnode
struct anode struct anode
{ {
u32 magic; /* 37e4 0aae */ __le32 magic; /* 37e4 0aae */
anode_secno self; /* pointer to this anode */ __le32 self; /* pointer to this anode */
secno up; /* parent anode or fnode */ __le32 up; /* parent anode or fnode */
struct bplus_header btree; /* b+tree, 40 extents or 60 subtrees */ struct bplus_header btree; /* b+tree, 40 extents or 60 subtrees */
union { union {
@ -509,7 +499,7 @@ struct anode
struct bplus_internal_node internal[60]; struct bplus_internal_node internal[60];
} u; } u;
u32 fill[3]; /* unused */ __le32 fill[3]; /* unused */
}; };
@ -528,32 +518,23 @@ struct anode
run, or in multiple runs. Flags in the fnode tell whether the EA list run, or in multiple runs. Flags in the fnode tell whether the EA list
is immediate, in a single run, or in multiple runs. */ is immediate, in a single run, or in multiple runs. */
enum {EA_indirect = 1, EA_anode = 2, EA_needea = 128 };
struct extended_attribute struct extended_attribute
{ {
#ifdef __LITTLE_ENDIAN u8 flags; /* bit 0 set -> value gives sector number
u8 indirect: 1; /* 1 -> value gives sector number
where real value starts */ where real value starts */
u8 anode: 1; /* 1 -> sector is an anode /* bit 1 set -> sector is an anode
that points to fragmented value */ that points to fragmented value */
u8 flag23456: 5; /* bit 7 set -> required ea */
u8 needea: 1; /* required ea */
#else
u8 needea: 1; /* required ea */
u8 flag23456: 5;
u8 anode: 1; /* 1 -> sector is an anode
that points to fragmented value */
u8 indirect: 1; /* 1 -> value gives sector number
where real value starts */
#endif
u8 namelen; /* length of name, bytes */ u8 namelen; /* length of name, bytes */
u8 valuelen_lo; /* length of value, bytes */ u8 valuelen_lo; /* length of value, bytes */
u8 valuelen_hi; /* length of value, bytes */ u8 valuelen_hi; /* length of value, bytes */
u8 name[0]; u8 name[];
/* /*
u8 name[namelen]; ascii attrib name u8 name[namelen]; ascii attrib name
u8 nul; terminating '\0', not counted u8 nul; terminating '\0', not counted
u8 value[valuelen]; value, arbitrary u8 value[valuelen]; value, arbitrary
if this.indirect, valuelen is 8 and the value is if this.flags & 1, valuelen is 8 and the value is
u32 length; real length of value, bytes u32 length; real length of value, bytes
secno secno; sector address where it starts secno secno; sector address where it starts
if this.anode, the above sector number is the root of an anode tree if this.anode, the above sector number is the root of an anode tree
@ -561,6 +542,16 @@ struct extended_attribute
*/ */
}; };
static inline bool ea_indirect(struct extended_attribute *ea)
{
return ea->flags & EA_indirect;
}
static inline bool ea_in_anode(struct extended_attribute *ea)
{
return ea->flags & EA_anode;
}
/* /*
Local Variables: Local Variables:
comment-column: 40 comment-column: 40

View File

@ -75,7 +75,7 @@ struct hpfs_sb_info {
unsigned char *sb_cp_table; /* code page tables: */ unsigned char *sb_cp_table; /* code page tables: */
/* 128 bytes uppercasing table & */ /* 128 bytes uppercasing table & */
/* 128 bytes lowercasing table */ /* 128 bytes lowercasing table */
unsigned *sb_bmp_dir; /* main bitmap directory */ __le32 *sb_bmp_dir; /* main bitmap directory */
unsigned sb_c_bitmap; /* current bitmap */ unsigned sb_c_bitmap; /* current bitmap */
unsigned sb_max_fwd_alloc; /* max forwad allocation */ unsigned sb_max_fwd_alloc; /* max forwad allocation */
int sb_timeshift; int sb_timeshift;
@ -93,7 +93,7 @@ struct quad_buffer_head {
static inline dnode_secno de_down_pointer (struct hpfs_dirent *de) static inline dnode_secno de_down_pointer (struct hpfs_dirent *de)
{ {
CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n")); CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n"));
return le32_to_cpu(*(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4)); return le32_to_cpu(*(__le32 *) ((void *) de + le16_to_cpu(de->length) - 4));
} }
/* The first dir entry in a dnode */ /* The first dir entry in a dnode */
@ -141,12 +141,12 @@ static inline struct extended_attribute *next_ea(struct extended_attribute *ea)
static inline secno ea_sec(struct extended_attribute *ea) static inline secno ea_sec(struct extended_attribute *ea)
{ {
return le32_to_cpu(get_unaligned((secno *)((char *)ea + 9 + ea->namelen))); return le32_to_cpu(get_unaligned((__le32 *)((char *)ea + 9 + ea->namelen)));
} }
static inline secno ea_len(struct extended_attribute *ea) static inline secno ea_len(struct extended_attribute *ea)
{ {
return le32_to_cpu(get_unaligned((secno *)((char *)ea + 5 + ea->namelen))); return le32_to_cpu(get_unaligned((__le32 *)((char *)ea + 5 + ea->namelen)));
} }
static inline char *ea_data(struct extended_attribute *ea) static inline char *ea_data(struct extended_attribute *ea)
@ -171,7 +171,7 @@ static inline void copy_de(struct hpfs_dirent *dst, struct hpfs_dirent *src)
dst->not_8x3 = n; dst->not_8x3 = n;
} }
static inline unsigned tstbits(u32 *bmp, unsigned b, unsigned n) static inline unsigned tstbits(__le32 *bmp, unsigned b, unsigned n)
{ {
int i; int i;
if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n; if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n;
@ -268,10 +268,10 @@ void hpfs_evict_inode(struct inode *);
/* map.c */ /* map.c */
unsigned *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *); __le32 *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *);
unsigned *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *); __le32 *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *);
unsigned char *hpfs_load_code_page(struct super_block *, secno); unsigned char *hpfs_load_code_page(struct super_block *, secno);
secno *hpfs_load_bitmap_directory(struct super_block *, secno bmp); __le32 *hpfs_load_bitmap_directory(struct super_block *, secno bmp);
struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **); struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **);
struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **); struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **);
struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *); struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *);

View File

@ -110,7 +110,7 @@ void hpfs_read_inode(struct inode *i)
} }
} }
} }
if (fnode->dirflag) { if (fnode_is_dir(fnode)) {
int n_dnodes, n_subdirs; int n_dnodes, n_subdirs;
i->i_mode |= S_IFDIR; i->i_mode |= S_IFDIR;
i->i_op = &hpfs_dir_iops; i->i_op = &hpfs_dir_iops;

View File

@ -8,12 +8,12 @@
#include "hpfs_fn.h" #include "hpfs_fn.h"
unsigned *hpfs_map_dnode_bitmap(struct super_block *s, struct quad_buffer_head *qbh) __le32 *hpfs_map_dnode_bitmap(struct super_block *s, struct quad_buffer_head *qbh)
{ {
return hpfs_map_4sectors(s, hpfs_sb(s)->sb_dmap, qbh, 0); return hpfs_map_4sectors(s, hpfs_sb(s)->sb_dmap, qbh, 0);
} }
unsigned int *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block, __le32 *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block,
struct quad_buffer_head *qbh, char *id) struct quad_buffer_head *qbh, char *id)
{ {
secno sec; secno sec;
@ -89,18 +89,18 @@ unsigned char *hpfs_load_code_page(struct super_block *s, secno cps)
return cp_table; return cp_table;
} }
secno *hpfs_load_bitmap_directory(struct super_block *s, secno bmp) __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp)
{ {
struct buffer_head *bh; struct buffer_head *bh;
int n = (hpfs_sb(s)->sb_fs_size + 0x200000 - 1) >> 21; int n = (hpfs_sb(s)->sb_fs_size + 0x200000 - 1) >> 21;
int i; int i;
secno *b; __le32 *b;
if (!(b = kmalloc(n * 512, GFP_KERNEL))) { if (!(b = kmalloc(n * 512, GFP_KERNEL))) {
printk("HPFS: can't allocate memory for bitmap directory\n"); printk("HPFS: can't allocate memory for bitmap directory\n");
return NULL; return NULL;
} }
for (i=0;i<n;i++) { for (i=0;i<n;i++) {
secno *d = hpfs_map_sector(s, bmp+i, &bh, n - i - 1); __le32 *d = hpfs_map_sector(s, bmp+i, &bh, n - i - 1);
if (!d) { if (!d) {
kfree(b); kfree(b);
return NULL; return NULL;
@ -130,16 +130,16 @@ struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_hea
(unsigned long)ino); (unsigned long)ino);
goto bail; goto bail;
} }
if (!fnode->dirflag) { if (!fnode_is_dir(fnode)) {
if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes != if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes !=
(fnode->btree.internal ? 12 : 8)) { (bp_internal(&fnode->btree) ? 12 : 8)) {
hpfs_error(s, hpfs_error(s,
"bad number of nodes in fnode %08lx", "bad number of nodes in fnode %08lx",
(unsigned long)ino); (unsigned long)ino);
goto bail; goto bail;
} }
if (le16_to_cpu(fnode->btree.first_free) != if (le16_to_cpu(fnode->btree.first_free) !=
8 + fnode->btree.n_used_nodes * (fnode->btree.internal ? 8 : 12)) { 8 + fnode->btree.n_used_nodes * (bp_internal(&fnode->btree) ? 8 : 12)) {
hpfs_error(s, hpfs_error(s,
"bad first_free pointer in fnode %08lx", "bad first_free pointer in fnode %08lx",
(unsigned long)ino); (unsigned long)ino);
@ -187,12 +187,12 @@ struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buff
goto bail; goto bail;
} }
if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes != if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes !=
(anode->btree.internal ? 60 : 40)) { (bp_internal(&anode->btree) ? 60 : 40)) {
hpfs_error(s, "bad number of nodes in anode %08x", ano); hpfs_error(s, "bad number of nodes in anode %08x", ano);
goto bail; goto bail;
} }
if (le16_to_cpu(anode->btree.first_free) != if (le16_to_cpu(anode->btree.first_free) !=
8 + anode->btree.n_used_nodes * (anode->btree.internal ? 8 : 12)) { 8 + anode->btree.n_used_nodes * (bp_internal(&anode->btree) ? 8 : 12)) {
hpfs_error(s, "bad first_free pointer in anode %08x", ano); hpfs_error(s, "bad first_free pointer in anode %08x", ano);
goto bail; goto bail;
} }

View File

@ -70,7 +70,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
fnode->len = len; fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len); memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = cpu_to_le32(dir->i_ino); fnode->up = cpu_to_le32(dir->i_ino);
fnode->dirflag = 1; fnode->flags |= FNODE_dir;
fnode->btree.n_free_nodes = 7; fnode->btree.n_free_nodes = 7;
fnode->btree.n_used_nodes = 1; fnode->btree.n_used_nodes = 1;
fnode->btree.first_free = cpu_to_le16(0x14); fnode->btree.first_free = cpu_to_le16(0x14);

View File

@ -572,7 +572,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
mark_buffer_dirty(bh2); mark_buffer_dirty(bh2);
} }
if (le32_to_cpu(spareblock->hotfixes_used) || le32_to_cpu(spareblock->n_spares_used)) { if (spareblock->hotfixes_used || spareblock->n_spares_used) {
if (errs >= 2) { if (errs >= 2) {
printk("HPFS: Hotfixes not supported here, try chkdsk\n"); printk("HPFS: Hotfixes not supported here, try chkdsk\n");
mark_dirty(s, 0); mark_dirty(s, 0);
@ -645,7 +645,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
root->i_mtime.tv_nsec = 0; root->i_mtime.tv_nsec = 0;
root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date)); root->i_ctime.tv_sec = local_to_gmt(s, le32_to_cpu(de->creation_date));
root->i_ctime.tv_nsec = 0; root->i_ctime.tv_nsec = 0;
hpfs_i(root)->i_ea_size = le16_to_cpu(de->ea_size); hpfs_i(root)->i_ea_size = le32_to_cpu(de->ea_size);
hpfs_i(root)->i_parent_dir = root->i_ino; hpfs_i(root)->i_parent_dir = root->i_ino;
if (root->i_size == -1) if (root->i_size == -1)
root->i_size = 2048; root->i_size = 2048;

View File

@ -1487,10 +1487,30 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
return 0; return 0;
} }
/*
* This does the actual work of updating an inodes time or version. Must have
* had called mnt_want_write() before calling this.
*/
static int update_time(struct inode *inode, struct timespec *time, int flags)
{
if (inode->i_op->update_time)
return inode->i_op->update_time(inode, time, flags);
if (flags & S_ATIME)
inode->i_atime = *time;
if (flags & S_VERSION)
inode_inc_iversion(inode);
if (flags & S_CTIME)
inode->i_ctime = *time;
if (flags & S_MTIME)
inode->i_mtime = *time;
mark_inode_dirty_sync(inode);
return 0;
}
/** /**
* touch_atime - update the access time * touch_atime - update the access time
* @mnt: mount the inode is accessed on * @path: the &struct path to update
* @dentry: dentry accessed
* *
* Update the accessed time on an inode and mark it for writeback. * Update the accessed time on an inode and mark it for writeback.
* This function automatically handles read only file systems and media, * This function automatically handles read only file systems and media,
@ -1525,12 +1545,83 @@ void touch_atime(struct path *path)
if (mnt_want_write(mnt)) if (mnt_want_write(mnt))
return; return;
inode->i_atime = now; /*
mark_inode_dirty_sync(inode); * File systems can error out when updating inodes if they need to
* allocate new space to modify an inode (such is the case for
* Btrfs), but since we touch atime while walking down the path we
* really don't care if we failed to update the atime of the file,
* so just ignore the return value.
*/
update_time(inode, &now, S_ATIME);
mnt_drop_write(mnt); mnt_drop_write(mnt);
} }
EXPORT_SYMBOL(touch_atime); EXPORT_SYMBOL(touch_atime);
/*
* The logic we want is
*
* if suid or (sgid and xgrp)
* remove privs
*/
int should_remove_suid(struct dentry *dentry)
{
umode_t mode = dentry->d_inode->i_mode;
int kill = 0;
/* suid always must be killed */
if (unlikely(mode & S_ISUID))
kill = ATTR_KILL_SUID;
/*
* sgid without any exec bits is just a mandatory locking mark; leave
* it alone. If some exec bits are set, it's a real sgid; kill it.
*/
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
kill |= ATTR_KILL_SGID;
if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
return kill;
return 0;
}
EXPORT_SYMBOL(should_remove_suid);
static int __remove_suid(struct dentry *dentry, int kill)
{
struct iattr newattrs;
newattrs.ia_valid = ATTR_FORCE | kill;
return notify_change(dentry, &newattrs);
}
int file_remove_suid(struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
int killsuid;
int killpriv;
int error = 0;
/* Fast path for nothing security related */
if (IS_NOSEC(inode))
return 0;
killsuid = should_remove_suid(dentry);
killpriv = security_inode_need_killpriv(dentry);
if (killpriv < 0)
return killpriv;
if (killpriv)
error = security_inode_killpriv(dentry);
if (!error && killsuid)
error = __remove_suid(dentry, killsuid);
if (!error && (inode->i_sb->s_flags & MS_NOSEC))
inode->i_flags |= S_NOSEC;
return error;
}
EXPORT_SYMBOL(file_remove_suid);
/** /**
* file_update_time - update mtime and ctime time * file_update_time - update mtime and ctime time
* @file: file accessed * @file: file accessed
@ -1540,18 +1631,20 @@ EXPORT_SYMBOL(touch_atime);
* usage in the file write path of filesystems, and filesystems may * usage in the file write path of filesystems, and filesystems may
* choose to explicitly ignore update via this function with the * choose to explicitly ignore update via this function with the
* S_NOCMTIME inode flag, e.g. for network filesystem where these * S_NOCMTIME inode flag, e.g. for network filesystem where these
* timestamps are handled by the server. * timestamps are handled by the server. This can return an error for
* file systems who need to allocate space in order to update an inode.
*/ */
void file_update_time(struct file *file) int file_update_time(struct file *file)
{ {
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
struct timespec now; struct timespec now;
enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0; int sync_it = 0;
int ret;
/* First try to exhaust all avenues to not sync */ /* First try to exhaust all avenues to not sync */
if (IS_NOCMTIME(inode)) if (IS_NOCMTIME(inode))
return; return 0;
now = current_fs_time(inode->i_sb); now = current_fs_time(inode->i_sb);
if (!timespec_equal(&inode->i_mtime, &now)) if (!timespec_equal(&inode->i_mtime, &now))
@ -1564,21 +1657,16 @@ void file_update_time(struct file *file)
sync_it |= S_VERSION; sync_it |= S_VERSION;
if (!sync_it) if (!sync_it)
return; return 0;
/* Finally allowed to write? Takes lock. */ /* Finally allowed to write? Takes lock. */
if (mnt_want_write_file(file)) if (mnt_want_write_file(file))
return; return 0;
/* Only change inode inside the lock region */ ret = update_time(inode, &now, sync_it);
if (sync_it & S_VERSION)
inode_inc_iversion(inode);
if (sync_it & S_CTIME)
inode->i_ctime = now;
if (sync_it & S_MTIME)
inode->i_mtime = now;
mark_inode_dirty_sync(inode);
mnt_drop_write_file(file); mnt_drop_write_file(file);
return ret;
} }
EXPORT_SYMBOL(file_update_time); EXPORT_SYMBOL(file_update_time);

View File

@ -56,7 +56,7 @@ extern int sb_prepare_remount_readonly(struct super_block *);
extern void __init mnt_init(void); extern void __init mnt_init(void);
DECLARE_BRLOCK(vfsmount_lock); extern struct lglock vfsmount_lock;
/* /*
@ -100,6 +100,7 @@ extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
extern long do_handle_open(int mountdirfd, extern long do_handle_open(int mountdirfd,
struct file_handle __user *ufh, int open_flag); struct file_handle __user *ufh, int open_flag);
extern int open_check_o_direct(struct file *f);
/* /*
* inode.c * inode.c

View File

@ -107,12 +107,11 @@ static struct dentry *isofs_export_get_parent(struct dentry *child)
} }
static int static int
isofs_export_encode_fh(struct dentry *dentry, isofs_export_encode_fh(struct inode *inode,
__u32 *fh32, __u32 *fh32,
int *max_len, int *max_len,
int connectable) struct inode *parent)
{ {
struct inode * inode = dentry->d_inode;
struct iso_inode_info * ei = ISOFS_I(inode); struct iso_inode_info * ei = ISOFS_I(inode);
int len = *max_len; int len = *max_len;
int type = 1; int type = 1;
@ -124,7 +123,7 @@ isofs_export_encode_fh(struct dentry *dentry,
* offset of the inode and the upper 16 bits of fh32[1] to * offset of the inode and the upper 16 bits of fh32[1] to
* hold the offset of the parent. * hold the offset of the parent.
*/ */
if (connectable && (len < 5)) { if (parent && (len < 5)) {
*max_len = 5; *max_len = 5;
return 255; return 255;
} else if (len < 3) { } else if (len < 3) {
@ -136,16 +135,12 @@ isofs_export_encode_fh(struct dentry *dentry,
fh32[0] = ei->i_iget5_block; fh32[0] = ei->i_iget5_block;
fh16[2] = (__u16)ei->i_iget5_offset; /* fh16 [sic] */ fh16[2] = (__u16)ei->i_iget5_offset; /* fh16 [sic] */
fh32[2] = inode->i_generation; fh32[2] = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) { if (parent) {
struct inode *parent;
struct iso_inode_info *eparent; struct iso_inode_info *eparent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
eparent = ISOFS_I(parent); eparent = ISOFS_I(parent);
fh32[3] = eparent->i_iget5_block; fh32[3] = eparent->i_iget5_block;
fh16[3] = (__u16)eparent->i_iget5_offset; /* fh16 [sic] */ fh16[3] = (__u16)eparent->i_iget5_offset; /* fh16 [sic] */
fh32[4] = parent->i_generation; fh32[4] = parent->i_generation;
spin_unlock(&dentry->d_lock);
len = 5; len = 5;
type = 2; type = 2;
} }

View File

@ -126,6 +126,10 @@ struct jffs2_sb_info {
struct jffs2_inodirty *wbuf_inodes; struct jffs2_inodirty *wbuf_inodes;
struct rw_semaphore wbuf_sem; /* Protects the write buffer */ struct rw_semaphore wbuf_sem; /* Protects the write buffer */
struct delayed_work wbuf_dwork; /* write-buffer write-out work */
int wbuf_queued; /* non-zero delayed work is queued */
spinlock_t wbuf_dwork_lock; /* protects wbuf_dwork and and wbuf_queued */
unsigned char *oobbuf; unsigned char *oobbuf;
int oobavail; /* How many bytes are available for JFFS2 in OOB */ int oobavail; /* How many bytes are available for JFFS2 in OOB */
#endif #endif

View File

@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_ubivol(c) (0) #define jffs2_ubivol(c) (0)
#define jffs2_ubivol_setup(c) (0) #define jffs2_ubivol_setup(c) (0)
#define jffs2_ubivol_cleanup(c) do {} while (0) #define jffs2_ubivol_cleanup(c) do {} while (0)
#define jffs2_dirty_trigger(c) do {} while (0)
#else /* NAND and/or ECC'd NOR support present */ #else /* NAND and/or ECC'd NOR support present */
@ -135,14 +136,10 @@ void jffs2_ubivol_cleanup(struct jffs2_sb_info *c);
#define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && ! (c->mtd->flags & MTD_BIT_WRITEABLE)) #define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && ! (c->mtd->flags & MTD_BIT_WRITEABLE))
int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c); int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c);
void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c); void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c);
void jffs2_dirty_trigger(struct jffs2_sb_info *c);
#endif /* WRITEBUFFER */ #endif /* WRITEBUFFER */
static inline void jffs2_dirty_trigger(struct jffs2_sb_info *c)
{
OFNI_BS_2SFFJ(c)->s_dirt = 1;
}
/* background.c */ /* background.c */
int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);

View File

@ -63,21 +63,6 @@ static void jffs2_i_init_once(void *foo)
inode_init_once(&f->vfs_inode); inode_init_once(&f->vfs_inode);
} }
static void jffs2_write_super(struct super_block *sb)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
lock_super(sb);
sb->s_dirt = 0;
if (!(sb->s_flags & MS_RDONLY)) {
jffs2_dbg(1, "%s()\n", __func__);
jffs2_flush_wbuf_gc(c, 0);
}
unlock_super(sb);
}
static const char *jffs2_compr_name(unsigned int compr) static const char *jffs2_compr_name(unsigned int compr)
{ {
switch (compr) { switch (compr) {
@ -113,8 +98,6 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
{ {
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
jffs2_write_super(sb);
mutex_lock(&c->alloc_sem); mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c); jffs2_flush_wbuf_pad(c);
mutex_unlock(&c->alloc_sem); mutex_unlock(&c->alloc_sem);
@ -251,7 +234,6 @@ static const struct super_operations jffs2_super_operations =
.alloc_inode = jffs2_alloc_inode, .alloc_inode = jffs2_alloc_inode,
.destroy_inode =jffs2_destroy_inode, .destroy_inode =jffs2_destroy_inode,
.put_super = jffs2_put_super, .put_super = jffs2_put_super,
.write_super = jffs2_write_super,
.statfs = jffs2_statfs, .statfs = jffs2_statfs,
.remount_fs = jffs2_remount_fs, .remount_fs = jffs2_remount_fs,
.evict_inode = jffs2_evict_inode, .evict_inode = jffs2_evict_inode,
@ -319,9 +301,6 @@ static void jffs2_put_super (struct super_block *sb)
jffs2_dbg(2, "%s()\n", __func__); jffs2_dbg(2, "%s()\n", __func__);
if (sb->s_dirt)
jffs2_write_super(sb);
mutex_lock(&c->alloc_sem); mutex_lock(&c->alloc_sem);
jffs2_flush_wbuf_pad(c); jffs2_flush_wbuf_pad(c);
mutex_unlock(&c->alloc_sem); mutex_unlock(&c->alloc_sem);

View File

@ -20,6 +20,7 @@
#include <linux/mtd/nand.h> #include <linux/mtd/nand.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/writeback.h>
#include "nodelist.h" #include "nodelist.h"
@ -85,7 +86,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
{ {
struct jffs2_inodirty *new; struct jffs2_inodirty *new;
/* Mark the superblock dirty so that kupdated will flush... */ /* Schedule delayed write-buffer write-out */
jffs2_dirty_trigger(c); jffs2_dirty_trigger(c);
if (jffs2_wbuf_pending_for_ino(c, ino)) if (jffs2_wbuf_pending_for_ino(c, ino))
@ -1148,6 +1149,47 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
return 1; return 1;
} }
static struct jffs2_sb_info *work_to_sb(struct work_struct *work)
{
struct delayed_work *dwork;
dwork = container_of(work, struct delayed_work, work);
return container_of(dwork, struct jffs2_sb_info, wbuf_dwork);
}
static void delayed_wbuf_sync(struct work_struct *work)
{
struct jffs2_sb_info *c = work_to_sb(work);
struct super_block *sb = OFNI_BS_2SFFJ(c);
spin_lock(&c->wbuf_dwork_lock);
c->wbuf_queued = 0;
spin_unlock(&c->wbuf_dwork_lock);
if (!(sb->s_flags & MS_RDONLY)) {
jffs2_dbg(1, "%s()\n", __func__);
jffs2_flush_wbuf_gc(c, 0);
}
}
void jffs2_dirty_trigger(struct jffs2_sb_info *c)
{
struct super_block *sb = OFNI_BS_2SFFJ(c);
unsigned long delay;
if (sb->s_flags & MS_RDONLY)
return;
spin_lock(&c->wbuf_dwork_lock);
if (!c->wbuf_queued) {
jffs2_dbg(1, "%s()\n", __func__);
delay = msecs_to_jiffies(dirty_writeback_interval * 10);
queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay);
c->wbuf_queued = 1;
}
spin_unlock(&c->wbuf_dwork_lock);
}
int jffs2_nand_flash_setup(struct jffs2_sb_info *c) int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
{ {
struct nand_ecclayout *oinfo = c->mtd->ecclayout; struct nand_ecclayout *oinfo = c->mtd->ecclayout;
@ -1169,6 +1211,8 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
/* Initialise write buffer */ /* Initialise write buffer */
init_rwsem(&c->wbuf_sem); init_rwsem(&c->wbuf_sem);
spin_lock_init(&c->wbuf_dwork_lock);
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
c->wbuf_pagesize = c->mtd->writesize; c->wbuf_pagesize = c->mtd->writesize;
c->wbuf_ofs = 0xFFFFFFFF; c->wbuf_ofs = 0xFFFFFFFF;
@ -1207,8 +1251,8 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
/* Initialize write buffer */ /* Initialize write buffer */
init_rwsem(&c->wbuf_sem); init_rwsem(&c->wbuf_sem);
spin_lock_init(&c->wbuf_dwork_lock);
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
c->wbuf_pagesize = c->mtd->erasesize; c->wbuf_pagesize = c->mtd->erasesize;
/* Find a suitable c->sector_size /* Find a suitable c->sector_size
@ -1267,6 +1311,9 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
/* Initialize write buffer */ /* Initialize write buffer */
init_rwsem(&c->wbuf_sem); init_rwsem(&c->wbuf_sem);
spin_lock_init(&c->wbuf_dwork_lock);
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
c->wbuf_pagesize = c->mtd->writesize; c->wbuf_pagesize = c->mtd->writesize;
c->wbuf_ofs = 0xFFFFFFFF; c->wbuf_ofs = 0xFFFFFFFF;
@ -1299,6 +1346,8 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) {
return 0; return 0;
init_rwsem(&c->wbuf_sem); init_rwsem(&c->wbuf_sem);
spin_lock_init(&c->wbuf_dwork_lock);
INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync);
c->wbuf_pagesize = c->mtd->writesize; c->wbuf_pagesize = c->mtd->writesize;
c->wbuf_ofs = 0xFFFFFFFF; c->wbuf_ofs = 0xFFFFFFFF;

View File

@ -1636,12 +1636,13 @@ EXPORT_SYMBOL(flock_lock_file_wait);
SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
{ {
struct file *filp; struct file *filp;
int fput_needed;
struct file_lock *lock; struct file_lock *lock;
int can_sleep, unlock; int can_sleep, unlock;
int error; int error;
error = -EBADF; error = -EBADF;
filp = fget(fd); filp = fget_light(fd, &fput_needed);
if (!filp) if (!filp)
goto out; goto out;
@ -1674,7 +1675,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
locks_free_lock(lock); locks_free_lock(lock);
out_putf: out_putf:
fput(filp); fput_light(filp, fput_needed);
out: out:
return error; return error;
} }

View File

@ -449,7 +449,7 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
mntget(nd->path.mnt); mntget(nd->path.mnt);
rcu_read_unlock(); rcu_read_unlock();
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
nd->flags &= ~LOOKUP_RCU; nd->flags &= ~LOOKUP_RCU;
return 0; return 0;
@ -507,14 +507,14 @@ static int complete_walk(struct nameidata *nd)
if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) { if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
rcu_read_unlock(); rcu_read_unlock();
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return -ECHILD; return -ECHILD;
} }
BUG_ON(nd->inode != dentry->d_inode); BUG_ON(nd->inode != dentry->d_inode);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
mntget(nd->path.mnt); mntget(nd->path.mnt);
rcu_read_unlock(); rcu_read_unlock();
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
} }
if (likely(!(nd->flags & LOOKUP_JUMPED))) if (likely(!(nd->flags & LOOKUP_JUMPED)))
@ -681,15 +681,15 @@ int follow_up(struct path *path)
struct mount *parent; struct mount *parent;
struct dentry *mountpoint; struct dentry *mountpoint;
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
parent = mnt->mnt_parent; parent = mnt->mnt_parent;
if (&parent->mnt == path->mnt) { if (&parent->mnt == path->mnt) {
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return 0; return 0;
} }
mntget(&parent->mnt); mntget(&parent->mnt);
mountpoint = dget(mnt->mnt_mountpoint); mountpoint = dget(mnt->mnt_mountpoint);
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
dput(path->dentry); dput(path->dentry);
path->dentry = mountpoint; path->dentry = mountpoint;
mntput(path->mnt); mntput(path->mnt);
@ -947,7 +947,7 @@ failed:
if (!(nd->flags & LOOKUP_ROOT)) if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL; nd->root.mnt = NULL;
rcu_read_unlock(); rcu_read_unlock();
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return -ECHILD; return -ECHILD;
} }
@ -1125,8 +1125,8 @@ static struct dentry *__lookup_hash(struct qstr *name,
* small and for now I'd prefer to have fast path as straight as possible. * small and for now I'd prefer to have fast path as straight as possible.
* It _is_ time-critical. * It _is_ time-critical.
*/ */
static int do_lookup(struct nameidata *nd, struct qstr *name, static int lookup_fast(struct nameidata *nd, struct qstr *name,
struct path *path, struct inode **inode) struct path *path, struct inode **inode)
{ {
struct vfsmount *mnt = nd->path.mnt; struct vfsmount *mnt = nd->path.mnt;
struct dentry *dentry, *parent = nd->path.dentry; struct dentry *dentry, *parent = nd->path.dentry;
@ -1208,7 +1208,7 @@ unlazy:
goto need_lookup; goto need_lookup;
} }
} }
done:
path->mnt = mnt; path->mnt = mnt;
path->dentry = dentry; path->dentry = dentry;
err = follow_managed(path, nd->flags); err = follow_managed(path, nd->flags);
@ -1222,6 +1222,17 @@ done:
return 0; return 0;
need_lookup: need_lookup:
return 1;
}
/* Fast lookup failed, do it the slow way */
static int lookup_slow(struct nameidata *nd, struct qstr *name,
struct path *path)
{
struct dentry *dentry, *parent;
int err;
parent = nd->path.dentry;
BUG_ON(nd->inode != parent->d_inode); BUG_ON(nd->inode != parent->d_inode);
mutex_lock(&parent->d_inode->i_mutex); mutex_lock(&parent->d_inode->i_mutex);
@ -1229,7 +1240,16 @@ need_lookup:
mutex_unlock(&parent->d_inode->i_mutex); mutex_unlock(&parent->d_inode->i_mutex);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return PTR_ERR(dentry); return PTR_ERR(dentry);
goto done; path->mnt = nd->path.mnt;
path->dentry = dentry;
err = follow_managed(path, nd->flags);
if (unlikely(err < 0)) {
path_put_conditional(path, nd);
return err;
}
if (err)
nd->flags |= LOOKUP_JUMPED;
return 0;
} }
static inline int may_lookup(struct nameidata *nd) static inline int may_lookup(struct nameidata *nd)
@ -1265,7 +1285,7 @@ static void terminate_walk(struct nameidata *nd)
if (!(nd->flags & LOOKUP_ROOT)) if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL; nd->root.mnt = NULL;
rcu_read_unlock(); rcu_read_unlock();
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
} }
} }
@ -1301,21 +1321,26 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
*/ */
if (unlikely(type != LAST_NORM)) if (unlikely(type != LAST_NORM))
return handle_dots(nd, type); return handle_dots(nd, type);
err = do_lookup(nd, name, path, &inode); err = lookup_fast(nd, name, path, &inode);
if (unlikely(err)) { if (unlikely(err)) {
terminate_walk(nd); if (err < 0)
return err; goto out_err;
}
if (!inode) { err = lookup_slow(nd, name, path);
path_to_nameidata(path, nd); if (err < 0)
terminate_walk(nd); goto out_err;
return -ENOENT;
inode = path->dentry->d_inode;
} }
err = -ENOENT;
if (!inode)
goto out_path_put;
if (should_follow_link(inode, follow)) { if (should_follow_link(inode, follow)) {
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
if (unlikely(unlazy_walk(nd, path->dentry))) { if (unlikely(unlazy_walk(nd, path->dentry))) {
terminate_walk(nd); err = -ECHILD;
return -ECHILD; goto out_err;
} }
} }
BUG_ON(inode != path->dentry->d_inode); BUG_ON(inode != path->dentry->d_inode);
@ -1324,6 +1349,12 @@ static inline int walk_component(struct nameidata *nd, struct path *path,
path_to_nameidata(path, nd); path_to_nameidata(path, nd);
nd->inode = inode; nd->inode = inode;
return 0; return 0;
out_path_put:
path_to_nameidata(path, nd);
out_err:
terminate_walk(nd);
return err;
} }
/* /*
@ -1620,7 +1651,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
nd->path = nd->root; nd->path = nd->root;
nd->inode = inode; nd->inode = inode;
if (flags & LOOKUP_RCU) { if (flags & LOOKUP_RCU) {
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
rcu_read_lock(); rcu_read_lock();
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
} else { } else {
@ -1633,7 +1664,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
if (*name=='/') { if (*name=='/') {
if (flags & LOOKUP_RCU) { if (flags & LOOKUP_RCU) {
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
rcu_read_lock(); rcu_read_lock();
set_root_rcu(nd); set_root_rcu(nd);
} else { } else {
@ -1646,7 +1677,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
struct fs_struct *fs = current->fs; struct fs_struct *fs = current->fs;
unsigned seq; unsigned seq;
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
rcu_read_lock(); rcu_read_lock();
do { do {
@ -1682,7 +1713,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
if (fput_needed) if (fput_needed)
*fp = file; *fp = file;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
rcu_read_lock(); rcu_read_lock();
} else { } else {
path_get(&file->f_path); path_get(&file->f_path);
@ -2169,6 +2200,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
int want_write = 0; int want_write = 0;
int acc_mode = op->acc_mode; int acc_mode = op->acc_mode;
struct file *filp; struct file *filp;
struct inode *inode;
int symlink_ok = 0;
struct path save_parent = { .dentry = NULL, .mnt = NULL };
bool retried = false;
int error; int error;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
@ -2200,30 +2235,23 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
} }
if (!(open_flag & O_CREAT)) { if (!(open_flag & O_CREAT)) {
int symlink_ok = 0;
if (nd->last.name[nd->last.len]) if (nd->last.name[nd->last.len])
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW)) if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
symlink_ok = 1; symlink_ok = 1;
/* we _can_ be in RCU mode here */ /* we _can_ be in RCU mode here */
error = walk_component(nd, path, &nd->last, LAST_NORM, error = lookup_fast(nd, &nd->last, path, &inode);
!symlink_ok); if (unlikely(error)) {
if (error < 0) if (error < 0)
return ERR_PTR(error);
if (error) /* symlink */
return NULL;
/* sayonara */
error = complete_walk(nd);
if (error)
return ERR_PTR(error);
error = -ENOTDIR;
if (nd->flags & LOOKUP_DIRECTORY) {
if (!nd->inode->i_op->lookup)
goto exit; goto exit;
error = lookup_slow(nd, &nd->last, path);
if (error < 0)
goto exit;
inode = path->dentry->d_inode;
} }
audit_inode(pathname, nd->path.dentry); goto finish_lookup;
goto ok;
} }
/* create side of things */ /* create side of things */
@ -2241,6 +2269,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (nd->last.name[nd->last.len]) if (nd->last.name[nd->last.len])
goto exit; goto exit;
retry_lookup:
mutex_lock(&dir->d_inode->i_mutex); mutex_lock(&dir->d_inode->i_mutex);
dentry = lookup_hash(nd); dentry = lookup_hash(nd);
@ -2302,22 +2331,49 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
if (error) if (error)
nd->flags |= LOOKUP_JUMPED; nd->flags |= LOOKUP_JUMPED;
BUG_ON(nd->flags & LOOKUP_RCU);
inode = path->dentry->d_inode;
finish_lookup:
/* we _can_ be in RCU mode here */
error = -ENOENT; error = -ENOENT;
if (!path->dentry->d_inode) if (!inode) {
goto exit_dput; path_to_nameidata(path, nd);
goto exit;
}
if (path->dentry->d_inode->i_op->follow_link) if (should_follow_link(inode, !symlink_ok)) {
if (nd->flags & LOOKUP_RCU) {
if (unlikely(unlazy_walk(nd, path->dentry))) {
error = -ECHILD;
goto exit;
}
}
BUG_ON(inode != path->dentry->d_inode);
return NULL; return NULL;
}
path_to_nameidata(path, nd); if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path->mnt) {
nd->inode = path->dentry->d_inode; path_to_nameidata(path, nd);
} else {
save_parent.dentry = nd->path.dentry;
save_parent.mnt = mntget(path->mnt);
nd->path.dentry = path->dentry;
}
nd->inode = inode;
/* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
error = complete_walk(nd); error = complete_walk(nd);
if (error) if (error) {
path_put(&save_parent);
return ERR_PTR(error); return ERR_PTR(error);
}
error = -EISDIR; error = -EISDIR;
if (S_ISDIR(nd->inode->i_mode)) if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
goto exit; goto exit;
error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
goto exit;
audit_inode(pathname, nd->path.dentry);
ok: ok:
if (!S_ISREG(nd->inode->i_mode)) if (!S_ISREG(nd->inode->i_mode))
will_truncate = 0; will_truncate = 0;
@ -2333,6 +2389,20 @@ common:
if (error) if (error)
goto exit; goto exit;
filp = nameidata_to_filp(nd); filp = nameidata_to_filp(nd);
if (filp == ERR_PTR(-EOPENSTALE) && save_parent.dentry && !retried) {
BUG_ON(save_parent.dentry != dir);
path_put(&nd->path);
nd->path = save_parent;
nd->inode = dir->d_inode;
save_parent.mnt = NULL;
save_parent.dentry = NULL;
if (want_write) {
mnt_drop_write(nd->path.mnt);
want_write = 0;
}
retried = true;
goto retry_lookup;
}
if (!IS_ERR(filp)) { if (!IS_ERR(filp)) {
error = ima_file_check(filp, op->acc_mode); error = ima_file_check(filp, op->acc_mode);
if (error) { if (error) {
@ -2352,7 +2422,8 @@ common:
out: out:
if (want_write) if (want_write)
mnt_drop_write(nd->path.mnt); mnt_drop_write(nd->path.mnt);
path_put(&nd->path); path_put(&save_parent);
terminate_walk(nd);
return filp; return filp;
exit_mutex_unlock: exit_mutex_unlock:
@ -2415,6 +2486,12 @@ out:
if (base) if (base)
fput(base); fput(base);
release_open_intent(nd); release_open_intent(nd);
if (filp == ERR_PTR(-EOPENSTALE)) {
if (flags & LOOKUP_RCU)
filp = ERR_PTR(-ECHILD);
else
filp = ERR_PTR(-ESTALE);
}
return filp; return filp;
out_filp: out_filp:

View File

@ -397,7 +397,7 @@ static int mnt_make_readonly(struct mount *mnt)
{ {
int ret = 0; int ret = 0;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
/* /*
* After storing MNT_WRITE_HOLD, we'll read the counters. This store * After storing MNT_WRITE_HOLD, we'll read the counters. This store
@ -431,15 +431,15 @@ static int mnt_make_readonly(struct mount *mnt)
*/ */
smp_wmb(); smp_wmb();
mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return ret; return ret;
} }
static void __mnt_unmake_readonly(struct mount *mnt) static void __mnt_unmake_readonly(struct mount *mnt)
{ {
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
mnt->mnt.mnt_flags &= ~MNT_READONLY; mnt->mnt.mnt_flags &= ~MNT_READONLY;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
int sb_prepare_remount_readonly(struct super_block *sb) int sb_prepare_remount_readonly(struct super_block *sb)
@ -451,7 +451,7 @@ int sb_prepare_remount_readonly(struct super_block *sb)
if (atomic_long_read(&sb->s_remove_count)) if (atomic_long_read(&sb->s_remove_count))
return -EBUSY; return -EBUSY;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) {
if (!(mnt->mnt.mnt_flags & MNT_READONLY)) { if (!(mnt->mnt.mnt_flags & MNT_READONLY)) {
mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; mnt->mnt.mnt_flags |= MNT_WRITE_HOLD;
@ -473,7 +473,7 @@ int sb_prepare_remount_readonly(struct super_block *sb)
if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD)
mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD;
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return err; return err;
} }
@ -522,14 +522,14 @@ struct vfsmount *lookup_mnt(struct path *path)
{ {
struct mount *child_mnt; struct mount *child_mnt;
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
child_mnt = __lookup_mnt(path->mnt, path->dentry, 1); child_mnt = __lookup_mnt(path->mnt, path->dentry, 1);
if (child_mnt) { if (child_mnt) {
mnt_add_count(child_mnt, 1); mnt_add_count(child_mnt, 1);
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return &child_mnt->mnt; return &child_mnt->mnt;
} else { } else {
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return NULL; return NULL;
} }
} }
@ -714,9 +714,9 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
mnt->mnt.mnt_sb = root->d_sb; mnt->mnt.mnt_sb = root->d_sb;
mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_mountpoint = mnt->mnt.mnt_root;
mnt->mnt_parent = mnt; mnt->mnt_parent = mnt;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return &mnt->mnt; return &mnt->mnt;
} }
EXPORT_SYMBOL_GPL(vfs_kern_mount); EXPORT_SYMBOL_GPL(vfs_kern_mount);
@ -745,9 +745,9 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
mnt->mnt.mnt_root = dget(root); mnt->mnt.mnt_root = dget(root);
mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_mountpoint = mnt->mnt.mnt_root;
mnt->mnt_parent = mnt; mnt->mnt_parent = mnt;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_add_tail(&mnt->mnt_instance, &sb->s_mounts); list_add_tail(&mnt->mnt_instance, &sb->s_mounts);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
if (flag & CL_SLAVE) { if (flag & CL_SLAVE) {
list_add(&mnt->mnt_slave, &old->mnt_slave_list); list_add(&mnt->mnt_slave, &old->mnt_slave_list);
@ -803,35 +803,36 @@ static void mntput_no_expire(struct mount *mnt)
{ {
put_again: put_again:
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
if (likely(atomic_read(&mnt->mnt_longterm))) { if (likely(atomic_read(&mnt->mnt_longterm))) {
mnt_add_count(mnt, -1); mnt_add_count(mnt, -1);
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return; return;
} }
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
mnt_add_count(mnt, -1); mnt_add_count(mnt, -1);
if (mnt_get_count(mnt)) { if (mnt_get_count(mnt)) {
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return; return;
} }
#else #else
mnt_add_count(mnt, -1); mnt_add_count(mnt, -1);
if (likely(mnt_get_count(mnt))) if (likely(mnt_get_count(mnt)))
return; return;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
#endif #endif
if (unlikely(mnt->mnt_pinned)) { if (unlikely(mnt->mnt_pinned)) {
mnt_add_count(mnt, mnt->mnt_pinned + 1); mnt_add_count(mnt, mnt->mnt_pinned + 1);
mnt->mnt_pinned = 0; mnt->mnt_pinned = 0;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
acct_auto_close_mnt(&mnt->mnt); acct_auto_close_mnt(&mnt->mnt);
goto put_again; goto put_again;
} }
list_del(&mnt->mnt_instance); list_del(&mnt->mnt_instance);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
mntfree(mnt); mntfree(mnt);
} }
@ -857,21 +858,21 @@ EXPORT_SYMBOL(mntget);
void mnt_pin(struct vfsmount *mnt) void mnt_pin(struct vfsmount *mnt)
{ {
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
real_mount(mnt)->mnt_pinned++; real_mount(mnt)->mnt_pinned++;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
EXPORT_SYMBOL(mnt_pin); EXPORT_SYMBOL(mnt_pin);
void mnt_unpin(struct vfsmount *m) void mnt_unpin(struct vfsmount *m)
{ {
struct mount *mnt = real_mount(m); struct mount *mnt = real_mount(m);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
if (mnt->mnt_pinned) { if (mnt->mnt_pinned) {
mnt_add_count(mnt, 1); mnt_add_count(mnt, 1);
mnt->mnt_pinned--; mnt->mnt_pinned--;
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
EXPORT_SYMBOL(mnt_unpin); EXPORT_SYMBOL(mnt_unpin);
@ -988,12 +989,12 @@ int may_umount_tree(struct vfsmount *m)
BUG_ON(!m); BUG_ON(!m);
/* write lock needed for mnt_get_count */ /* write lock needed for mnt_get_count */
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
for (p = mnt; p; p = next_mnt(p, mnt)) { for (p = mnt; p; p = next_mnt(p, mnt)) {
actual_refs += mnt_get_count(p); actual_refs += mnt_get_count(p);
minimum_refs += 2; minimum_refs += 2;
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
if (actual_refs > minimum_refs) if (actual_refs > minimum_refs)
return 0; return 0;
@ -1020,10 +1021,10 @@ int may_umount(struct vfsmount *mnt)
{ {
int ret = 1; int ret = 1;
down_read(&namespace_sem); down_read(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
if (propagate_mount_busy(real_mount(mnt), 2)) if (propagate_mount_busy(real_mount(mnt), 2))
ret = 0; ret = 0;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_read(&namespace_sem); up_read(&namespace_sem);
return ret; return ret;
} }
@ -1040,13 +1041,13 @@ void release_mounts(struct list_head *head)
struct dentry *dentry; struct dentry *dentry;
struct mount *m; struct mount *m;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
dentry = mnt->mnt_mountpoint; dentry = mnt->mnt_mountpoint;
m = mnt->mnt_parent; m = mnt->mnt_parent;
mnt->mnt_mountpoint = mnt->mnt.mnt_root; mnt->mnt_mountpoint = mnt->mnt.mnt_root;
mnt->mnt_parent = mnt; mnt->mnt_parent = mnt;
m->mnt_ghosts--; m->mnt_ghosts--;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
dput(dentry); dput(dentry);
mntput(&m->mnt); mntput(&m->mnt);
} }
@ -1073,8 +1074,9 @@ void umount_tree(struct mount *mnt, int propagate, struct list_head *kill)
list_del_init(&p->mnt_expire); list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list); list_del_init(&p->mnt_list);
__touch_mnt_namespace(p->mnt_ns); __touch_mnt_namespace(p->mnt_ns);
if (p->mnt_ns)
__mnt_make_shortterm(p);
p->mnt_ns = NULL; p->mnt_ns = NULL;
__mnt_make_shortterm(p);
list_del_init(&p->mnt_child); list_del_init(&p->mnt_child);
if (mnt_has_parent(p)) { if (mnt_has_parent(p)) {
p->mnt_parent->mnt_ghosts++; p->mnt_parent->mnt_ghosts++;
@ -1112,12 +1114,12 @@ static int do_umount(struct mount *mnt, int flags)
* probably don't strictly need the lock here if we examined * probably don't strictly need the lock here if we examined
* all race cases, but it's a slowpath. * all race cases, but it's a slowpath.
*/ */
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
if (mnt_get_count(mnt) != 2) { if (mnt_get_count(mnt) != 2) {
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return -EBUSY; return -EBUSY;
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
if (!xchg(&mnt->mnt_expiry_mark, 1)) if (!xchg(&mnt->mnt_expiry_mark, 1))
return -EAGAIN; return -EAGAIN;
@ -1159,7 +1161,7 @@ static int do_umount(struct mount *mnt, int flags)
} }
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
event++; event++;
if (!(flags & MNT_DETACH)) if (!(flags & MNT_DETACH))
@ -1171,7 +1173,7 @@ static int do_umount(struct mount *mnt, int flags)
umount_tree(mnt, 1, &umount_list); umount_tree(mnt, 1, &umount_list);
retval = 0; retval = 0;
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);
return retval; return retval;
@ -1286,19 +1288,19 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
q = clone_mnt(p, p->mnt.mnt_root, flag); q = clone_mnt(p, p->mnt.mnt_root, flag);
if (!q) if (!q)
goto Enomem; goto Enomem;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_add_tail(&q->mnt_list, &res->mnt_list); list_add_tail(&q->mnt_list, &res->mnt_list);
attach_mnt(q, &path); attach_mnt(q, &path);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
} }
return res; return res;
Enomem: Enomem:
if (res) { if (res) {
LIST_HEAD(umount_list); LIST_HEAD(umount_list);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
umount_tree(res, 0, &umount_list); umount_tree(res, 0, &umount_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
release_mounts(&umount_list); release_mounts(&umount_list);
} }
return NULL; return NULL;
@ -1318,9 +1320,9 @@ void drop_collected_mounts(struct vfsmount *mnt)
{ {
LIST_HEAD(umount_list); LIST_HEAD(umount_list);
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
umount_tree(real_mount(mnt), 0, &umount_list); umount_tree(real_mount(mnt), 0, &umount_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);
} }
@ -1448,7 +1450,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
if (err) if (err)
goto out_cleanup_ids; goto out_cleanup_ids;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
if (IS_MNT_SHARED(dest_mnt)) { if (IS_MNT_SHARED(dest_mnt)) {
for (p = source_mnt; p; p = next_mnt(p, source_mnt)) for (p = source_mnt; p; p = next_mnt(p, source_mnt))
@ -1467,7 +1469,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
list_del_init(&child->mnt_hash); list_del_init(&child->mnt_hash);
commit_tree(child); commit_tree(child);
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
return 0; return 0;
@ -1565,10 +1567,10 @@ static int do_change_type(struct path *path, int flag)
goto out_unlock; goto out_unlock;
} }
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
change_mnt_propagation(m, type); change_mnt_propagation(m, type);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
out_unlock: out_unlock:
up_write(&namespace_sem); up_write(&namespace_sem);
@ -1617,9 +1619,9 @@ static int do_loopback(struct path *path, char *old_name,
err = graft_tree(mnt, path); err = graft_tree(mnt, path);
if (err) { if (err) {
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
umount_tree(mnt, 0, &umount_list); umount_tree(mnt, 0, &umount_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
out2: out2:
unlock_mount(path); unlock_mount(path);
@ -1677,16 +1679,16 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
else else
err = do_remount_sb(sb, flags, data, 0); err = do_remount_sb(sb, flags, data, 0);
if (!err) { if (!err) {
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK; mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK;
mnt->mnt.mnt_flags = mnt_flags; mnt->mnt.mnt_flags = mnt_flags;
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
up_write(&sb->s_umount); up_write(&sb->s_umount);
if (!err) { if (!err) {
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
touch_mnt_namespace(mnt->mnt_ns); touch_mnt_namespace(mnt->mnt_ns);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
} }
return err; return err;
} }
@ -1893,9 +1895,9 @@ fail:
/* remove m from any expiration list it may be on */ /* remove m from any expiration list it may be on */
if (!list_empty(&mnt->mnt_expire)) { if (!list_empty(&mnt->mnt_expire)) {
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_del_init(&mnt->mnt_expire); list_del_init(&mnt->mnt_expire);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
} }
mntput(m); mntput(m);
@ -1911,11 +1913,11 @@ fail:
void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
{ {
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list); list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
} }
EXPORT_SYMBOL(mnt_set_expiry); EXPORT_SYMBOL(mnt_set_expiry);
@ -1935,7 +1937,7 @@ void mark_mounts_for_expiry(struct list_head *mounts)
return; return;
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
/* extract from the expiration list every vfsmount that matches the /* extract from the expiration list every vfsmount that matches the
* following criteria: * following criteria:
@ -1954,7 +1956,7 @@ void mark_mounts_for_expiry(struct list_head *mounts)
touch_mnt_namespace(mnt->mnt_ns); touch_mnt_namespace(mnt->mnt_ns);
umount_tree(mnt, 1, &umounts); umount_tree(mnt, 1, &umounts);
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umounts); release_mounts(&umounts);
@ -2218,9 +2220,9 @@ void mnt_make_shortterm(struct vfsmount *m)
struct mount *mnt = real_mount(m); struct mount *mnt = real_mount(m);
if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) if (atomic_add_unless(&mnt->mnt_longterm, -1, 1))
return; return;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
atomic_dec(&mnt->mnt_longterm); atomic_dec(&mnt->mnt_longterm);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
#endif #endif
} }
@ -2250,9 +2252,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
new_ns->root = new; new_ns->root = new;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
list_add_tail(&new_ns->list, &new->mnt_list); list_add_tail(&new_ns->list, &new->mnt_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
/* /*
* Second pass: switch the tsk->fs->* elements and mark new vfsmounts * Second pass: switch the tsk->fs->* elements and mark new vfsmounts
@ -2416,9 +2418,9 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
int path_is_under(struct path *path1, struct path *path2) int path_is_under(struct path *path1, struct path *path2)
{ {
int res; int res;
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2); res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2);
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return res; return res;
} }
EXPORT_SYMBOL(path_is_under); EXPORT_SYMBOL(path_is_under);
@ -2505,7 +2507,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* make sure we can reach put_old from new_root */ /* make sure we can reach put_old from new_root */
if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new)) if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new))
goto out4; goto out4;
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
detach_mnt(new_mnt, &parent_path); detach_mnt(new_mnt, &parent_path);
detach_mnt(root_mnt, &root_parent); detach_mnt(root_mnt, &root_parent);
/* mount old root on put_old */ /* mount old root on put_old */
@ -2513,7 +2515,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* mount new_root on / */ /* mount new_root on / */
attach_mnt(new_mnt, &root_parent); attach_mnt(new_mnt, &root_parent);
touch_mnt_namespace(current->nsproxy->mnt_ns); touch_mnt_namespace(current->nsproxy->mnt_ns);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
chroot_fs_refs(&root, &new); chroot_fs_refs(&root, &new);
error = 0; error = 0;
out4: out4:
@ -2576,7 +2578,7 @@ void __init mnt_init(void)
for (u = 0; u < HASH_SIZE; u++) for (u = 0; u < HASH_SIZE; u++)
INIT_LIST_HEAD(&mount_hashtable[u]); INIT_LIST_HEAD(&mount_hashtable[u]);
br_lock_init(vfsmount_lock); br_lock_init(&vfsmount_lock);
err = sysfs_init(); err = sysfs_init();
if (err) if (err)
@ -2596,9 +2598,9 @@ void put_mnt_ns(struct mnt_namespace *ns)
if (!atomic_dec_and_test(&ns->count)) if (!atomic_dec_and_test(&ns->count))
return; return;
down_write(&namespace_sem); down_write(&namespace_sem);
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
umount_tree(ns->root, 0, &umount_list); umount_tree(ns->root, 0, &umount_list);
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);
kfree(ns); kfree(ns);

View File

@ -221,6 +221,10 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
already_written = 0; already_written = 0;
errno = file_update_time(file);
if (errno)
goto outrel;
bouncebuffer = vmalloc(bufsize); bouncebuffer = vmalloc(bufsize);
if (!bouncebuffer) { if (!bouncebuffer) {
errno = -EIO; /* -ENOMEM */ errno = -EIO; /* -ENOMEM */
@ -252,8 +256,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
} }
vfree(bouncebuffer); vfree(bouncebuffer);
file_update_time(file);
*ppos = pos; *ppos = pos;
if (pos > i_size_read(inode)) { if (pos > i_size_read(inode)) {

View File

@ -23,17 +23,17 @@ struct ncp_mount_data_kernel {
unsigned long flags; /* NCP_MOUNT_* flags */ unsigned long flags; /* NCP_MOUNT_* flags */
unsigned int int_flags; /* internal flags */ unsigned int int_flags; /* internal flags */
#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001 #define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001
__kernel_uid32_t mounted_uid; /* Who may umount() this filesystem? */ uid_t mounted_uid; /* Who may umount() this filesystem? */
struct pid *wdog_pid; /* Who cares for our watchdog packets? */ struct pid *wdog_pid; /* Who cares for our watchdog packets? */
unsigned int ncp_fd; /* The socket to the ncp port */ unsigned int ncp_fd; /* The socket to the ncp port */
unsigned int time_out; /* How long should I wait after unsigned int time_out; /* How long should I wait after
sending a NCP request? */ sending a NCP request? */
unsigned int retry_count; /* And how often should I retry? */ unsigned int retry_count; /* And how often should I retry? */
unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
__kernel_uid32_t uid; uid_t uid;
__kernel_gid32_t gid; gid_t gid;
__kernel_mode_t file_mode; umode_t file_mode;
__kernel_mode_t dir_mode; umode_t dir_mode;
int info_fd; int info_fd;
}; };

View File

@ -1354,10 +1354,10 @@ out:
} }
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
static int nfs_open_revalidate(struct dentry *, struct nameidata *); static int nfs4_lookup_revalidate(struct dentry *, struct nameidata *);
const struct dentry_operations nfs4_dentry_operations = { const struct dentry_operations nfs4_dentry_operations = {
.d_revalidate = nfs_open_revalidate, .d_revalidate = nfs4_lookup_revalidate,
.d_delete = nfs_dentry_delete, .d_delete = nfs_dentry_delete,
.d_iput = nfs_dentry_iput, .d_iput = nfs_dentry_iput,
.d_automount = nfs_d_automount, .d_automount = nfs_d_automount,
@ -1519,13 +1519,11 @@ no_open:
return nfs_lookup(dir, dentry, nd); return nfs_lookup(dir, dentry, nd);
} }
static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
struct dentry *parent = NULL; struct dentry *parent = NULL;
struct inode *inode; struct inode *inode;
struct inode *dir; struct inode *dir;
struct nfs_open_context *ctx;
struct iattr attr;
int openflags, ret = 0; int openflags, ret = 0;
if (nd->flags & LOOKUP_RCU) if (nd->flags & LOOKUP_RCU)
@ -1554,57 +1552,13 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* We cannot do exclusive creation on a positive dentry */ /* We cannot do exclusive creation on a positive dentry */
if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
goto no_open_dput; goto no_open_dput;
/* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL);
ctx = create_nfs_open_context(dentry, openflags); /* Let f_op->open() actually open (and revalidate) the file */
ret = PTR_ERR(ctx); ret = 1;
if (IS_ERR(ctx))
goto out;
attr.ia_valid = ATTR_OPEN;
if (openflags & O_TRUNC) {
attr.ia_valid |= ATTR_SIZE;
attr.ia_size = 0;
nfs_wb_all(inode);
}
/*
* Note: we're not holding inode->i_mutex and so may be racing with
* operations that change the directory. We therefore save the
* change attribute *before* we do the RPC call.
*/
inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
switch (ret) {
case -EPERM:
case -EACCES:
case -EDQUOT:
case -ENOSPC:
case -EROFS:
goto out_put_ctx;
default:
goto out_drop;
}
}
iput(inode);
if (inode != dentry->d_inode)
goto out_drop;
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
ret = nfs_intent_set_file(nd, ctx);
if (ret >= 0)
ret = 1;
out: out:
dput(parent); dput(parent);
return ret; return ret;
out_drop:
d_drop(dentry);
ret = 0;
out_put_ctx:
put_nfs_open_context(ctx);
goto out;
no_open_dput: no_open_dput:
dput(parent); dput(parent);

View File

@ -879,12 +879,81 @@ const struct file_operations nfs_file_operations = {
static int static int
nfs4_file_open(struct inode *inode, struct file *filp) nfs4_file_open(struct inode *inode, struct file *filp)
{ {
struct nfs_open_context *ctx;
struct dentry *dentry = filp->f_path.dentry;
struct dentry *parent = NULL;
struct inode *dir;
unsigned openflags = filp->f_flags;
struct iattr attr;
int err;
BUG_ON(inode != dentry->d_inode);
/* /*
* NFSv4 opens are handled in d_lookup and d_revalidate. If we get to * If no cached dentry exists or if it's negative, NFSv4 handled the
* this point, then something is very wrong * opens in ->lookup() or ->create().
*
* We only get this far for a cached positive dentry. We skipped
* revalidation, so handle it here by dropping the dentry and returning
* -EOPENSTALE. The VFS will retry the lookup/create/open.
*/ */
dprintk("NFS: %s called! inode=%p filp=%p\n", __func__, inode, filp);
return -ENOTDIR; dprintk("NFS: open file(%s/%s)\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
if ((openflags & O_ACCMODE) == 3)
openflags--;
/* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL);
parent = dget_parent(dentry);
dir = parent->d_inode;
ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
err = PTR_ERR(ctx);
if (IS_ERR(ctx))
goto out;
attr.ia_valid = ATTR_OPEN;
if (openflags & O_TRUNC) {
attr.ia_valid |= ATTR_SIZE;
attr.ia_size = 0;
nfs_wb_all(inode);
}
inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
switch (err) {
case -EPERM:
case -EACCES:
case -EDQUOT:
case -ENOSPC:
case -EROFS:
goto out_put_ctx;
default:
goto out_drop;
}
}
iput(inode);
if (inode != dentry->d_inode)
goto out_drop;
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
nfs_file_set_open_context(filp, ctx);
err = 0;
out_put_ctx:
put_nfs_open_context(ctx);
out:
dput(parent);
return err;
out_drop:
d_drop(dentry);
err = -EOPENSTALE;
goto out_put_ctx;
} }
const struct file_operations nfs4_file_operations = { const struct file_operations nfs4_file_operations = {

View File

@ -508,31 +508,29 @@ static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh,
return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen); return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen);
} }
static int nilfs_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp, static int nilfs_encode_fh(struct inode *inode, __u32 *fh, int *lenp,
int connectable) struct inode *parent)
{ {
struct nilfs_fid *fid = (struct nilfs_fid *)fh; struct nilfs_fid *fid = (struct nilfs_fid *)fh;
struct inode *inode = dentry->d_inode;
struct nilfs_root *root = NILFS_I(inode)->i_root; struct nilfs_root *root = NILFS_I(inode)->i_root;
int type; int type;
if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE || if (parent && *lenp < NILFS_FID_SIZE_CONNECTABLE) {
(connectable && *lenp < NILFS_FID_SIZE_CONNECTABLE)) *lenp = NILFS_FID_SIZE_CONNECTABLE;
return 255; return 255;
}
if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE) {
*lenp = NILFS_FID_SIZE_NON_CONNECTABLE;
return 255;
}
fid->cno = root->cno; fid->cno = root->cno;
fid->ino = inode->i_ino; fid->ino = inode->i_ino;
fid->gen = inode->i_generation; fid->gen = inode->i_generation;
if (connectable && !S_ISDIR(inode->i_mode)) { if (parent) {
struct inode *parent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
fid->parent_ino = parent->i_ino; fid->parent_ino = parent->i_ino;
fid->parent_gen = parent->i_generation; fid->parent_gen = parent->i_generation;
spin_unlock(&dentry->d_lock);
type = FILEID_NILFS_WITH_PARENT; type = FILEID_NILFS_WITH_PARENT;
*lenp = NILFS_FID_SIZE_CONNECTABLE; *lenp = NILFS_FID_SIZE_CONNECTABLE;
} else { } else {

View File

@ -123,7 +123,7 @@ int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
} }
EXPORT_SYMBOL_GPL(__fsnotify_parent); EXPORT_SYMBOL_GPL(__fsnotify_parent);
static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, static int send_to_group(struct inode *to_tell,
struct fsnotify_mark *inode_mark, struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark, struct fsnotify_mark *vfsmount_mark,
__u32 mask, void *data, __u32 mask, void *data,
@ -168,10 +168,10 @@ static int send_to_group(struct inode *to_tell, struct vfsmount *mnt,
vfsmount_test_mask &= ~inode_mark->ignored_mask; vfsmount_test_mask &= ~inode_mark->ignored_mask;
} }
pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x inode_mark=%p" pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p"
" inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x" " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x"
" data=%p data_is=%d cookie=%d event=%p\n", " data=%p data_is=%d cookie=%d event=%p\n",
__func__, group, to_tell, mnt, mask, inode_mark, __func__, group, to_tell, mask, inode_mark,
inode_test_mask, vfsmount_mark, vfsmount_test_mask, data, inode_test_mask, vfsmount_mark, vfsmount_test_mask, data,
data_is, cookie, *event); data_is, cookie, *event);
@ -258,16 +258,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
if (inode_group > vfsmount_group) { if (inode_group > vfsmount_group) {
/* handle inode */ /* handle inode */
ret = send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, ret = send_to_group(to_tell, inode_mark, NULL, mask, data,
data_is, cookie, file_name, &event); data_is, cookie, file_name, &event);
/* we didn't use the vfsmount_mark */ /* we didn't use the vfsmount_mark */
vfsmount_group = NULL; vfsmount_group = NULL;
} else if (vfsmount_group > inode_group) { } else if (vfsmount_group > inode_group) {
ret = send_to_group(to_tell, &mnt->mnt, NULL, vfsmount_mark, mask, data, ret = send_to_group(to_tell, NULL, vfsmount_mark, mask, data,
data_is, cookie, file_name, &event); data_is, cookie, file_name, &event);
inode_group = NULL; inode_group = NULL;
} else { } else {
ret = send_to_group(to_tell, &mnt->mnt, inode_mark, vfsmount_mark, ret = send_to_group(to_tell, inode_mark, vfsmount_mark,
mask, data, data_is, cookie, file_name, mask, data, data_is, cookie, file_name,
&event); &event);
} }

View File

@ -2096,7 +2096,9 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
err = file_remove_suid(file); err = file_remove_suid(file);
if (err) if (err)
goto out; goto out;
file_update_time(file); err = file_update_time(file);
if (err)
goto out;
written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos, written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos,
count); count);
out: out:

View File

@ -422,45 +422,46 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
struct ocfs2_blockcheck_stats *stats) struct ocfs2_blockcheck_stats *stats)
{ {
int rc = 0; int rc = 0;
struct ocfs2_block_check check; u32 bc_crc32e;
u16 bc_ecc;
u32 crc, ecc; u32 crc, ecc;
ocfs2_blockcheck_inc_check(stats); ocfs2_blockcheck_inc_check(stats);
check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); bc_crc32e = le32_to_cpu(bc->bc_crc32e);
check.bc_ecc = le16_to_cpu(bc->bc_ecc); bc_ecc = le16_to_cpu(bc->bc_ecc);
memset(bc, 0, sizeof(struct ocfs2_block_check)); memset(bc, 0, sizeof(struct ocfs2_block_check));
/* Fast path - if the crc32 validates, we're good to go */ /* Fast path - if the crc32 validates, we're good to go */
crc = crc32_le(~0, data, blocksize); crc = crc32_le(~0, data, blocksize);
if (crc == check.bc_crc32e) if (crc == bc_crc32e)
goto out; goto out;
ocfs2_blockcheck_inc_failure(stats); ocfs2_blockcheck_inc_failure(stats);
mlog(ML_ERROR, mlog(ML_ERROR,
"CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n", "CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc); (unsigned int)bc_crc32e, (unsigned int)crc);
/* Ok, try ECC fixups */ /* Ok, try ECC fixups */
ecc = ocfs2_hamming_encode_block(data, blocksize); ecc = ocfs2_hamming_encode_block(data, blocksize);
ocfs2_hamming_fix_block(data, blocksize, ecc ^ check.bc_ecc); ocfs2_hamming_fix_block(data, blocksize, ecc ^ bc_ecc);
/* And check the crc32 again */ /* And check the crc32 again */
crc = crc32_le(~0, data, blocksize); crc = crc32_le(~0, data, blocksize);
if (crc == check.bc_crc32e) { if (crc == bc_crc32e) {
ocfs2_blockcheck_inc_recover(stats); ocfs2_blockcheck_inc_recover(stats);
goto out; goto out;
} }
mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n", mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc); (unsigned int)bc_crc32e, (unsigned int)crc);
rc = -EIO; rc = -EIO;
out: out:
bc->bc_crc32e = cpu_to_le32(check.bc_crc32e); bc->bc_crc32e = cpu_to_le32(bc_crc32e);
bc->bc_ecc = cpu_to_le16(check.bc_ecc); bc->bc_ecc = cpu_to_le16(bc_ecc);
return rc; return rc;
} }
@ -528,7 +529,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
struct ocfs2_blockcheck_stats *stats) struct ocfs2_blockcheck_stats *stats)
{ {
int i, rc = 0; int i, rc = 0;
struct ocfs2_block_check check; u32 bc_crc32e;
u16 bc_ecc;
u32 crc, ecc, fix; u32 crc, ecc, fix;
BUG_ON(nr < 0); BUG_ON(nr < 0);
@ -538,21 +540,21 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
ocfs2_blockcheck_inc_check(stats); ocfs2_blockcheck_inc_check(stats);
check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); bc_crc32e = le32_to_cpu(bc->bc_crc32e);
check.bc_ecc = le16_to_cpu(bc->bc_ecc); bc_ecc = le16_to_cpu(bc->bc_ecc);
memset(bc, 0, sizeof(struct ocfs2_block_check)); memset(bc, 0, sizeof(struct ocfs2_block_check));
/* Fast path - if the crc32 validates, we're good to go */ /* Fast path - if the crc32 validates, we're good to go */
for (i = 0, crc = ~0; i < nr; i++) for (i = 0, crc = ~0; i < nr; i++)
crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
if (crc == check.bc_crc32e) if (crc == bc_crc32e)
goto out; goto out;
ocfs2_blockcheck_inc_failure(stats); ocfs2_blockcheck_inc_failure(stats);
mlog(ML_ERROR, mlog(ML_ERROR,
"CRC32 failed: stored: %u, computed %u. Applying ECC.\n", "CRC32 failed: stored: %u, computed %u. Applying ECC.\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc); (unsigned int)bc_crc32e, (unsigned int)crc);
/* Ok, try ECC fixups */ /* Ok, try ECC fixups */
for (i = 0, ecc = 0; i < nr; i++) { for (i = 0, ecc = 0; i < nr; i++) {
@ -565,7 +567,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
bhs[i]->b_size * 8, bhs[i]->b_size * 8,
bhs[i]->b_size * 8 * i); bhs[i]->b_size * 8 * i);
} }
fix = ecc ^ check.bc_ecc; fix = ecc ^ bc_ecc;
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
/* /*
* Try the fix against each buffer. It will only affect * Try the fix against each buffer. It will only affect
@ -578,19 +580,19 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
/* And check the crc32 again */ /* And check the crc32 again */
for (i = 0, crc = ~0; i < nr; i++) for (i = 0, crc = ~0; i < nr; i++)
crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
if (crc == check.bc_crc32e) { if (crc == bc_crc32e) {
ocfs2_blockcheck_inc_recover(stats); ocfs2_blockcheck_inc_recover(stats);
goto out; goto out;
} }
mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
(unsigned int)check.bc_crc32e, (unsigned int)crc); (unsigned int)bc_crc32e, (unsigned int)crc);
rc = -EIO; rc = -EIO;
out: out:
bc->bc_crc32e = cpu_to_le32(check.bc_crc32e); bc->bc_crc32e = cpu_to_le32(bc_crc32e);
bc->bc_ecc = cpu_to_le16(check.bc_ecc); bc->bc_ecc = cpu_to_le16(bc_ecc);
return rc; return rc;
} }

View File

@ -293,7 +293,7 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf; struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf;
char *name; char *name;
struct list_head *iter, *head=NULL; struct list_head *iter, *head=NULL;
u64 cookie; __be64 cookie;
u32 flags; u32 flags;
u8 node; u8 node;

View File

@ -679,7 +679,7 @@ struct dlm_query_join_packet {
}; };
union dlm_query_join_response { union dlm_query_join_response {
u32 intval; __be32 intval;
struct dlm_query_join_packet packet; struct dlm_query_join_packet packet;
}; };
@ -755,8 +755,8 @@ struct dlm_query_region {
struct dlm_node_info { struct dlm_node_info {
u8 ni_nodenum; u8 ni_nodenum;
u8 pad1; u8 pad1;
u16 ni_ipv4_port; __be16 ni_ipv4_port;
u32 ni_ipv4_address; __be32 ni_ipv4_address;
}; };
struct dlm_query_nodeinfo { struct dlm_query_nodeinfo {

View File

@ -818,7 +818,7 @@ static void dlm_query_join_packet_to_wire(struct dlm_query_join_packet *packet,
union dlm_query_join_response response; union dlm_query_join_response response;
response.packet = *packet; response.packet = *packet;
*wire = cpu_to_be32(response.intval); *wire = be32_to_cpu(response.intval);
} }
static void dlm_query_join_wire_to_packet(u32 wire, static void dlm_query_join_wire_to_packet(u32 wire,

View File

@ -177,21 +177,23 @@ bail:
return parent; return parent;
} }
static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len, static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len,
int connectable) struct inode *parent)
{ {
struct inode *inode = dentry->d_inode;
int len = *max_len; int len = *max_len;
int type = 1; int type = 1;
u64 blkno; u64 blkno;
u32 generation; u32 generation;
__le32 *fh = (__force __le32 *) fh_in; __le32 *fh = (__force __le32 *) fh_in;
#ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION
#error "You go ahead and fix that mess, then. Somehow"
trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len, trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len,
dentry->d_name.name, dentry->d_name.name,
fh, len, connectable); fh, len, connectable);
#endif
if (connectable && (len < 6)) { if (parent && (len < 6)) {
*max_len = 6; *max_len = 6;
type = 255; type = 255;
goto bail; goto bail;
@ -211,12 +213,7 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff)); fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff));
fh[2] = cpu_to_le32(generation); fh[2] = cpu_to_le32(generation);
if (connectable && !S_ISDIR(inode->i_mode)) { if (parent) {
struct inode *parent;
spin_lock(&dentry->d_lock);
parent = dentry->d_parent->d_inode;
blkno = OCFS2_I(parent)->ip_blkno; blkno = OCFS2_I(parent)->ip_blkno;
generation = parent->i_generation; generation = parent->i_generation;
@ -224,8 +221,6 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff)); fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff));
fh[5] = cpu_to_le32(generation); fh[5] = cpu_to_le32(generation);
spin_unlock(&dentry->d_lock);
len = 6; len = 6;
type = 2; type = 2;

View File

@ -273,11 +273,13 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
inode->i_gid = le32_to_cpu(fe->i_gid); inode->i_gid = le32_to_cpu(fe->i_gid);
/* Fast symlinks will have i_size but no allocated clusters. */ /* Fast symlinks will have i_size but no allocated clusters. */
if (S_ISLNK(inode->i_mode) && !fe->i_clusters) if (S_ISLNK(inode->i_mode) && !fe->i_clusters) {
inode->i_blocks = 0; inode->i_blocks = 0;
else inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops;
} else {
inode->i_blocks = ocfs2_inode_sector_count(inode); inode->i_blocks = ocfs2_inode_sector_count(inode);
inode->i_mapping->a_ops = &ocfs2_aops; inode->i_mapping->a_ops = &ocfs2_aops;
}
inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime); inode->i_atime.tv_sec = le64_to_cpu(fe->i_atime);
inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec); inode->i_atime.tv_nsec = le32_to_cpu(fe->i_atime_nsec);
inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime); inode->i_mtime.tv_sec = le64_to_cpu(fe->i_mtime);
@ -331,10 +333,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
OCFS2_I(inode)->ip_dir_lock_gen = 1; OCFS2_I(inode)->ip_dir_lock_gen = 1;
break; break;
case S_IFLNK: case S_IFLNK:
if (ocfs2_inode_is_fast_symlink(inode)) inode->i_op = &ocfs2_symlink_inode_operations;
inode->i_op = &ocfs2_fast_symlink_inode_operations;
else
inode->i_op = &ocfs2_symlink_inode_operations;
i_size_write(inode, le64_to_cpu(fe->i_size)); i_size_write(inode, le64_to_cpu(fe->i_size));
break; break;
default: default:

View File

@ -864,7 +864,7 @@ int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info,
if (status) if (status)
break; break;
reqp = (struct ocfs2_info_request *)(unsigned long)req_addr; reqp = (struct ocfs2_info_request __user *)(unsigned long)req_addr;
if (!reqp) { if (!reqp) {
status = -EINVAL; status = -EINVAL;
goto bail; goto bail;
@ -888,9 +888,11 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct ocfs2_space_resv sr; struct ocfs2_space_resv sr;
struct ocfs2_new_group_input input; struct ocfs2_new_group_input input;
struct reflink_arguments args; struct reflink_arguments args;
const char *old_path, *new_path; const char __user *old_path;
const char __user *new_path;
bool preserve; bool preserve;
struct ocfs2_info info; struct ocfs2_info info;
void __user *argp = (void __user *)arg;
switch (cmd) { switch (cmd) {
case OCFS2_IOC_GETFLAGS: case OCFS2_IOC_GETFLAGS:
@ -937,17 +939,15 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return ocfs2_group_add(inode, &input); return ocfs2_group_add(inode, &input);
case OCFS2_IOC_REFLINK: case OCFS2_IOC_REFLINK:
if (copy_from_user(&args, (struct reflink_arguments *)arg, if (copy_from_user(&args, argp, sizeof(args)))
sizeof(args)))
return -EFAULT; return -EFAULT;
old_path = (const char *)(unsigned long)args.old_path; old_path = (const char __user *)(unsigned long)args.old_path;
new_path = (const char *)(unsigned long)args.new_path; new_path = (const char __user *)(unsigned long)args.new_path;
preserve = (args.preserve != 0); preserve = (args.preserve != 0);
return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve); return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
case OCFS2_IOC_INFO: case OCFS2_IOC_INFO:
if (copy_from_user(&info, (struct ocfs2_info __user *)arg, if (copy_from_user(&info, argp, sizeof(struct ocfs2_info)))
sizeof(struct ocfs2_info)))
return -EFAULT; return -EFAULT;
return ocfs2_info_handle(inode, &info, 0); return ocfs2_info_handle(inode, &info, 0);
@ -960,22 +960,20 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (copy_from_user(&range, (struct fstrim_range *)arg, if (copy_from_user(&range, argp, sizeof(range)))
sizeof(range)))
return -EFAULT; return -EFAULT;
ret = ocfs2_trim_fs(sb, &range); ret = ocfs2_trim_fs(sb, &range);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (copy_to_user((struct fstrim_range *)arg, &range, if (copy_to_user(argp, &range, sizeof(range)))
sizeof(range)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case OCFS2_IOC_MOVE_EXT: case OCFS2_IOC_MOVE_EXT:
return ocfs2_ioctl_move_extents(filp, (void __user *)arg); return ocfs2_ioctl_move_extents(filp, argp);
default: default:
return -ENOTTY; return -ENOTTY;
} }
@ -988,6 +986,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
struct reflink_arguments args; struct reflink_arguments args;
struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode;
struct ocfs2_info info; struct ocfs2_info info;
void __user *argp = (void __user *)arg;
switch (cmd) { switch (cmd) {
case OCFS2_IOC32_GETFLAGS: case OCFS2_IOC32_GETFLAGS:
@ -1006,16 +1005,14 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case FITRIM: case FITRIM:
break; break;
case OCFS2_IOC_REFLINK: case OCFS2_IOC_REFLINK:
if (copy_from_user(&args, (struct reflink_arguments *)arg, if (copy_from_user(&args, argp, sizeof(args)))
sizeof(args)))
return -EFAULT; return -EFAULT;
preserve = (args.preserve != 0); preserve = (args.preserve != 0);
return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path), return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path),
compat_ptr(args.new_path), preserve); compat_ptr(args.new_path), preserve);
case OCFS2_IOC_INFO: case OCFS2_IOC_INFO:
if (copy_from_user(&info, (struct ocfs2_info __user *)arg, if (copy_from_user(&info, argp, sizeof(struct ocfs2_info)))
sizeof(struct ocfs2_info)))
return -EFAULT; return -EFAULT;
return ocfs2_info_handle(inode, &info, 1); return ocfs2_info_handle(inode, &info, 1);

View File

@ -1082,8 +1082,7 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp)
context->file = filp; context->file = filp;
if (argp) { if (argp) {
if (copy_from_user(&range, (struct ocfs2_move_extents *)argp, if (copy_from_user(&range, argp, sizeof(range))) {
sizeof(range))) {
status = -EFAULT; status = -EFAULT;
goto out; goto out;
} }
@ -1138,8 +1137,7 @@ out:
* length and new_offset even if failure happens somewhere. * length and new_offset even if failure happens somewhere.
*/ */
if (argp) { if (argp) {
if (copy_to_user((struct ocfs2_move_extents *)argp, &range, if (copy_to_user(argp, &range, sizeof(range)))
sizeof(range)))
status = -EFAULT; status = -EFAULT;
} }

View File

@ -1724,15 +1724,16 @@ static int ocfs2_symlink(struct inode *dir,
fe = (struct ocfs2_dinode *) new_fe_bh->b_data; fe = (struct ocfs2_dinode *) new_fe_bh->b_data;
inode->i_rdev = 0; inode->i_rdev = 0;
newsize = l - 1; newsize = l - 1;
inode->i_op = &ocfs2_symlink_inode_operations;
if (l > ocfs2_fast_symlink_chars(sb)) { if (l > ocfs2_fast_symlink_chars(sb)) {
u32 offset = 0; u32 offset = 0;
inode->i_op = &ocfs2_symlink_inode_operations;
status = dquot_alloc_space_nodirty(inode, status = dquot_alloc_space_nodirty(inode,
ocfs2_clusters_to_bytes(osb->sb, 1)); ocfs2_clusters_to_bytes(osb->sb, 1));
if (status) if (status)
goto bail; goto bail;
did_quota = 1; did_quota = 1;
inode->i_mapping->a_ops = &ocfs2_aops;
status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0, status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
new_fe_bh, new_fe_bh,
handle, data_ac, NULL, handle, data_ac, NULL,
@ -1750,7 +1751,7 @@ static int ocfs2_symlink(struct inode *dir,
i_size_write(inode, newsize); i_size_write(inode, newsize);
inode->i_blocks = ocfs2_inode_sector_count(inode); inode->i_blocks = ocfs2_inode_sector_count(inode);
} else { } else {
inode->i_op = &ocfs2_fast_symlink_inode_operations; inode->i_mapping->a_ops = &ocfs2_fast_symlink_aops;
memcpy((char *) fe->id2.i_symlink, symname, l); memcpy((char *) fe->id2.i_symlink, symname, l);
i_size_write(inode, newsize); i_size_write(inode, newsize);
inode->i_blocks = 0; inode->i_blocks = 0;

View File

@ -54,101 +54,40 @@
#include "buffer_head_io.h" #include "buffer_head_io.h"
static char *ocfs2_fast_symlink_getlink(struct inode *inode, static int ocfs2_fast_symlink_readpage(struct file *unused, struct page *page)
struct buffer_head **bh)
{ {
int status; struct inode *inode = page->mapping->host;
char *link = NULL; struct buffer_head *bh;
int status = ocfs2_read_inode_block(inode, &bh);
struct ocfs2_dinode *fe; struct ocfs2_dinode *fe;
const char *link;
void *kaddr;
size_t len;
status = ocfs2_read_inode_block(inode, bh);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
link = ERR_PTR(status); return status;
goto bail;
} }
fe = (struct ocfs2_dinode *) (*bh)->b_data; fe = (struct ocfs2_dinode *) bh->b_data;
link = (char *) fe->id2.i_symlink; link = (char *) fe->id2.i_symlink;
bail: /* will be less than a page size */
len = strnlen(link, ocfs2_fast_symlink_chars(inode->i_sb));
return link; kaddr = kmap_atomic(page);
} memcpy(kaddr, link, len + 1);
kunmap_atomic(kaddr);
static int ocfs2_readlink(struct dentry *dentry, SetPageUptodate(page);
char __user *buffer, unlock_page(page);
int buflen)
{
int ret;
char *link;
struct buffer_head *bh = NULL;
struct inode *inode = dentry->d_inode;
link = ocfs2_fast_symlink_getlink(inode, &bh);
if (IS_ERR(link)) {
ret = PTR_ERR(link);
goto out;
}
/*
* Without vfsmount we can't update atime now,
* but we will update atime here ultimately.
*/
ret = vfs_readlink(dentry, buffer, buflen, link);
brelse(bh); brelse(bh);
out: return 0;
if (ret < 0)
mlog_errno(ret);
return ret;
} }
static void *ocfs2_fast_follow_link(struct dentry *dentry, const struct address_space_operations ocfs2_fast_symlink_aops = {
struct nameidata *nd) .readpage = ocfs2_fast_symlink_readpage,
{ };
int status = 0;
int len;
char *target, *link = ERR_PTR(-ENOMEM);
struct inode *inode = dentry->d_inode;
struct buffer_head *bh = NULL;
BUG_ON(!ocfs2_inode_is_fast_symlink(inode));
target = ocfs2_fast_symlink_getlink(inode, &bh);
if (IS_ERR(target)) {
status = PTR_ERR(target);
mlog_errno(status);
goto bail;
}
/* Fast symlinks can't be large */
len = strnlen(target, ocfs2_fast_symlink_chars(inode->i_sb));
link = kzalloc(len + 1, GFP_NOFS);
if (!link) {
status = -ENOMEM;
mlog_errno(status);
goto bail;
}
memcpy(link, target, len);
bail:
nd_set_link(nd, status ? ERR_PTR(status) : link);
brelse(bh);
if (status)
mlog_errno(status);
return NULL;
}
static void ocfs2_fast_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
{
char *link = nd_get_link(nd);
if (!IS_ERR(link))
kfree(link);
}
const struct inode_operations ocfs2_symlink_inode_operations = { const struct inode_operations ocfs2_symlink_inode_operations = {
.readlink = page_readlink, .readlink = generic_readlink,
.follow_link = page_follow_link_light, .follow_link = page_follow_link_light,
.put_link = page_put_link, .put_link = page_put_link,
.getattr = ocfs2_getattr, .getattr = ocfs2_getattr,
@ -159,15 +98,3 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
.removexattr = generic_removexattr, .removexattr = generic_removexattr,
.fiemap = ocfs2_fiemap, .fiemap = ocfs2_fiemap,
}; };
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
.readlink = ocfs2_readlink,
.follow_link = ocfs2_fast_follow_link,
.put_link = ocfs2_fast_put_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ocfs2_listxattr,
.removexattr = generic_removexattr,
.fiemap = ocfs2_fiemap,
};

View File

@ -27,7 +27,7 @@
#define OCFS2_SYMLINK_H #define OCFS2_SYMLINK_H
extern const struct inode_operations ocfs2_symlink_inode_operations; extern const struct inode_operations ocfs2_symlink_inode_operations;
extern const struct inode_operations ocfs2_fast_symlink_inode_operations; extern const struct address_space_operations ocfs2_fast_symlink_aops;
/* /*
* Test whether an inode is a fast symlink. * Test whether an inode is a fast symlink.

View File

@ -654,10 +654,23 @@ static inline int __get_file_write_access(struct inode *inode,
return error; return error;
} }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, int open_check_o_direct(struct file *f)
struct file *f, {
int (*open)(struct inode *, struct file *), /* NB: we're sure to have correct a_ops only after f_op->open */
const struct cred *cred) if (f->f_flags & O_DIRECT) {
if (!f->f_mapping->a_ops ||
((!f->f_mapping->a_ops->direct_IO) &&
(!f->f_mapping->a_ops->get_xip_mem))) {
return -EINVAL;
}
}
return 0;
}
static struct file *do_dentry_open(struct dentry *dentry, struct vfsmount *mnt,
struct file *f,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{ {
static const struct file_operations empty_fops = {}; static const struct file_operations empty_fops = {};
struct inode *inode; struct inode *inode;
@ -713,16 +726,6 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
/* NB: we're sure to have correct a_ops only after f_op->open */
if (f->f_flags & O_DIRECT) {
if (!f->f_mapping->a_ops ||
((!f->f_mapping->a_ops->direct_IO) &&
(!f->f_mapping->a_ops->get_xip_mem))) {
fput(f);
f = ERR_PTR(-EINVAL);
}
}
return f; return f;
cleanup_all: cleanup_all:
@ -744,12 +747,29 @@ cleanup_all:
f->f_path.dentry = NULL; f->f_path.dentry = NULL;
f->f_path.mnt = NULL; f->f_path.mnt = NULL;
cleanup_file: cleanup_file:
put_filp(f);
dput(dentry); dput(dentry);
mntput(mnt); mntput(mnt);
return ERR_PTR(error); return ERR_PTR(error);
} }
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
struct file *f,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{
struct file *res = do_dentry_open(dentry, mnt, f, open, cred);
if (!IS_ERR(res)) {
int error = open_check_o_direct(f);
if (error) {
fput(res);
res = ERR_PTR(error);
}
} else {
put_filp(f);
}
return res;
}
/** /**
* lookup_instantiate_filp - instantiates the open intent filp * lookup_instantiate_filp - instantiates the open intent filp
* @nd: pointer to nameidata * @nd: pointer to nameidata
@ -804,13 +824,31 @@ struct file *nameidata_to_filp(struct nameidata *nd)
/* Pick up the filp from the open intent */ /* Pick up the filp from the open intent */
filp = nd->intent.open.file; filp = nd->intent.open.file;
nd->intent.open.file = NULL;
/* Has the filesystem initialised the file for us? */ /* Has the filesystem initialised the file for us? */
if (filp->f_path.dentry == NULL) { if (filp->f_path.dentry != NULL) {
nd->intent.open.file = NULL;
} else {
struct file *res;
path_get(&nd->path); path_get(&nd->path);
filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp, res = do_dentry_open(nd->path.dentry, nd->path.mnt,
NULL, cred); filp, NULL, cred);
if (!IS_ERR(res)) {
int error;
nd->intent.open.file = NULL;
BUG_ON(res != filp);
error = open_check_o_direct(filp);
if (error) {
fput(filp);
filp = ERR_PTR(error);
}
} else {
/* Allow nd->intent.open.file to be recycled */
filp = res;
}
} }
return filp; return filp;
} }

View File

@ -654,8 +654,11 @@ out:
wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM);
kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
} }
if (ret > 0) if (ret > 0) {
file_update_time(filp); int err = file_update_time(filp);
if (err)
ret = err;
}
return ret; return ret;
} }

View File

@ -257,12 +257,12 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,
prev_src_mnt = child; prev_src_mnt = child;
} }
out: out:
br_write_lock(vfsmount_lock); br_write_lock(&vfsmount_lock);
while (!list_empty(&tmp_list)) { while (!list_empty(&tmp_list)) {
child = list_first_entry(&tmp_list, struct mount, mnt_hash); child = list_first_entry(&tmp_list, struct mount, mnt_hash);
umount_tree(child, 0, &umount_list); umount_tree(child, 0, &umount_list);
} }
br_write_unlock(vfsmount_lock); br_write_unlock(&vfsmount_lock);
release_mounts(&umount_list); release_mounts(&umount_list);
return ret; return ret;
} }

View File

@ -23,12 +23,12 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
poll_wait(file, &p->ns->poll, wait); poll_wait(file, &p->ns->poll, wait);
br_read_lock(vfsmount_lock); br_read_lock(&vfsmount_lock);
if (p->m.poll_event != ns->event) { if (p->m.poll_event != ns->event) {
p->m.poll_event = ns->event; p->m.poll_event = ns->event;
res |= POLLERR | POLLPRI; res |= POLLERR | POLLPRI;
} }
br_read_unlock(vfsmount_lock); br_read_unlock(&vfsmount_lock);
return res; return res;
} }

View File

@ -108,11 +108,11 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
int error; int error;
struct file * file; struct file * file;
struct readdir_callback buf; struct readdir_callback buf;
int fput_needed;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.result = 0; buf.result = 0;
buf.dirent = dirent; buf.dirent = dirent;
@ -121,8 +121,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
if (buf.result) if (buf.result)
error = buf.result; error = buf.result;
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }
@ -195,16 +194,15 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
struct file * file; struct file * file;
struct linux_dirent __user * lastdirent; struct linux_dirent __user * lastdirent;
struct getdents_callback buf; struct getdents_callback buf;
int fput_needed;
int error; int error;
error = -EFAULT;
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
goto out; return -EFAULT;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.current_dir = dirent; buf.current_dir = dirent;
buf.previous = NULL; buf.previous = NULL;
@ -221,8 +219,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }
@ -278,16 +275,15 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
struct file * file; struct file * file;
struct linux_dirent64 __user * lastdirent; struct linux_dirent64 __user * lastdirent;
struct getdents_callback64 buf; struct getdents_callback64 buf;
int fput_needed;
int error; int error;
error = -EFAULT;
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
goto out; return -EFAULT;
error = -EBADF; file = fget_light(fd, &fput_needed);
file = fget(fd);
if (!file) if (!file)
goto out; return -EBADF;
buf.current_dir = dirent; buf.current_dir = dirent;
buf.previous = NULL; buf.previous = NULL;
@ -305,7 +301,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fput(file); fput_light(file, fput_needed);
out:
return error; return error;
} }

View File

@ -1592,13 +1592,12 @@ struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
(fh_type == 6) ? fid->raw[5] : 0); (fh_type == 6) ? fid->raw[5] : 0);
} }
int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp, int reiserfs_encode_fh(struct inode *inode, __u32 * data, int *lenp,
int need_parent) struct inode *parent)
{ {
struct inode *inode = dentry->d_inode;
int maxlen = *lenp; int maxlen = *lenp;
if (need_parent && (maxlen < 5)) { if (parent && (maxlen < 5)) {
*lenp = 5; *lenp = 5;
return 255; return 255;
} else if (maxlen < 3) { } else if (maxlen < 3) {
@ -1610,20 +1609,15 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
data[2] = inode->i_generation; data[2] = inode->i_generation;
*lenp = 3; *lenp = 3;
/* no room for directory info? return what we've stored so far */ if (parent) {
if (maxlen < 5 || !need_parent) data[3] = parent->i_ino;
return 3; data[4] = le32_to_cpu(INODE_PKEY(parent)->k_dir_id);
*lenp = 5;
spin_lock(&dentry->d_lock); if (maxlen >= 6) {
inode = dentry->d_parent->d_inode; data[5] = parent->i_generation;
data[3] = inode->i_ino; *lenp = 6;
data[4] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id); }
*lenp = 5;
if (maxlen >= 6) {
data[5] = inode->i_generation;
*lenp = 6;
} }
spin_unlock(&dentry->d_lock);
return *lenp; return *lenp;
} }

View File

@ -1923,6 +1923,8 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
* the workqueue job (flush_async_commit) needs this lock * the workqueue job (flush_async_commit) needs this lock
*/ */
reiserfs_write_unlock(sb); reiserfs_write_unlock(sb);
cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work);
flush_workqueue(commit_wq); flush_workqueue(commit_wq);
if (!reiserfs_mounted_fs_count) { if (!reiserfs_mounted_fs_count) {
@ -3231,8 +3233,6 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
th->t_trans_id, journal->j_trans_id); th->t_trans_id, journal->j_trans_id);
} }
sb->s_dirt = 1;
prepared = test_clear_buffer_journal_prepared(bh); prepared = test_clear_buffer_journal_prepared(bh);
clear_buffer_journal_restore_dirty(bh); clear_buffer_journal_restore_dirty(bh);
/* already in this transaction, we are done */ /* already in this transaction, we are done */
@ -3316,6 +3316,7 @@ int journal_mark_dirty(struct reiserfs_transaction_handle *th,
journal->j_first = cn; journal->j_first = cn;
journal->j_last = cn; journal->j_last = cn;
} }
reiserfs_schedule_old_flush(sb);
return 0; return 0;
} }
@ -3492,7 +3493,7 @@ static void flush_async_commits(struct work_struct *work)
** flushes any old transactions to disk ** flushes any old transactions to disk
** ends the current transaction if it is too old ** ends the current transaction if it is too old
*/ */
int reiserfs_flush_old_commits(struct super_block *sb) void reiserfs_flush_old_commits(struct super_block *sb)
{ {
time_t now; time_t now;
struct reiserfs_transaction_handle th; struct reiserfs_transaction_handle th;
@ -3502,9 +3503,8 @@ int reiserfs_flush_old_commits(struct super_block *sb)
/* safety check so we don't flush while we are replaying the log during /* safety check so we don't flush while we are replaying the log during
* mount * mount
*/ */
if (list_empty(&journal->j_journal_list)) { if (list_empty(&journal->j_journal_list))
return 0; return;
}
/* check the current transaction. If there are no writers, and it is /* check the current transaction. If there are no writers, and it is
* too old, finish it, and force the commit blocks to disk * too old, finish it, and force the commit blocks to disk
@ -3526,7 +3526,6 @@ int reiserfs_flush_old_commits(struct super_block *sb)
do_journal_end(&th, sb, 1, COMMIT_NOW | WAIT); do_journal_end(&th, sb, 1, COMMIT_NOW | WAIT);
} }
} }
return sb->s_dirt;
} }
/* /*
@ -3955,7 +3954,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
** it tells us if we should continue with the journal_end, or just return ** it tells us if we should continue with the journal_end, or just return
*/ */
if (!check_journal_end(th, sb, nblocks, flags)) { if (!check_journal_end(th, sb, nblocks, flags)) {
sb->s_dirt = 1; reiserfs_schedule_old_flush(sb);
wake_queued_writers(sb); wake_queued_writers(sb);
reiserfs_async_progress_wait(sb); reiserfs_async_progress_wait(sb);
goto out; goto out;

Some files were not shown because too many files have changed in this diff Show More