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

Pull second set of VFS changes from Al Viro:
 "Assorted f_pos race fixes, making do_splice_direct() safe to call with
  i_mutex on parent, O_TMPFILE support, Jeff's locks.c series,
  ->d_hash/->d_compare calling conventions changes from Linus, misc
  stuff all over the place."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (63 commits)
  Document ->tmpfile()
  ext4: ->tmpfile() support
  vfs: export lseek_execute() to modules
  lseek_execute() doesn't need an inode passed to it
  block_dev: switch to fixed_size_llseek()
  cpqphp_sysfs: switch to fixed_size_llseek()
  tile-srom: switch to fixed_size_llseek()
  proc_powerpc: switch to fixed_size_llseek()
  ubi/cdev: switch to fixed_size_llseek()
  pci/proc: switch to fixed_size_llseek()
  isapnp: switch to fixed_size_llseek()
  lpfc: switch to fixed_size_llseek()
  locks: give the blocked_hash its own spinlock
  locks: add a new "lm_owner_key" lock operation
  locks: turn the blocked_list into a hashtable
  locks: convert fl_link to a hlist_node
  locks: avoid taking global lock if possible when waking up blocked waiters
  locks: protect most of the file_lock handling with i_lock
  locks: encapsulate the fl_link list handling
  locks: make "added" in __posix_lock_file a bool
  ...
This commit is contained in:
Linus Torvalds 2013-07-03 09:10:19 -07:00
commit 790eac5640
98 changed files with 978 additions and 985 deletions

View File

@ -11,10 +11,8 @@ be able to use diff(1).
prototypes:
int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *,
struct qstr *);
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
@ -66,6 +64,7 @@ prototypes:
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
locking rules:
all may block
@ -93,6 +92,7 @@ removexattr: yes
fiemap: no
update_time: no
atomic_open: yes
tmpfile: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
@ -344,25 +344,38 @@ prototypes:
locking rules:
file_lock_lock may block
inode->i_lock may block
fl_copy_lock: yes no
fl_release_private: maybe no
----------------------- lock_manager_operations ---------------------------
prototypes:
int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
unsigned long (*lm_owner_key)(struct file_lock *);
void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, struct file_lock *, int);
void (*lm_break)(struct file_lock *); /* break_lease callback */
int (*lm_change)(struct file_lock **, int);
locking rules:
file_lock_lock may block
lm_compare_owner: yes no
lm_notify: yes no
lm_grant: no no
lm_break: yes no
lm_change yes no
inode->i_lock blocked_lock_lock may block
lm_compare_owner: yes[1] maybe no
lm_owner_key yes[1] yes no
lm_notify: yes yes no
lm_grant: no no no
lm_break: yes no no
lm_change yes no no
[1]: ->lm_compare_owner and ->lm_owner_key are generally called with
*an* inode->i_lock held. It may not be the i_lock of the inode
associated with either file_lock argument! This is the case with deadlock
detection, since the code has to chase down the owners of locks that may
be entirely unrelated to the one on which the lock is being acquired.
For deadlock detection however, the blocked_lock_lock is also held. The
fact that these locks are held ensures that the file_locks do not
disappear out from under you while doing the comparison or generating an
owner key.
--------------------------- buffer_head -----------------------------------
prototypes:

View File

@ -360,6 +360,8 @@ struct inode_operations {
int (*removexattr) (struct dentry *, const char *);
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *,
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
} ____cacheline_aligned;
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
};
@ -472,6 +474,9 @@ otherwise noted.
component is negative or needs lookup. Cached positive dentries are
still handled by f_op->open().
tmpfile: called in the end of O_TMPFILE open(). Optional, equivalent to
atomically creating, opening and unlinking a file in given directory.
The Address Space Object
========================
@ -901,10 +906,8 @@ defined:
struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *,
struct qstr *);
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
@ -949,25 +952,24 @@ struct dentry_operations {
d_hash: called when the VFS adds a dentry to the hash table. The first
dentry passed to d_hash is the parent directory that the name is
to be hashed into. The inode is the dentry's inode.
to be hashed into.
Same locking and synchronisation rules as d_compare regarding
what is safe to dereference etc.
d_compare: called to compare a dentry name with a given name. The first
dentry is the parent of the dentry to be compared, the second is
the parent's inode, then the dentry and inode (may be NULL) of the
child dentry. len and name string are properties of the dentry to be
compared. qstr is the name to compare it with.
the child dentry. len and name string are properties of the dentry
to be compared. qstr is the name to compare it with.
Must be constant and idempotent, and should not take locks if
possible, and should not or store into the dentry or inodes.
Should not dereference pointers outside the dentry or inodes without
possible, and should not or store into the dentry.
Should not dereference pointers outside the dentry without
lots of care (eg. d_parent, d_inode, d_name should not be used).
However, our vfsmount is pinned, and RCU held, so the dentries and
inodes won't disappear, neither will our sb or filesystem module.
->i_sb and ->d_sb may be used.
->d_sb may be used.
It is a tricky calling convention because it needs to be called under
"rcu-walk", ie. without any locks or references on things.

View File

@ -32,6 +32,7 @@
#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_PATH 040000000
#define O_TMPFILE 0100000000
#define F_GETLK 7
#define F_SETLK 8

View File

@ -101,7 +101,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
if (file) {
struct path *path = &file->f_path;
nm = d_path(path, buf, PAGE_SIZE - 1);
inode = vma->vm_file->f_path.dentry->d_inode;
inode = file_inode(vma->vm_file);
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}

View File

@ -20,6 +20,7 @@
#define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */
#define O_PATH 020000000
#define O_TMPFILE 040000000
#define F_GETLK64 8
#define F_SETLK64 9

View File

@ -29,25 +29,9 @@
#ifdef CONFIG_PPC64
static loff_t page_map_seek( struct file *file, loff_t off, int whence)
static loff_t page_map_seek(struct file *file, loff_t off, int whence)
{
loff_t new;
switch(whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
case 2:
new = PAGE_SIZE + off;
break;
default:
return -EINVAL;
}
if ( new < 0 || new > PAGE_SIZE )
return -EINVAL;
return (file->f_pos = new);
return fixed_size_llseek(file, off, whence, PAGE_SIZE);
}
static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,

View File

@ -35,6 +35,7 @@
#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_PATH 0x1000000
#define O_TMPFILE 0x2000000
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */

View File

@ -98,32 +98,8 @@ static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
{
struct ps3_storage_device *dev = ps3flash_dev;
loff_t res;
mutex_lock(&file->f_mapping->host->i_mutex);
switch (origin) {
case 0:
break;
case 1:
offset += file->f_pos;
break;
case 2:
offset += dev->regions[dev->region_idx].size*dev->blk_size;
break;
default:
offset = -1;
}
if (offset < 0) {
res = -EINVAL;
goto out;
}
file->f_pos = offset;
res = file->f_pos;
out:
mutex_unlock(&file->f_mapping->host->i_mutex);
return res;
return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
dev->regions[dev->region_idx].size*dev->blk_size);
}
static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,

View File

@ -273,32 +273,10 @@ static ssize_t srom_write(struct file *filp, const char __user *buf,
}
/* Provide our own implementation so we can use srom->total_size. */
loff_t srom_llseek(struct file *filp, loff_t offset, int origin)
loff_t srom_llseek(struct file *file, loff_t offset, int origin)
{
struct srom_dev *srom = filp->private_data;
if (mutex_lock_interruptible(&srom->lock))
return -ERESTARTSYS;
switch (origin) {
case SEEK_END:
offset += srom->total_size;
break;
case SEEK_CUR:
offset += filp->f_pos;
break;
}
if (offset < 0 || offset > srom->total_size) {
offset = -EINVAL;
} else {
filp->f_pos = offset;
filp->f_version = 0;
}
mutex_unlock(&srom->lock);
return offset;
struct srom_dev *srom = file->private_data;
return fixed_size_llseek(file, offset, origin, srom->total_size);
}
static ssize_t total_show(struct device *dev,

View File

@ -55,25 +55,7 @@ struct mtd_file_info {
static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig)
{
struct mtd_file_info *mfi = file->private_data;
struct mtd_info *mtd = mfi->mtd;
switch (orig) {
case SEEK_SET:
break;
case SEEK_CUR:
offset += file->f_pos;
break;
case SEEK_END:
offset += mtd->size;
break;
default:
return -EINVAL;
}
if (offset >= 0 && offset <= mtd->size)
return file->f_pos = offset;
return -EINVAL;
return fixed_size_llseek(file, offset, orig, mfi->mtd->size);
}
static int count;

View File

@ -155,7 +155,6 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
{
struct ubi_volume_desc *desc = file->private_data;
struct ubi_volume *vol = desc->vol;
loff_t new_offset;
if (vol->updating) {
/* Update is in progress, seeking is prohibited */
@ -163,30 +162,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
return -EBUSY;
}
switch (origin) {
case 0: /* SEEK_SET */
new_offset = offset;
break;
case 1: /* SEEK_CUR */
new_offset = file->f_pos + offset;
break;
case 2: /* SEEK_END */
new_offset = vol->used_bytes + offset;
break;
default:
return -EINVAL;
}
if (new_offset < 0 || new_offset > vol->used_bytes) {
ubi_err("bad seek %lld", new_offset);
return -EINVAL;
}
dbg_gen("seek volume %d, offset %lld, origin %d, new offset %lld",
vol->vol_id, offset, origin, new_offset);
file->f_pos = new_offset;
return new_offset;
return fixed_size_llseek(file, offset, origin, vol->used_bytes);
}
static int vol_cdev_fsync(struct file *file, loff_t start, loff_t end,

View File

@ -230,32 +230,12 @@ bnad_debugfs_open_drvinfo(struct inode *inode, struct file *file)
static loff_t
bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
{
loff_t pos = file->f_pos;
struct bnad_debug_info *debug = file->private_data;
if (!debug)
return -EINVAL;
switch (orig) {
case 0:
file->f_pos = offset;
break;
case 1:
file->f_pos += offset;
break;
case 2:
file->f_pos = debug->buffer_len + offset;
break;
default:
return -EINVAL;
}
if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
file->f_pos = pos;
return -EINVAL;
}
return file->f_pos;
return fixed_size_llseek(file, offset, orig, debug->buffer_len);
}
static ssize_t

View File

@ -1056,7 +1056,7 @@ static ssize_t dev_mem_read(struct file *file,
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.start = *ppos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);
@ -1137,7 +1137,7 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
return -EINVAL;
memset(&part, 0, sizeof(part));
part.mem.start = file->f_pos;
part.mem.start = *ppos;
part.mem.size = bytes;
buf = kmalloc(bytes, GFP_KERNEL);

View File

@ -31,20 +31,9 @@
#define EISA_EEPROM_MINOR 241
static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin )
static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin)
{
switch (origin) {
case 0:
/* nothing to do */
break;
case 1:
offset += file->f_pos;
break;
case 2:
offset += HPEE_MAX_LENGTH;
break;
}
return (offset >= 0 && offset < HPEE_MAX_LENGTH) ? (file->f_pos = offset) : -EINVAL;
return fixed_size_llseek(file, offset, origin, HPEE_MAX_LENGTH);
}
static ssize_t eisa_eeprom_read(struct file * file,

View File

@ -167,26 +167,8 @@ exit:
static loff_t lseek(struct file *file, loff_t off, int whence)
{
struct ctrl_dbg *dbg;
loff_t new = -1;
mutex_lock(&cpqphp_mutex);
dbg = file->private_data;
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
}
if (new < 0 || new > dbg->size) {
mutex_unlock(&cpqphp_mutex);
return -EINVAL;
}
mutex_unlock(&cpqphp_mutex);
return (file->f_pos = new);
struct ctrl_dbg *dbg = file->private_data;
return fixed_size_llseek(file, off, whence, dbg->size);
}
static ssize_t read(struct file *file, char __user *buf,

View File

@ -20,27 +20,8 @@ static int proc_initialized; /* = 0 */
static loff_t
proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
struct inode *inode = file_inode(file);
mutex_lock(&inode->i_mutex);
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
case 2:
new = inode->i_size + off;
break;
}
if (new < 0 || new > inode->i_size)
new = -EINVAL;
else
file->f_pos = new;
mutex_unlock(&inode->i_mutex);
return new;
struct pci_dev *dev = PDE_DATA(file_inode(file));
return fixed_size_llseek(file, off, whence, dev->cfg_size);
}
static ssize_t

View File

@ -29,27 +29,7 @@ static struct proc_dir_entry *isapnp_proc_bus_dir = NULL;
static loff_t isapnp_proc_bus_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
struct inode *inode = file_inode(file);
mutex_lock(&inode->i_mutex);
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
case 2:
new = 256 + off;
break;
}
if (new < 0 || new > 256)
new = -EINVAL;
else
file->f_pos = new;
mutex_unlock(&inode->i_mutex);
return new;
return fixed_size_llseek(file, off, whence, 256);
}
static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,

View File

@ -173,31 +173,9 @@ bfad_debugfs_open_reg(struct inode *inode, struct file *file)
static loff_t
bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
{
struct bfad_debug_info *debug;
loff_t pos = file->f_pos;
debug = file->private_data;
switch (orig) {
case 0:
file->f_pos = offset;
break;
case 1:
file->f_pos += offset;
break;
case 2:
file->f_pos = debug->buffer_len + offset;
break;
default:
return -EINVAL;
}
if (file->f_pos < 0 || file->f_pos > debug->buffer_len) {
file->f_pos = pos;
return -EINVAL;
}
return file->f_pos;
struct bfad_debug_info *debug = file->private_data;
return fixed_size_llseek(file, offset, orig,
debug->buffer_len);
}
static ssize_t

View File

@ -164,20 +164,8 @@ static loff_t fnic_trace_debugfs_lseek(struct file *file,
int howto)
{
fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
loff_t pos = -1;
switch (howto) {
case 0:
pos = offset;
break;
case 1:
pos = file->f_pos + offset;
break;
case 2:
pos = fnic_dbg_prt->buffer_len + offset;
}
return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ?
-EINVAL : (file->f_pos = pos);
return fixed_size_llseek(file, offset, howto,
fnic_dbg_prt->buffer_len);
}
/*

View File

@ -1165,22 +1165,8 @@ out:
static loff_t
lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
{
struct lpfc_debug *debug;
loff_t pos = -1;
debug = file->private_data;
switch (whence) {
case 0:
pos = off;
break;
case 1:
pos = file->f_pos + off;
break;
case 2:
pos = debug->len + off;
}
return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
struct lpfc_debug *debug = file->private_data;
return fixed_size_llseek(file, off, whence, debug->len);
}
/**

View File

@ -696,7 +696,7 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EBADF;
break;
}
if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
if (!(in_egroup_p(file_inode(file)->i_gid) ||
capable(CAP_SYSLOG))) {
ret = -EPERM;
break;

View File

@ -2329,9 +2329,6 @@ static int comedi_close(struct inode *inode, struct file *file)
mutex_unlock(&dev->mutex);
if (file->f_flags & FASYNC)
comedi_fasync(-1, file, 0);
return 0;
}

View File

@ -188,22 +188,7 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
console_unlock();
if (size < 0)
return size;
switch (orig) {
default:
return -EINVAL;
case 2:
offset += size;
break;
case 1:
offset += file->f_pos;
case 0:
break;
}
if (offset < 0 || offset > size) {
return -EINVAL;
}
file->f_pos = offset;
return file->f_pos;
return fixed_size_llseek(file, offset, orig, size);
}

View File

@ -21,27 +21,7 @@
static loff_t
proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
struct inode *inode = file_inode(file);
mutex_lock(&inode->i_mutex);
switch (whence) {
case 0:
new = off;
break;
case 1:
new = file->f_pos + off;
break;
case 2:
new = sizeof(struct ConfigDev) + off;
break;
}
if (new < 0 || new > sizeof(struct ConfigDev))
new = -EINVAL;
else
file->f_pos = new;
mutex_unlock(&inode->i_mutex);
return new;
return fixed_size_llseek(file, off, whence, sizeof(struct ConfigDev));
}
static ssize_t

View File

@ -191,8 +191,7 @@ const struct file_operations adfs_dir_operations = {
};
static int
adfs_hash(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr)
adfs_hash(const struct dentry *parent, struct qstr *qstr)
{
const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen;
const unsigned char *name;
@ -228,8 +227,7 @@ adfs_hash(const struct dentry *parent, const struct inode *inode,
* requirements of the underlying filesystem.
*/
static int
adfs_compare(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
adfs_compare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
int i;

View File

@ -13,18 +13,12 @@
typedef int (*toupper_t)(int);
static int affs_toupper(int ch);
static int affs_hash_dentry(const struct dentry *,
const struct inode *, struct qstr *);
static int affs_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int affs_hash_dentry(const struct dentry *, struct qstr *);
static int affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
static int affs_intl_toupper(int ch);
static int affs_intl_hash_dentry(const struct dentry *,
const struct inode *, struct qstr *);
static int affs_intl_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int affs_intl_hash_dentry(const struct dentry *, struct qstr *);
static int affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
const struct dentry_operations affs_dentry_operations = {
@ -86,14 +80,12 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
}
static int
affs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
{
return __affs_hash_dentry(qstr, affs_toupper);
}
static int
affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
{
return __affs_hash_dentry(qstr, affs_intl_toupper);
}
@ -131,15 +123,13 @@ static inline int __affs_compare_dentry(unsigned int len,
}
static int
affs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return __affs_compare_dentry(len, str, name, affs_toupper);
}
static int
affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return __affs_compare_dentry(len, str, name, affs_intl_toupper);

View File

@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)
*/
static int afs_do_setlk(struct file *file, struct file_lock *fl)
{
struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
struct inode *inode = file_inode(file);
struct afs_vnode *vnode = AFS_FS_I(inode);
afs_lock_type_t type;
struct key *key = file->private_data;
int ret;
@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)
type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
lock_flocks();
spin_lock(&inode->i_lock);
/* make sure we've got a callback on this file and that our view of the
* data version is up to date */
@ -420,7 +421,7 @@ given_lock:
afs_vnode_fetch_status(vnode, NULL, key);
error:
unlock_flocks();
spin_unlock(&inode->i_lock);
_leave(" = %d", ret);
return ret;

View File

@ -39,6 +39,8 @@
#include <asm/kmap_types.h>
#include <asm/uaccess.h>
#include "internal.h"
#define AIO_RING_MAGIC 0xa10a10a1
#define AIO_RING_COMPAT_FEATURES 1
#define AIO_RING_INCOMPAT_FEATURES 0

View File

@ -325,31 +325,10 @@ static int blkdev_write_end(struct file *file, struct address_space *mapping,
static loff_t block_llseek(struct file *file, loff_t offset, int whence)
{
struct inode *bd_inode = file->f_mapping->host;
loff_t size;
loff_t retval;
mutex_lock(&bd_inode->i_mutex);
size = i_size_read(bd_inode);
retval = -EINVAL;
switch (whence) {
case SEEK_END:
offset += size;
break;
case SEEK_CUR:
offset += file->f_pos;
case SEEK_SET:
break;
default:
goto out;
}
if (offset >= 0 && offset <= size) {
if (offset != file->f_pos) {
file->f_pos = offset;
}
retval = offset;
}
out:
retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode));
mutex_unlock(&bd_inode->i_mutex);
return retval;
}

View File

@ -2425,20 +2425,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
}
}
if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
offset = -EINVAL;
goto out;
}
if (offset > inode->i_sb->s_maxbytes) {
offset = -EINVAL;
goto out;
}
/* Special lock needed here? */
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out:
mutex_unlock(&inode->i_mutex);
return offset;

View File

@ -3881,7 +3881,7 @@ drop_write:
static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
struct btrfs_ioctl_quota_rescan_args *qsa;
int ret;
@ -3914,7 +3914,7 @@ drop_write:
static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
struct btrfs_ioctl_quota_rescan_args *qsa;
int ret = 0;
@ -4020,7 +4020,7 @@ out:
static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
const char *label = root->fs_info->super_copy->label;
size_t len = strnlen(label, BTRFS_LABEL_SIZE);
int ret;
@ -4039,7 +4039,7 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
{
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
struct btrfs_super_block *super_block = root->fs_info->super_copy;
struct btrfs_trans_handle *trans;
char label[BTRFS_LABEL_SIZE];

View File

@ -866,16 +866,7 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
break;
}
if (offset < 0 || offset > inode->i_sb->s_maxbytes) {
offset = -EINVAL;
goto out;
}
/* Special lock needed here? */
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out:
mutex_unlock(&inode->i_mutex);

View File

@ -192,7 +192,7 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
/**
* Encode the flock and fcntl locks for the given inode into the ceph_filelock
* array. Must be called with lock_flocks() already held.
* array. Must be called with inode->i_lock already held.
* If we encounter more of a specific lock type than expected, return -ENOSPC.
*/
int ceph_encode_locks_to_buffer(struct inode *inode,

View File

@ -2481,20 +2481,20 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
struct ceph_filelock *flocks;
encode_again:
lock_flocks();
spin_lock(&inode->i_lock);
ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
unlock_flocks();
spin_unlock(&inode->i_lock);
flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
sizeof(struct ceph_filelock), GFP_NOFS);
if (!flocks) {
err = -ENOMEM;
goto out_free;
}
lock_flocks();
spin_lock(&inode->i_lock);
err = ceph_encode_locks_to_buffer(inode, flocks,
num_fcntl_locks,
num_flock_locks);
unlock_flocks();
spin_unlock(&inode->i_lock);
if (err) {
kfree(flocks);
if (err == -ENOSPC)

View File

@ -765,7 +765,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
{
/* note that this is called by vfs setlease with lock_flocks held
/* note that this is called by vfs setlease with i_lock held
to protect *lease from going away */
struct inode *inode = file_inode(file);
struct cifsFileInfo *cfile = file->private_data;

View File

@ -822,8 +822,7 @@ const struct dentry_operations cifs_dentry_ops = {
/* d_delete: cifs_d_delete, */ /* not needed except for debugging */
};
static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
struct qstr *q)
static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
{
struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
unsigned long hash;
@ -838,12 +837,10 @@ static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode,
return 0;
}
static int cifs_ci_compare(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int cifs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls;
struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
if ((name->len == len) &&
(nls_strnicmp(codepage, name->name, str, len) == 0))

View File

@ -999,7 +999,7 @@ try_again:
rc = wait_event_interruptible(flock->fl_wait, !flock->fl_next);
if (!rc)
goto try_again;
locks_delete_block(flock);
posix_unblock_lock(flock);
}
return rc;
}
@ -1092,6 +1092,7 @@ struct lock_to_push {
static int
cifs_push_posix_locks(struct cifsFileInfo *cfile)
{
struct inode *inode = cfile->dentry->d_inode;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct file_lock *flock, **before;
unsigned int count = 0, i = 0;
@ -1102,12 +1103,12 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
xid = get_xid();
lock_flocks();
cifs_for_each_lock(cfile->dentry->d_inode, before) {
spin_lock(&inode->i_lock);
cifs_for_each_lock(inode, before) {
if ((*before)->fl_flags & FL_POSIX)
count++;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
INIT_LIST_HEAD(&locks_to_send);
@ -1126,8 +1127,8 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
}
el = locks_to_send.next;
lock_flocks();
cifs_for_each_lock(cfile->dentry->d_inode, before) {
spin_lock(&inode->i_lock);
cifs_for_each_lock(inode, before) {
flock = *before;
if ((flock->fl_flags & FL_POSIX) == 0)
continue;
@ -1152,7 +1153,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
lck->offset = flock->fl_start;
el = el->next;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) {
int stored_rc;

View File

@ -487,13 +487,7 @@ static int coda_venus_readdir(struct file *coda_file, struct dir_context *ctx)
/* skip null entries */
if (vdir->d_fileno && name.len) {
/* try to look up this entry in the dcache, that way
* userspace doesn't have to worry about breaking
* getcwd by having mismatched inode numbers for
* internal volume mountpoints. */
ino = find_inode_number(de, &name);
if (!ino) ino = vdir->d_fileno;
ino = vdir->d_fileno;
type = CDT2DT(vdir->d_type);
if (!dir_emit(ctx, name.name, name.len, ino, type))
break;

View File

@ -1730,7 +1730,7 @@ EXPORT_SYMBOL(d_add_ci);
* Do the slow-case of the dentry name compare.
*
* Unlike the dentry_cmp() function, we need to atomically
* load the name, length and inode information, so that the
* load the name and length information, so that the
* filesystem can rely on them, and can use the 'name' and
* 'len' information without worrying about walking off the
* end of memory etc.
@ -1748,22 +1748,18 @@ enum slow_d_compare {
static noinline enum slow_d_compare slow_dentry_cmp(
const struct dentry *parent,
struct inode *inode,
struct dentry *dentry,
unsigned int seq,
const struct qstr *name)
{
int tlen = dentry->d_name.len;
const char *tname = dentry->d_name.name;
struct inode *i = dentry->d_inode;
if (read_seqcount_retry(&dentry->d_seq, seq)) {
cpu_relax();
return D_COMP_SEQRETRY;
}
if (parent->d_op->d_compare(parent, inode,
dentry, i,
tlen, tname, name))
if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
return D_COMP_NOMATCH;
return D_COMP_OK;
}
@ -1773,7 +1769,6 @@ static noinline enum slow_d_compare slow_dentry_cmp(
* @parent: parent dentry
* @name: qstr of name we wish to find
* @seqp: returns d_seq value at the point where the dentry was found
* @inode: returns dentry->d_inode when the inode was found valid.
* Returns: dentry, or NULL
*
* __d_lookup_rcu is the dcache lookup function for rcu-walk name
@ -1800,7 +1795,7 @@ static noinline enum slow_d_compare slow_dentry_cmp(
*/
struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name,
unsigned *seqp, struct inode *inode)
unsigned *seqp)
{
u64 hashlen = name->hash_len;
const unsigned char *str = name->name;
@ -1834,11 +1829,10 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
seqretry:
/*
* The dentry sequence count protects us from concurrent
* renames, and thus protects inode, parent and name fields.
* renames, and thus protects parent and name fields.
*
* The caller must perform a seqcount check in order
* to do anything useful with the returned dentry,
* including using the 'd_inode' pointer.
* to do anything useful with the returned dentry.
*
* NOTE! We do a "raw" seqcount_begin here. That means that
* we don't wait for the sequence count to stabilize if it
@ -1852,12 +1846,12 @@ seqretry:
continue;
if (d_unhashed(dentry))
continue;
*seqp = seq;
if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) {
if (dentry->d_name.hash != hashlen_hash(hashlen))
continue;
switch (slow_dentry_cmp(parent, inode, dentry, seq, name)) {
*seqp = seq;
switch (slow_dentry_cmp(parent, dentry, seq, name)) {
case D_COMP_OK:
return dentry;
case D_COMP_NOMATCH:
@ -1869,6 +1863,7 @@ seqretry:
if (dentry->d_name.hash_len != hashlen)
continue;
*seqp = seq;
if (!dentry_cmp(dentry, str, hashlen_len(hashlen)))
return dentry;
}
@ -1966,9 +1961,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
if (parent->d_flags & DCACHE_OP_COMPARE) {
int tlen = dentry->d_name.len;
const char *tname = dentry->d_name.name;
if (parent->d_op->d_compare(parent, parent->d_inode,
dentry, dentry->d_inode,
tlen, tname, name))
if (parent->d_op->d_compare(parent, dentry, tlen, tname, name))
goto next;
} else {
if (dentry->d_name.len != len)
@ -2005,7 +1998,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
*/
name->hash = full_name_hash(name->name, name->len);
if (dir->d_flags & DCACHE_OP_HASH) {
int err = dir->d_op->d_hash(dir, dir->d_inode, name);
int err = dir->d_op->d_hash(dir, name);
if (unlikely(err < 0))
return ERR_PTR(err);
}
@ -2975,34 +2968,21 @@ rename_retry:
goto again;
}
/**
* find_inode_number - check for dentry with name
* @dir: directory to check
* @name: Name to find.
*
* Check whether a dentry already exists for the given name,
* and return the inode number if it has an inode. Otherwise
* 0 is returned.
*
* This routine is used to post-process directory listings for
* filesystems using synthetic inode numbers, and is necessary
* to keep getcwd() working.
*/
ino_t find_inode_number(struct dentry *dir, struct qstr *name)
void d_tmpfile(struct dentry *dentry, struct inode *inode)
{
struct dentry * dentry;
ino_t ino = 0;
dentry = d_hash_and_lookup(dir, name);
if (!IS_ERR_OR_NULL(dentry)) {
if (dentry->d_inode)
ino = dentry->d_inode->i_ino;
dput(dentry);
}
return ino;
inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
!hlist_unhashed(&dentry->d_alias) ||
!d_unlinked(dentry));
spin_lock(&dentry->d_parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
dentry->d_name.len = sprintf(dentry->d_iname, "#%llu",
(unsigned long long)inode->i_ino);
spin_unlock(&dentry->d_lock);
spin_unlock(&dentry->d_parent->d_lock);
d_instantiate(dentry, inode);
}
EXPORT_SYMBOL(find_inode_number);
EXPORT_SYMBOL(d_tmpfile);
static __initdata unsigned long dhash_entries;
static int __init set_dhash_entries(char *str)

View File

@ -2243,12 +2243,11 @@ out:
*/
int ecryptfs_decode_and_decrypt_filename(char **plaintext_name,
size_t *plaintext_name_size,
struct dentry *ecryptfs_dir_dentry,
struct super_block *sb,
const char *name, size_t name_size)
{
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&ecryptfs_superblock_to_private(
ecryptfs_dir_dentry->d_sb)->mount_crypt_stat;
&ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
char *decoded_name;
size_t decoded_name_size;
size_t packet_size;

View File

@ -575,7 +575,7 @@ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
struct inode *ecryptfs_inode);
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
size_t *decrypted_name_size,
struct dentry *ecryptfs_dentry,
struct super_block *sb,
const char *name, size_t name_size);
int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
int ecryptfs_encrypt_and_encode_filename(

View File

@ -70,7 +70,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
struct ecryptfs_getdents_callback {
struct dir_context ctx;
struct dir_context *caller;
struct dentry *dentry;
struct super_block *sb;
int filldir_called;
int entries_written;
};
@ -88,7 +88,7 @@ ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
buf->filldir_called++;
rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
buf->dentry, lower_name,
buf->sb, lower_name,
lower_namelen);
if (rc) {
printk(KERN_ERR "%s: Error attempting to decode and decrypt "
@ -114,15 +114,14 @@ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
{
int rc;
struct file *lower_file;
struct inode *inode;
struct inode *inode = file_inode(file);
struct ecryptfs_getdents_callback buf = {
.ctx.actor = ecryptfs_filldir,
.caller = ctx,
.dentry = file->f_path.dentry
.sb = inode->i_sb,
};
lower_file = ecryptfs_file_to_lower(file);
lower_file->f_pos = ctx->pos;
inode = file_inode(file);
rc = iterate_dir(lower_file, &buf.ctx);
ctx->pos = buf.ctx.pos;
if (rc < 0)

View File

@ -679,7 +679,7 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
set_fs(old_fs);
if (rc < 0)
goto out;
rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb,
lower_buf, rc);
out:
kfree(lower_buf);

View File

@ -45,8 +45,8 @@ static struct super_block *efivarfs_sb;
* So we need to perform a case-sensitive match on part 1 and a
* case-insensitive match on part 2.
*/
static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int efivarfs_d_compare(const struct dentry *parent,
const struct dentry *dentry,
unsigned int len, const char *str,
const struct qstr *name)
{
@ -63,8 +63,7 @@ static int efivarfs_d_compare(const struct dentry *parent, const struct inode *p
return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
}
static int efivarfs_d_hash(const struct dentry *dentry,
const struct inode *inode, struct qstr *qstr)
static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr)
{
unsigned long hash = init_name_hash();
const unsigned char *s = qstr->name;
@ -108,7 +107,7 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
q.name = name;
q.len = strlen(name);
err = efivarfs_d_hash(NULL, NULL, &q);
err = efivarfs_d_hash(NULL, &q);
if (err)
return ERR_PTR(err);

View File

@ -110,13 +110,14 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN
.intent = LOOKUP_OPEN,
.lookup_flags = LOOKUP_FOLLOW,
};
if (IS_ERR(tmp))
goto out;
file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
file = do_filp_open(AT_FDCWD, tmp, &uselib_flags);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@ -756,10 +757,11 @@ struct file *open_exec(const char *name)
static const struct open_flags open_exec_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN
.intent = LOOKUP_OPEN,
.lookup_flags = LOOKUP_FOLLOW,
};
file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);
file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags);
if (IS_ERR(file))
goto out;

View File

@ -119,6 +119,29 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode
return ext2_add_nondir(dentry, inode);
}
static int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct inode *inode = ext2_new_inode(dir, mode, NULL);
if (IS_ERR(inode))
return PTR_ERR(inode);
inode->i_op = &ext2_file_inode_operations;
if (ext2_use_xip(inode->i_sb)) {
inode->i_mapping->a_ops = &ext2_aops_xip;
inode->i_fop = &ext2_xip_file_operations;
} else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
unlock_new_inode(inode);
return 0;
}
static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
{
struct inode * inode;
@ -398,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = {
#endif
.setattr = ext2_setattr,
.get_acl = ext2_get_acl,
.tmpfile = ext2_tmpfile,
};
const struct inode_operations ext2_special_inode_operations = {

View File

@ -1759,6 +1759,45 @@ retry:
return err;
}
static int ext3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
handle_t *handle;
struct inode *inode;
int err, retries = 0;
dquot_initialize(dir);
retry:
handle = ext3_journal_start(dir, EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
4 + EXT3_XATTR_TRANS_BLOCKS);
if (IS_ERR(handle))
return PTR_ERR(handle);
inode = ext3_new_inode (handle, dir, NULL, mode);
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext3_file_inode_operations;
inode->i_fop = &ext3_file_operations;
ext3_set_aops(inode);
err = ext3_orphan_add(handle, inode);
if (err)
goto err_drop_inode;
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
unlock_new_inode(inode);
}
ext3_journal_stop(handle);
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
err_drop_inode:
ext3_journal_stop(handle);
unlock_new_inode(inode);
iput(inode);
return err;
}
static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
{
handle_t *handle;
@ -2300,7 +2339,7 @@ static int ext3_link (struct dentry * old_dentry,
retry:
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS);
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
if (IS_ERR(handle))
return PTR_ERR(handle);
@ -2314,6 +2353,11 @@ retry:
err = ext3_add_entry(handle, dentry, inode);
if (!err) {
ext3_mark_inode_dirty(handle, inode);
/* this can happen only for tmpfile being
* linked the first time
*/
if (inode->i_nlink == 1)
ext3_orphan_del(handle, inode);
d_instantiate(dentry, inode);
} else {
drop_nlink(inode);
@ -2516,6 +2560,7 @@ const struct inode_operations ext3_dir_inode_operations = {
.mkdir = ext3_mkdir,
.rmdir = ext3_rmdir,
.mknod = ext3_mknod,
.tmpfile = ext3_tmpfile,
.rename = ext3_rename,
.setattr = ext3_setattr,
#ifdef CONFIG_EXT3_FS_XATTR

View File

@ -494,17 +494,7 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
if (dataoff > isize)
return -ENXIO;
if (dataoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
return -EINVAL;
if (dataoff > maxsize)
return -EINVAL;
if (dataoff != file->f_pos) {
file->f_pos = dataoff;
file->f_version = 0;
}
return dataoff;
return vfs_setpos(file, dataoff, maxsize);
}
/*
@ -580,17 +570,7 @@ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
if (holeoff > isize)
holeoff = isize;
if (holeoff < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
return -EINVAL;
if (holeoff > maxsize)
return -EINVAL;
if (holeoff != file->f_pos) {
file->f_pos = holeoff;
file->f_version = 0;
}
return holeoff;
return vfs_setpos(file, holeoff, maxsize);
}
/*

View File

@ -2296,6 +2296,45 @@ retry:
return err;
}
static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
handle_t *handle;
struct inode *inode;
int err, retries = 0;
dquot_initialize(dir);
retry:
inode = ext4_new_inode_start_handle(dir, mode,
NULL, 0, NULL,
EXT4_HT_DIR,
EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) +
4 + EXT4_XATTR_TRANS_BLOCKS);
handle = ext4_journal_current_handle();
err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
ext4_set_aops(inode);
err = ext4_orphan_add(handle, inode);
if (err)
goto err_drop_inode;
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
unlock_new_inode(inode);
}
if (handle)
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
err_drop_inode:
ext4_journal_stop(handle);
unlock_new_inode(inode);
iput(inode);
return err;
}
struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
struct ext4_dir_entry_2 *de,
int blocksize, int csum_size,
@ -2903,7 +2942,7 @@ static int ext4_link(struct dentry *old_dentry,
retry:
handle = ext4_journal_start(dir, EXT4_HT_DIR,
(EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS));
EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1);
if (IS_ERR(handle))
return PTR_ERR(handle);
@ -2917,6 +2956,11 @@ retry:
err = ext4_add_entry(handle, dentry, inode);
if (!err) {
ext4_mark_inode_dirty(handle, inode);
/* this can happen only for tmpfile being
* linked the first time
*/
if (inode->i_nlink == 1)
ext4_orphan_del(handle, inode);
d_instantiate(dentry, inode);
} else {
drop_nlink(inode);
@ -3169,6 +3213,7 @@ const struct inode_operations ext4_dir_inode_operations = {
.mkdir = ext4_mkdir,
.rmdir = ext4_rmdir,
.mknod = ext4_mknod,
.tmpfile = ext4_tmpfile,
.rename = ext4_rename,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,

View File

@ -148,8 +148,7 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len,
* that the existing dentry can be used. The msdos fs routines will
* return ENOENT or EINVAL as appropriate.
*/
static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
static int msdos_hash(const struct dentry *dentry, struct qstr *qstr)
{
struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options;
unsigned char msdos_name[MSDOS_NAME];
@ -165,8 +164,7 @@ static int msdos_hash(const struct dentry *dentry, const struct inode *inode,
* Compare two msdos names. If either of the names are invalid,
* we fall back to doing the standard name comparison.
*/
static int msdos_cmp(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int msdos_cmp(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options;

View File

@ -107,8 +107,7 @@ static unsigned int vfat_striptail_len(const struct qstr *qstr)
* that the existing dentry can be used. The vfat fs routines will
* return ENOENT or EINVAL as appropriate.
*/
static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
static int vfat_hash(const struct dentry *dentry, struct qstr *qstr)
{
qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
return 0;
@ -120,8 +119,7 @@ static int vfat_hash(const struct dentry *dentry, const struct inode *inode,
* that the existing dentry can be used. The vfat fs routines will
* return ENOENT or EINVAL as appropriate.
*/
static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr)
{
struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
const unsigned char *name;
@ -142,8 +140,7 @@ static int vfat_hashi(const struct dentry *dentry, const struct inode *inode,
/*
* Case insensitive compare of two vfat names.
*/
static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int vfat_cmpi(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
@ -162,8 +159,7 @@ static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode,
/*
* Case sensitive compare of two vfat names.
*/
static int vfat_cmp(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int vfat_cmp(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
unsigned int alen, blen;

View File

@ -227,7 +227,7 @@ static void __fput(struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct vfsmount *mnt = file->f_path.mnt;
struct inode *inode = dentry->d_inode;
struct inode *inode = file->f_inode;
might_sleep();

View File

@ -548,8 +548,7 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
res = io->bytes < 0 ? io->size : io->bytes;
if (!is_sync_kiocb(io->iocb)) {
struct path *path = &io->iocb->ki_filp->f_path;
struct inode *inode = path->dentry->d_inode;
struct inode *inode = file_inode(io->iocb->ki_filp);
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);

View File

@ -109,8 +109,7 @@ fail:
return 0;
}
static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode,
struct qstr *str)
static int gfs2_dhash(const struct dentry *dentry, struct qstr *str)
{
str->hash = gfs2_disk_hash(str->name, str->len);
return 0;

View File

@ -912,7 +912,7 @@ out_uninit:
* cluster; until we do, disable leases (by just returning -EINVAL),
* unless the administrator has requested purely local locking.
*
* Locking: called under lock_flocks
* Locking: called under i_lock
*
* Returns: errno
*/

View File

@ -229,13 +229,10 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *);
/* string.c */
extern const struct dentry_operations hfs_dentry_operations;
extern int hfs_hash_dentry(const struct dentry *, const struct inode *,
struct qstr *);
extern int hfs_hash_dentry(const struct dentry *, struct qstr *);
extern int hfs_strcmp(const unsigned char *, unsigned int,
const unsigned char *, unsigned int);
extern int hfs_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
extern int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
/* trans.c */

View File

@ -51,8 +51,7 @@ static unsigned char caseorder[256] = {
/*
* Hash a string to an integer in a case-independent way
*/
int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *this)
int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
{
const unsigned char *name = this->name;
unsigned int hash, len = this->len;
@ -93,8 +92,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
* Test for equality of two strings in the HFS filename character ordering.
* return 1 on failure and 0 on success
*/
int hfs_compare_dentry(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
int hfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
const unsigned char *n1, *n2;

View File

@ -495,11 +495,8 @@ int hfsplus_uni2asc(struct super_block *,
const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *,
struct hfsplus_unistr *, int, const char *, int);
int hfsplus_hash_dentry(const struct dentry *dentry,
const struct inode *inode, struct qstr *str);
int hfsplus_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
/* wrapper.c */

View File

@ -334,8 +334,7 @@ int hfsplus_asc2uni(struct super_block *sb,
* Composed unicode characters are decomposed and case-folding is performed
* if the appropriate bits are (un)set on the superblock.
*/
int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *str)
int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
{
struct super_block *sb = dentry->d_sb;
const char *astr;
@ -386,9 +385,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode,
* Composed unicode characters are decomposed and case-folding is performed
* if the appropriate bits are (un)set on the superblock.
*/
int hfsplus_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
int hfsplus_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct super_block *sb = parent->d_sb;

View File

@ -12,8 +12,7 @@
* Note: the dentry argument is the parent dentry.
*/
static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
static int hpfs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
{
unsigned long hash;
int i;
@ -35,9 +34,7 @@ static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *ino
return 0;
}
static int hpfs_compare_dentry(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int hpfs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
unsigned al = len;

View File

@ -333,8 +333,10 @@ EXPORT_SYMBOL(set_nlink);
*/
void inc_nlink(struct inode *inode)
{
if (WARN_ON(inode->i_nlink == 0))
if (unlikely(inode->i_nlink == 0)) {
WARN_ON(!(inode->i_state & I_LINKABLE));
atomic_long_dec(&inode->i_sb->s_remove_count);
}
inode->__i_nlink++;
}

View File

@ -96,11 +96,12 @@ struct open_flags {
umode_t mode;
int acc_mode;
int intent;
int lookup_flags;
};
extern struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op, int flags);
const struct open_flags *op);
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
const char *, const struct open_flags *, int lookup_flags);
const char *, const struct open_flags *);
extern long do_handle_open(int mountdirfd,
struct file_handle __user *ufh, int open_flag);
@ -130,6 +131,7 @@ extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
* read_write.c
*/
extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
extern int rw_verify_area(int, struct file *, const loff_t *, size_t);
/*
* splice.c

View File

@ -28,31 +28,23 @@
#define BEQUIET
static int isofs_hashi(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_hash(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_hashi(const struct dentry *parent, struct qstr *qstr);
static int isofs_hash(const struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
#ifdef CONFIG_JOLIET
static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
struct qstr *qstr);
static int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr);
static int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr);
static int isofs_dentry_cmpi_ms(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
static int isofs_dentry_cmp_ms(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name);
#endif
@ -265,30 +257,26 @@ static int isofs_dentry_cmp_common(
}
static int
isofs_hash(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
isofs_hash(const struct dentry *dentry, struct qstr *qstr)
{
return isofs_hash_common(dentry, qstr, 0);
}
static int
isofs_hashi(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
isofs_hashi(const struct dentry *dentry, struct qstr *qstr)
{
return isofs_hashi_common(dentry, qstr, 0);
}
static int
isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
isofs_dentry_cmp(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(len, str, name, 0, 0);
}
static int
isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(len, str, name, 0, 1);
@ -296,30 +284,26 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
#ifdef CONFIG_JOLIET
static int
isofs_hash_ms(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
{
return isofs_hash_common(dentry, qstr, 1);
}
static int
isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
isofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr)
{
return isofs_hashi_common(dentry, qstr, 1);
}
static int
isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
isofs_dentry_cmp_ms(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(len, str, name, 1, 0);
}
static int
isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
isofs_dentry_cmpi_ms(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
return isofs_dentry_cmp_common(len, str, name, 1, 1);

View File

@ -37,8 +37,7 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
qstr.name = compare;
qstr.len = dlen;
return dentry->d_op->d_compare(NULL, NULL, NULL, NULL,
dentry->d_name.len, dentry->d_name.name, &qstr);
return dentry->d_op->d_compare(NULL, NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
}
/*

View File

@ -1538,8 +1538,7 @@ const struct file_operations jfs_dir_operations = {
.llseek = generic_file_llseek,
};
static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
struct qstr *this)
static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
{
unsigned long hash;
int i;
@ -1552,9 +1551,7 @@ static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode,
return 0;
}
static int jfs_ci_compare(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int jfs_ci_compare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
int i, result = 1;

View File

@ -276,7 +276,7 @@ static int nlmsvc_unlink_block(struct nlm_block *block)
dprintk("lockd: unlinking block %p...\n", block);
/* Remove block from list */
status = posix_unblock_lock(block->b_file->f_file, &block->b_call->a_args.lock.fl);
status = posix_unblock_lock(&block->b_call->a_args.lock.fl);
nlmsvc_remove_block(block);
return status;
}
@ -744,8 +744,20 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid;
}
/*
* Since NLM uses two "keys" for tracking locks, we need to hash them down
* to one for the blocked_hash. Here, we're just xor'ing the host address
* with the pid in order to create a key value for picking a hash bucket.
*/
static unsigned long
nlmsvc_owner_key(struct file_lock *fl)
{
return (unsigned long)fl->fl_owner ^ (unsigned long)fl->fl_pid;
}
const struct lock_manager_operations nlmsvc_lock_operations = {
.lm_compare_owner = nlmsvc_same_owner,
.lm_owner_key = nlmsvc_owner_key,
.lm_notify = nlmsvc_notify_blocked,
.lm_grant = nlmsvc_grant_deferred,
};

View File

@ -169,7 +169,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
again:
file->f_locks = 0;
lock_flocks(); /* protects i_flock list */
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
if (fl->fl_lmops != &nlmsvc_lock_operations)
continue;
@ -181,7 +181,7 @@ again:
if (match(lockhost, host)) {
struct file_lock lock = *fl;
unlock_flocks();
spin_unlock(&inode->i_lock);
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
@ -193,7 +193,7 @@ again:
goto again;
}
}
unlock_flocks();
spin_unlock(&inode->i_lock);
return 0;
}
@ -228,14 +228,14 @@ nlm_file_inuse(struct nlm_file *file)
if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
return 1;
lock_flocks();
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl; fl = fl->fl_next) {
if (fl->fl_lmops == &nlmsvc_lock_operations) {
unlock_flocks();
spin_unlock(&inode->i_lock);
return 1;
}
}
unlock_flocks();
spin_unlock(&inode->i_lock);
file->f_locks = 0;
return 0;
}

View File

@ -126,6 +126,7 @@
#include <linux/time.h>
#include <linux/rcupdate.h>
#include <linux/pid_namespace.h>
#include <linux/hashtable.h>
#include <asm/uaccess.h>
@ -153,30 +154,51 @@ int lease_break_time = 45;
#define for_each_lock(inode, lockp) \
for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
static LIST_HEAD(file_lock_list);
static LIST_HEAD(blocked_list);
/*
* The global file_lock_list is only used for displaying /proc/locks. Protected
* by the file_lock_lock.
*/
static HLIST_HEAD(file_lock_list);
static DEFINE_SPINLOCK(file_lock_lock);
/*
* Protects the two list heads above, plus the inode->i_flock list
* The blocked_hash is used to find POSIX lock loops for deadlock detection.
* It is protected by blocked_lock_lock.
*
* We hash locks by lockowner in order to optimize searching for the lock a
* particular lockowner is waiting on.
*
* FIXME: make this value scale via some heuristic? We generally will want more
* buckets when we have more lockowners holding locks, but that's a little
* difficult to determine without knowing what the workload will look like.
*/
void lock_flocks(void)
{
spin_lock(&file_lock_lock);
}
EXPORT_SYMBOL_GPL(lock_flocks);
#define BLOCKED_HASH_BITS 7
static DEFINE_HASHTABLE(blocked_hash, BLOCKED_HASH_BITS);
void unlock_flocks(void)
{
spin_unlock(&file_lock_lock);
}
EXPORT_SYMBOL_GPL(unlock_flocks);
/*
* This lock protects the blocked_hash. Generally, if you're accessing it, you
* want to be holding this lock.
*
* In addition, it also protects the fl->fl_block list, and the fl->fl_next
* pointer for file_lock structures that are acting as lock requests (in
* contrast to those that are acting as records of acquired locks).
*
* Note that when we acquire this lock in order to change the above fields,
* we often hold the i_lock as well. In certain cases, when reading the fields
* protected by this lock, we can skip acquiring it iff we already hold the
* i_lock.
*
* In particular, adding an entry to the fl_block list requires that you hold
* both the i_lock and the blocked_lock_lock (acquired in that order). Deleting
* an entry from the list however only requires the file_lock_lock.
*/
static DEFINE_SPINLOCK(blocked_lock_lock);
static struct kmem_cache *filelock_cache __read_mostly;
static void locks_init_lock_heads(struct file_lock *fl)
{
INIT_LIST_HEAD(&fl->fl_link);
INIT_HLIST_NODE(&fl->fl_link);
INIT_LIST_HEAD(&fl->fl_block);
init_waitqueue_head(&fl->fl_wait);
}
@ -210,7 +232,7 @@ void locks_free_lock(struct file_lock *fl)
{
BUG_ON(waitqueue_active(&fl->fl_wait));
BUG_ON(!list_empty(&fl->fl_block));
BUG_ON(!list_empty(&fl->fl_link));
BUG_ON(!hlist_unhashed(&fl->fl_link));
locks_release_private(fl);
kmem_cache_free(filelock_cache, fl);
@ -484,47 +506,108 @@ static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
return fl1->fl_owner == fl2->fl_owner;
}
static inline void
locks_insert_global_locks(struct file_lock *fl)
{
spin_lock(&file_lock_lock);
hlist_add_head(&fl->fl_link, &file_lock_list);
spin_unlock(&file_lock_lock);
}
static inline void
locks_delete_global_locks(struct file_lock *fl)
{
spin_lock(&file_lock_lock);
hlist_del_init(&fl->fl_link);
spin_unlock(&file_lock_lock);
}
static unsigned long
posix_owner_key(struct file_lock *fl)
{
if (fl->fl_lmops && fl->fl_lmops->lm_owner_key)
return fl->fl_lmops->lm_owner_key(fl);
return (unsigned long)fl->fl_owner;
}
static inline void
locks_insert_global_blocked(struct file_lock *waiter)
{
hash_add(blocked_hash, &waiter->fl_link, posix_owner_key(waiter));
}
static inline void
locks_delete_global_blocked(struct file_lock *waiter)
{
hash_del(&waiter->fl_link);
}
/* Remove waiter from blocker's block list.
* When blocker ends up pointing to itself then the list is empty.
*
* Must be called with blocked_lock_lock held.
*/
static void __locks_delete_block(struct file_lock *waiter)
{
locks_delete_global_blocked(waiter);
list_del_init(&waiter->fl_block);
list_del_init(&waiter->fl_link);
waiter->fl_next = NULL;
}
/*
*/
void locks_delete_block(struct file_lock *waiter)
static void locks_delete_block(struct file_lock *waiter)
{
lock_flocks();
spin_lock(&blocked_lock_lock);
__locks_delete_block(waiter);
unlock_flocks();
spin_unlock(&blocked_lock_lock);
}
EXPORT_SYMBOL(locks_delete_block);
/* Insert waiter into blocker's block list.
* We use a circular list so that processes can be easily woken up in
* the order they blocked. The documentation doesn't require this but
* it seems like the reasonable thing to do.
*
* Must be called with both the i_lock and blocked_lock_lock held. The fl_block
* list itself is protected by the file_lock_list, but by ensuring that the
* i_lock is also held on insertions we can avoid taking the blocked_lock_lock
* in some cases when we see that the fl_block list is empty.
*/
static void locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
static void __locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
{
BUG_ON(!list_empty(&waiter->fl_block));
list_add_tail(&waiter->fl_block, &blocker->fl_block);
waiter->fl_next = blocker;
list_add_tail(&waiter->fl_block, &blocker->fl_block);
if (IS_POSIX(blocker))
list_add(&waiter->fl_link, &blocked_list);
locks_insert_global_blocked(waiter);
}
/* Wake up processes blocked waiting for blocker.
* If told to wait then schedule the processes until the block list
* is empty, otherwise empty the block list ourselves.
/* Must be called with i_lock held. */
static void locks_insert_block(struct file_lock *blocker,
struct file_lock *waiter)
{
spin_lock(&blocked_lock_lock);
__locks_insert_block(blocker, waiter);
spin_unlock(&blocked_lock_lock);
}
/*
* Wake up processes blocked waiting for blocker.
*
* Must be called with the inode->i_lock held!
*/
static void locks_wake_up_blocks(struct file_lock *blocker)
{
/*
* Avoid taking global lock if list is empty. This is safe since new
* blocked requests are only added to the list under the i_lock, and
* the i_lock is always held here. Note that removal from the fl_block
* list does not require the i_lock, so we must recheck list_empty()
* after acquiring the blocked_lock_lock.
*/
if (list_empty(&blocker->fl_block))
return;
spin_lock(&blocked_lock_lock);
while (!list_empty(&blocker->fl_block)) {
struct file_lock *waiter;
@ -536,20 +619,23 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
else
wake_up(&waiter->fl_wait);
}
spin_unlock(&blocked_lock_lock);
}
/* Insert file lock fl into an inode's lock list at the position indicated
* by pos. At the same time add the lock to the global file lock list.
*
* Must be called with the i_lock held!
*/
static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
{
list_add(&fl->fl_link, &file_lock_list);
fl->fl_nspid = get_pid(task_tgid(current));
/* insert into file's list */
fl->fl_next = *pos;
*pos = fl;
locks_insert_global_locks(fl);
}
/*
@ -557,14 +643,17 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
* Wake up processes that are blocked waiting for this lock,
* notify the FS that the lock has been cleared and
* finally free the lock.
*
* Must be called with the i_lock held!
*/
static void locks_delete_lock(struct file_lock **thisfl_p)
{
struct file_lock *fl = *thisfl_p;
locks_delete_global_locks(fl);
*thisfl_p = fl->fl_next;
fl->fl_next = NULL;
list_del_init(&fl->fl_link);
if (fl->fl_nspid) {
put_pid(fl->fl_nspid);
@ -625,8 +714,9 @@ void
posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
struct inode *inode = file_inode(filp);
lock_flocks();
spin_lock(&inode->i_lock);
for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
continue;
@ -639,7 +729,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
fl->fl_pid = pid_vnr(cfl->fl_nspid);
} else
fl->fl_type = F_UNLCK;
unlock_flocks();
spin_unlock(&inode->i_lock);
return;
}
EXPORT_SYMBOL(posix_test_lock);
@ -676,13 +766,14 @@ static struct file_lock *what_owner_is_waiting_for(struct file_lock *block_fl)
{
struct file_lock *fl;
list_for_each_entry(fl, &blocked_list, fl_link) {
hash_for_each_possible(blocked_hash, fl, fl_link, posix_owner_key(block_fl)) {
if (posix_same_owner(fl, block_fl))
return fl->fl_next;
}
return NULL;
}
/* Must be called with the blocked_lock_lock held! */
static int posix_locks_deadlock(struct file_lock *caller_fl,
struct file_lock *block_fl)
{
@ -718,7 +809,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
return -ENOMEM;
}
lock_flocks();
spin_lock(&inode->i_lock);
if (request->fl_flags & FL_ACCESS)
goto find_conflict;
@ -748,9 +839,9 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
* give it the opportunity to lock the file.
*/
if (found) {
unlock_flocks();
spin_unlock(&inode->i_lock);
cond_resched();
lock_flocks();
spin_lock(&inode->i_lock);
}
find_conflict:
@ -777,7 +868,7 @@ find_conflict:
error = 0;
out:
unlock_flocks();
spin_unlock(&inode->i_lock);
if (new_fl)
locks_free_lock(new_fl);
return error;
@ -791,7 +882,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
struct file_lock *left = NULL;
struct file_lock *right = NULL;
struct file_lock **before;
int error, added = 0;
int error;
bool added = false;
/*
* We may need two file_lock structures for this operation,
@ -806,7 +898,12 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
new_fl2 = locks_alloc_lock();
}
lock_flocks();
spin_lock(&inode->i_lock);
/*
* New lock request. Walk all POSIX locks and look for conflicts. If
* there are any, either return error or put the request on the
* blocker's list of waiters and the global blocked_hash.
*/
if (request->fl_type != F_UNLCK) {
for_each_lock(inode, before) {
fl = *before;
@ -819,11 +916,17 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
error = -EAGAIN;
if (!(request->fl_flags & FL_SLEEP))
goto out;
/*
* Deadlock detection and insertion into the blocked
* locks list must be done while holding the same lock!
*/
error = -EDEADLK;
if (posix_locks_deadlock(request, fl))
goto out;
error = FILE_LOCK_DEFERRED;
locks_insert_block(fl, request);
spin_lock(&blocked_lock_lock);
if (likely(!posix_locks_deadlock(request, fl))) {
error = FILE_LOCK_DEFERRED;
__locks_insert_block(fl, request);
}
spin_unlock(&blocked_lock_lock);
goto out;
}
}
@ -845,7 +948,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
before = &fl->fl_next;
}
/* Process locks with this owner. */
/* Process locks with this owner. */
while ((fl = *before) && posix_same_owner(request, fl)) {
/* Detect adjacent or overlapping regions (if same lock type)
*/
@ -880,7 +983,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
continue;
}
request = fl;
added = 1;
added = true;
}
else {
/* Processing for different lock types is a bit
@ -891,7 +994,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (fl->fl_start > request->fl_end)
break;
if (request->fl_type == F_UNLCK)
added = 1;
added = true;
if (fl->fl_start < request->fl_start)
left = fl;
/* If the next lock in the list has a higher end
@ -921,7 +1024,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
locks_release_private(fl);
locks_copy_private(fl, request);
request = fl;
added = 1;
added = true;
}
}
/* Go on to next lock.
@ -931,10 +1034,9 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
}
/*
* The above code only modifies existing locks in case of
* merging or replacing. If new lock(s) need to be inserted
* all modifications are done bellow this, so it's safe yet to
* bail out.
* The above code only modifies existing locks in case of merging or
* replacing. If new lock(s) need to be inserted all modifications are
* done below this, so it's safe yet to bail out.
*/
error = -ENOLCK; /* "no luck" */
if (right && left == right && !new_fl2)
@ -974,7 +1076,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
locks_wake_up_blocks(left);
}
out:
unlock_flocks();
spin_unlock(&inode->i_lock);
/*
* Free any unused locks.
*/
@ -1049,14 +1151,14 @@ int locks_mandatory_locked(struct inode *inode)
/*
* Search the lock list for this inode for any POSIX locks.
*/
lock_flocks();
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!IS_POSIX(fl))
continue;
if (fl->fl_owner != owner)
break;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
return fl ? -EAGAIN : 0;
}
@ -1199,7 +1301,7 @@ int __break_lease(struct inode *inode, unsigned int mode)
if (IS_ERR(new_fl))
return PTR_ERR(new_fl);
lock_flocks();
spin_lock(&inode->i_lock);
time_out_leases(inode);
@ -1249,11 +1351,11 @@ restart:
break_time++;
}
locks_insert_block(flock, new_fl);
unlock_flocks();
spin_unlock(&inode->i_lock);
error = wait_event_interruptible_timeout(new_fl->fl_wait,
!new_fl->fl_next, break_time);
lock_flocks();
__locks_delete_block(new_fl);
spin_lock(&inode->i_lock);
locks_delete_block(new_fl);
if (error >= 0) {
if (error == 0)
time_out_leases(inode);
@ -1270,7 +1372,7 @@ restart:
}
out:
unlock_flocks();
spin_unlock(&inode->i_lock);
locks_free_lock(new_fl);
return error;
}
@ -1323,9 +1425,10 @@ EXPORT_SYMBOL(lease_get_mtime);
int fcntl_getlease(struct file *filp)
{
struct file_lock *fl;
struct inode *inode = file_inode(filp);
int type = F_UNLCK;
lock_flocks();
spin_lock(&inode->i_lock);
time_out_leases(file_inode(filp));
for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
fl = fl->fl_next) {
@ -1334,11 +1437,11 @@ int fcntl_getlease(struct file *filp)
break;
}
}
unlock_flocks();
spin_unlock(&inode->i_lock);
return type;
}
int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry;
@ -1403,7 +1506,7 @@ out:
return error;
}
int generic_delete_lease(struct file *filp, struct file_lock **flp)
static int generic_delete_lease(struct file *filp, struct file_lock **flp)
{
struct file_lock *fl, **before;
struct dentry *dentry = filp->f_path.dentry;
@ -1428,7 +1531,7 @@ int generic_delete_lease(struct file *filp, struct file_lock **flp)
* The (input) flp->fl_lmops->lm_break function is required
* by break_lease().
*
* Called with file_lock_lock held.
* Called with inode->i_lock held.
*/
int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
{
@ -1497,11 +1600,12 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
{
struct inode *inode = file_inode(filp);
int error;
lock_flocks();
spin_lock(&inode->i_lock);
error = __vfs_setlease(filp, arg, lease);
unlock_flocks();
spin_unlock(&inode->i_lock);
return error;
}
@ -1519,6 +1623,7 @@ static int do_fcntl_delete_lease(struct file *filp)
static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
{
struct file_lock *fl, *ret;
struct inode *inode = file_inode(filp);
struct fasync_struct *new;
int error;
@ -1532,10 +1637,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
return -ENOMEM;
}
ret = fl;
lock_flocks();
spin_lock(&inode->i_lock);
error = __vfs_setlease(filp, arg, &ret);
if (error) {
unlock_flocks();
spin_unlock(&inode->i_lock);
locks_free_lock(fl);
goto out_free_fasync;
}
@ -1552,7 +1657,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
new = NULL;
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
unlock_flocks();
spin_unlock(&inode->i_lock);
out_free_fasync:
if (new)
@ -2076,7 +2181,7 @@ void locks_remove_flock(struct file *filp)
fl.fl_ops->fl_release_private(&fl);
}
lock_flocks();
spin_lock(&inode->i_lock);
before = &inode->i_flock;
while ((fl = *before) != NULL) {
@ -2094,30 +2199,28 @@ void locks_remove_flock(struct file *filp)
}
before = &fl->fl_next;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
}
/**
* posix_unblock_lock - stop waiting for a file lock
* @filp: how the file was opened
* @waiter: the lock which was waiting
*
* lockd needs to block waiting for locks.
*/
int
posix_unblock_lock(struct file *filp, struct file_lock *waiter)
posix_unblock_lock(struct file_lock *waiter)
{
int status = 0;
lock_flocks();
spin_lock(&blocked_lock_lock);
if (waiter->fl_next)
__locks_delete_block(waiter);
else
status = -ENOENT;
unlock_flocks();
spin_unlock(&blocked_lock_lock);
return status;
}
EXPORT_SYMBOL(posix_unblock_lock);
/**
@ -2215,7 +2318,7 @@ static int locks_show(struct seq_file *f, void *v)
{
struct file_lock *fl, *bfl;
fl = list_entry(v, struct file_lock, fl_link);
fl = hlist_entry(v, struct file_lock, fl_link);
lock_get_status(f, fl, *((loff_t *)f->private), "");
@ -2229,21 +2332,23 @@ static void *locks_start(struct seq_file *f, loff_t *pos)
{
loff_t *p = f->private;
lock_flocks();
spin_lock(&file_lock_lock);
spin_lock(&blocked_lock_lock);
*p = (*pos + 1);
return seq_list_start(&file_lock_list, *pos);
return seq_hlist_start(&file_lock_list, *pos);
}
static void *locks_next(struct seq_file *f, void *v, loff_t *pos)
{
loff_t *p = f->private;
++*p;
return seq_list_next(v, &file_lock_list, pos);
return seq_hlist_next(v, &file_lock_list, pos);
}
static void locks_stop(struct seq_file *f, void *v)
{
unlock_flocks();
spin_unlock(&blocked_lock_lock);
spin_unlock(&file_lock_lock);
}
static const struct seq_operations locks_seq_operations = {
@ -2290,7 +2395,8 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
lock_flocks();
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (IS_POSIX(fl)) {
if (fl->fl_type == F_RDLCK)
@ -2307,7 +2413,7 @@ int lock_may_read(struct inode *inode, loff_t start, unsigned long len)
result = 0;
break;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
return result;
}
@ -2330,7 +2436,8 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
{
struct file_lock *fl;
int result = 1;
lock_flocks();
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (IS_POSIX(fl)) {
if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
@ -2345,7 +2452,7 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len)
result = 0;
break;
}
unlock_flocks();
spin_unlock(&inode->i_lock);
return result;
}

View File

@ -93,7 +93,7 @@ static int minix_readdir(struct file *file, struct dir_context *ctx)
unsigned offset;
unsigned long n;
ctx->pos = pos = (pos + chunk_size-1) & ~(chunk_size-1);
ctx->pos = pos = ALIGN(pos, chunk_size);
if (pos >= inode->i_size)
return 0;

View File

@ -54,6 +54,18 @@ static int minix_mknod(struct inode * dir, struct dentry *dentry, umode_t mode,
return error;
}
static int minix_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int error;
struct inode *inode = minix_new_inode(dir, mode, &error);
if (inode) {
minix_set_inode(inode, 0);
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
}
return error;
}
static int minix_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool excl)
{
@ -254,4 +266,5 @@ const struct inode_operations minix_dir_inode_operations = {
.mknod = minix_mknod,
.rename = minix_rename,
.getattr = minix_getattr,
.tmpfile = minix_tmpfile,
};

View File

@ -1352,7 +1352,7 @@ static int lookup_fast(struct nameidata *nd,
*/
if (nd->flags & LOOKUP_RCU) {
unsigned seq;
dentry = __d_lookup_rcu(parent, &nd->last, &seq, nd->inode);
dentry = __d_lookup_rcu(parent, &nd->last, &seq);
if (!dentry)
goto unlazy;
@ -1787,8 +1787,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
struct dentry *parent = nd->path.dentry;
nd->flags &= ~LOOKUP_JUMPED;
if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
err = parent->d_op->d_hash(parent, nd->inode,
&this);
err = parent->d_op->d_hash(parent, &this);
if (err < 0)
break;
}
@ -2121,7 +2120,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
* to use its own hash..
*/
if (base->d_flags & DCACHE_OP_HASH) {
int err = base->d_op->d_hash(base, base->d_inode, &this);
int err = base->d_op->d_hash(base, &this);
if (err < 0)
return ERR_PTR(err);
}
@ -2690,28 +2689,10 @@ static int do_last(struct nameidata *nd, struct path *path,
nd->flags &= ~LOOKUP_PARENT;
nd->flags |= op->intent;
switch (nd->last_type) {
case LAST_DOTDOT:
case LAST_DOT:
if (nd->last_type != LAST_NORM) {
error = handle_dots(nd, nd->last_type);
if (error)
return error;
/* fallthrough */
case LAST_ROOT:
error = complete_walk(nd);
if (error)
return error;
audit_inode(name, nd->path.dentry, 0);
if (open_flag & O_CREAT) {
error = -EISDIR;
goto out;
}
goto finish_open;
case LAST_BIND:
error = complete_walk(nd);
if (error)
return error;
audit_inode(name, dir, 0);
goto finish_open;
}
@ -2841,19 +2822,19 @@ finish_lookup:
}
nd->inode = inode;
/* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
finish_open:
error = complete_walk(nd);
if (error) {
path_put(&save_parent);
return error;
}
audit_inode(name, nd->path.dentry, 0);
error = -EISDIR;
if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
goto out;
error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode))
goto out;
audit_inode(name, nd->path.dentry, 0);
finish_open:
if (!S_ISREG(nd->inode->i_mode))
will_truncate = false;
@ -2920,6 +2901,67 @@ stale_open:
goto retry_lookup;
}
static int do_tmpfile(int dfd, struct filename *pathname,
struct nameidata *nd, int flags,
const struct open_flags *op,
struct file *file, int *opened)
{
static const struct qstr name = QSTR_INIT("/", 1);
struct dentry *dentry, *child;
struct inode *dir;
int error = path_lookupat(dfd, pathname->name,
flags | LOOKUP_DIRECTORY, nd);
if (unlikely(error))
return error;
error = mnt_want_write(nd->path.mnt);
if (unlikely(error))
goto out;
/* we want directory to be writable */
error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC);
if (error)
goto out2;
dentry = nd->path.dentry;
dir = dentry->d_inode;
if (!dir->i_op->tmpfile) {
error = -EOPNOTSUPP;
goto out2;
}
child = d_alloc(dentry, &name);
if (unlikely(!child)) {
error = -ENOMEM;
goto out2;
}
nd->flags &= ~LOOKUP_DIRECTORY;
nd->flags |= op->intent;
dput(nd->path.dentry);
nd->path.dentry = child;
error = dir->i_op->tmpfile(dir, nd->path.dentry, op->mode);
if (error)
goto out2;
audit_inode(pathname, nd->path.dentry, 0);
error = may_open(&nd->path, op->acc_mode, op->open_flag);
if (error)
goto out2;
file->f_path.mnt = nd->path.mnt;
error = finish_open(file, nd->path.dentry, NULL, opened);
if (error)
goto out2;
error = open_check_o_direct(file);
if (error) {
fput(file);
} else if (!(op->open_flag & O_EXCL)) {
struct inode *inode = file_inode(file);
spin_lock(&inode->i_lock);
inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock);
}
out2:
mnt_drop_write(nd->path.mnt);
out:
path_put(&nd->path);
return error;
}
static struct file *path_openat(int dfd, struct filename *pathname,
struct nameidata *nd, const struct open_flags *op, int flags)
{
@ -2935,6 +2977,11 @@ static struct file *path_openat(int dfd, struct filename *pathname,
file->f_flags = op->open_flag;
if (unlikely(file->f_flags & O_TMPFILE)) {
error = do_tmpfile(dfd, pathname, nd, flags, op, file, &opened);
goto out;
}
error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);
if (unlikely(error))
goto out;
@ -2987,9 +3034,10 @@ out:
}
struct file *do_filp_open(int dfd, struct filename *pathname,
const struct open_flags *op, int flags)
const struct open_flags *op)
{
struct nameidata nd;
int flags = op->lookup_flags;
struct file *filp;
filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
@ -3001,17 +3049,16 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
}
struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
const char *name, const struct open_flags *op, int flags)
const char *name, const struct open_flags *op)
{
struct nameidata nd;
struct file *file;
struct filename filename = { .name = name };
int flags = op->lookup_flags | LOOKUP_ROOT;
nd.root.mnt = mnt;
nd.root.dentry = dentry;
flags |= LOOKUP_ROOT;
if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP);
@ -3586,12 +3633,18 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
mutex_lock(&inode->i_mutex);
/* Make sure we don't allow creating hardlink to an unlinked file */
if (inode->i_nlink == 0)
if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE))
error = -ENOENT;
else if (max_links && inode->i_nlink >= max_links)
error = -EMLINK;
else
error = dir->i_op->link(old_dentry, dir, new_dentry);
if (!error && (inode->i_state & I_LINKABLE)) {
spin_lock(&inode->i_lock);
inode->i_state &= ~I_LINKABLE;
spin_unlock(&inode->i_lock);
}
mutex_unlock(&inode->i_mutex);
if (!error)
fsnotify_link(dir, inode, new_dentry);

View File

@ -73,10 +73,8 @@ const struct inode_operations ncp_dir_inode_operations =
* Dentry operations routines
*/
static int ncp_lookup_validate(struct dentry *, unsigned int);
static int ncp_hash_dentry(const struct dentry *, const struct inode *,
struct qstr *);
static int ncp_compare_dentry(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
static int ncp_hash_dentry(const struct dentry *, struct qstr *);
static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
static int ncp_delete_dentry(const struct dentry *);
@ -119,11 +117,19 @@ static inline int ncp_case_sensitive(const struct inode *i)
/*
* Note: leave the hash unchanged if the directory
* is case-sensitive.
*
* Accessing the parent inode can be racy under RCU pathwalking.
* Use ACCESS_ONCE() to make sure we use _one_ particular inode,
* the callers will handle races.
*/
static int
ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
struct qstr *this)
ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
{
struct inode *inode = ACCESS_ONCE(dentry->d_inode);
if (!inode)
return 0;
if (!ncp_case_sensitive(inode)) {
struct super_block *sb = dentry->d_sb;
struct nls_table *t;
@ -140,14 +146,24 @@ ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
return 0;
}
/*
* Accessing the parent inode can be racy under RCU pathwalking.
* Use ACCESS_ONCE() to make sure we use _one_ particular inode,
* the callers will handle races.
*/
static int
ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct inode *pinode;
if (len != name->len)
return 1;
pinode = ACCESS_ONCE(parent->d_inode);
if (!pinode)
return 1;
if (ncp_case_sensitive(pinode))
return strncmp(str, name->name, len);
@ -659,8 +675,6 @@ end_advance:
if (!valid)
ctl.valid = 0;
if (!ctl.filled && (ctl.fpos == ctx->pos)) {
if (!ino)
ino = find_inode_number(dentry, &qname);
if (!ino)
ino = iunique(dir->i_sb, 2);
ctl.filled = !dir_emit(ctx, qname.name, qname.len,
@ -1123,17 +1137,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
/*
* fail with EBUSY if there are still references to this
* directory.
*/
dentry_unhash(new_dentry);
error = -EBUSY;
if (!d_unhashed(new_dentry))
goto out;
}
ncp_age_dentry(server, old_dentry);
ncp_age_dentry(server, new_dentry);

View File

@ -891,6 +891,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
if (!server) /* How this could happen? */
goto out;
result = -EPERM;
if (IS_DEADDIR(dentry->d_inode))
goto out;
/* ageing the dentry to force validation */
ncp_age_dentry(server, dentry);

View File

@ -73,20 +73,20 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
if (inode->i_flock == NULL)
goto out;
/* Protect inode->i_flock using the file locks lock */
lock_flocks();
/* Protect inode->i_flock using the i_lock */
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue;
if (nfs_file_open_context(fl->fl_file) != ctx)
continue;
unlock_flocks();
spin_unlock(&inode->i_lock);
status = nfs4_lock_delegation_recall(fl, state, stateid);
if (status < 0)
goto out;
lock_flocks();
spin_lock(&inode->i_lock);
}
unlock_flocks();
spin_unlock(&inode->i_lock);
out:
return status;
}

View File

@ -1373,13 +1373,13 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
/* Guard against delegation returns and new lock/unlock calls */
down_write(&nfsi->rwsem);
/* Protect inode->i_flock using the BKL */
lock_flocks();
spin_lock(&inode->i_lock);
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
continue;
if (nfs_file_open_context(fl->fl_file)->state != state)
continue;
unlock_flocks();
spin_unlock(&inode->i_lock);
status = ops->recover_lock(state, fl);
switch (status) {
case 0:
@ -1406,9 +1406,9 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
/* kill_proc(fl->fl_pid, SIGLOST, 1); */
status = 0;
}
lock_flocks();
spin_lock(&inode->i_lock);
}
unlock_flocks();
spin_unlock(&inode->i_lock);
out:
up_write(&nfsi->rwsem);
return status;

View File

@ -2645,13 +2645,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru);
/* only place dl_time is set. protected by lock_flocks*/
/* Only place dl_time is set; protected by i_lock: */
dp->dl_time = get_seconds();
nfsd4_cb_recall(dp);
}
/* Called from break_lease() with lock_flocks() held. */
/* Called from break_lease() with i_lock held. */
static void nfsd_break_deleg_cb(struct file_lock *fl)
{
struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
@ -4520,7 +4520,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
struct inode *inode = filp->fi_inode;
int status = 0;
lock_flocks();
spin_lock(&inode->i_lock);
for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
status = 1;
@ -4528,7 +4528,7 @@ check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
}
}
out:
unlock_flocks();
spin_unlock(&inode->i_lock);
return status;
}

View File

@ -399,9 +399,6 @@ static int fanotify_release(struct inode *ignored, struct file *file)
wake_up(&group->fanotify_data.access_waitq);
#endif
if (file->f_flags & FASYNC)
fsnotify_fasync(-1, file, 0);
/* matches the fanotify_init->fsnotify_alloc_group */
fsnotify_destroy_group(group);

View File

@ -2646,17 +2646,7 @@ static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int whence)
goto out;
}
if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
ret = -EINVAL;
if (!ret && offset > inode->i_sb->s_maxbytes)
ret = -EINVAL;
if (ret)
goto out;
if (offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out:
mutex_unlock(&inode->i_mutex);

View File

@ -840,11 +840,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
if (flags & __O_SYNC)
flags |= O_DSYNC;
/*
* If we have O_PATH in the open flag. Then we
* cannot have anything other than the below set of flags
*/
if (flags & O_PATH) {
if (flags & O_TMPFILE) {
if (!(flags & O_CREAT))
return -EINVAL;
acc_mode = MAY_OPEN | ACC_MODE(flags);
} else if (flags & O_PATH) {
/*
* If we have O_PATH in the open flag. Then we
* cannot have anything other than the below set of flags
*/
flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
acc_mode = 0;
} else {
@ -876,7 +880,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
lookup_flags |= LOOKUP_DIRECTORY;
if (!(flags & O_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
return lookup_flags;
op->lookup_flags = lookup_flags;
return 0;
}
/**
@ -893,8 +898,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
struct file *file_open_name(struct filename *name, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
return do_filp_open(AT_FDCWD, name, &op, lookup);
int err = build_open_flags(flags, mode, &op);
return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op);
}
/**
@ -919,37 +924,43 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
const char *filename, int flags)
{
struct open_flags op;
int lookup = build_open_flags(flags, 0, &op);
int err = build_open_flags(flags, 0, &op);
if (err)
return ERR_PTR(err);
if (flags & O_CREAT)
return ERR_PTR(-EINVAL);
if (!filename && (flags & O_DIRECTORY))
if (!dentry->d_inode->i_op->lookup)
return ERR_PTR(-ENOTDIR);
return do_file_open_root(dentry, mnt, filename, &op, lookup);
return do_file_open_root(dentry, mnt, filename, &op);
}
EXPORT_SYMBOL(file_open_root);
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
struct filename *tmp = getname(filename);
int fd = PTR_ERR(tmp);
int fd = build_open_flags(flags, mode, &op);
struct filename *tmp;
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
putname(tmp);
}
putname(tmp);
return fd;
}

View File

@ -1686,41 +1686,29 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
instantiate_t instantiate, struct task_struct *task, const void *ptr)
{
struct dentry *child, *dir = file->f_path.dentry;
struct qstr qname = QSTR_INIT(name, len);
struct inode *inode;
struct qstr qname;
ino_t ino = 0;
unsigned type = DT_UNKNOWN;
unsigned type;
ino_t ino;
qname.name = name;
qname.len = len;
qname.hash = full_name_hash(name, len);
child = d_lookup(dir, &qname);
child = d_hash_and_lookup(dir, &qname);
if (!child) {
struct dentry *new;
new = d_alloc(dir, &qname);
if (new) {
child = instantiate(dir->d_inode, new, task, ptr);
if (child)
dput(new);
else
child = new;
child = d_alloc(dir, &qname);
if (!child)
goto end_instantiate;
if (instantiate(dir->d_inode, child, task, ptr) < 0) {
dput(child);
goto end_instantiate;
}
}
if (!child || IS_ERR(child) || !child->d_inode)
goto end_instantiate;
inode = child->d_inode;
if (inode) {
ino = inode->i_ino;
type = inode->i_mode >> 12;
}
ino = inode->i_ino;
type = inode->i_mode >> 12;
dput(child);
end_instantiate:
if (!ino)
ino = find_inode_number(dir, &qname);
if (!ino)
ino = 1;
return dir_emit(ctx, name, len, ino, type);
end_instantiate:
return dir_emit(ctx, name, len, 1, DT_UNKNOWN);
}
#ifdef CONFIG_CHECKPOINT_RESTORE
@ -1846,7 +1834,7 @@ struct map_files_info {
unsigned char name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */
};
static struct dentry *
static int
proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
struct task_struct *task, const void *ptr)
{
@ -1856,7 +1844,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
return ERR_PTR(-ENOENT);
return -ENOENT;
ei = PROC_I(inode);
ei->op.proc_get_link = proc_map_files_get_link;
@ -1873,7 +1861,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
d_set_d_op(dentry, &tid_map_files_dentry_operations);
d_add(dentry, inode);
return NULL;
return 0;
}
static struct dentry *proc_map_files_lookup(struct inode *dir,
@ -1882,23 +1870,23 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
unsigned long vm_start, vm_end;
struct vm_area_struct *vma;
struct task_struct *task;
struct dentry *result;
int result;
struct mm_struct *mm;
result = ERR_PTR(-EPERM);
result = -EPERM;
if (!capable(CAP_SYS_ADMIN))
goto out;
result = ERR_PTR(-ENOENT);
result = -ENOENT;
task = get_proc_task(dir);
if (!task)
goto out;
result = ERR_PTR(-EACCES);
result = -EACCES;
if (!ptrace_may_access(task, PTRACE_MODE_READ))
goto out_put_task;
result = ERR_PTR(-ENOENT);
result = -ENOENT;
if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
goto out_put_task;
@ -1921,7 +1909,7 @@ out_no_vma:
out_put_task:
put_task_struct(task);
out:
return result;
return ERR_PTR(result);
}
static const struct inode_operations proc_map_files_inode_operations = {
@ -2135,13 +2123,12 @@ static const struct file_operations proc_timers_operations = {
};
#endif /* CONFIG_CHECKPOINT_RESTORE */
static struct dentry *proc_pident_instantiate(struct inode *dir,
static int proc_pident_instantiate(struct inode *dir,
struct dentry *dentry, struct task_struct *task, const void *ptr)
{
const struct pid_entry *p = ptr;
struct inode *inode;
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-ENOENT);
inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
@ -2160,9 +2147,9 @@ static struct dentry *proc_pident_instantiate(struct inode *dir,
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
static struct dentry *proc_pident_lookup(struct inode *dir,
@ -2170,11 +2157,11 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
const struct pid_entry *ents,
unsigned int nents)
{
struct dentry *error;
int error;
struct task_struct *task = get_proc_task(dir);
const struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
error = -ENOENT;
if (!task)
goto out_no_task;
@ -2197,7 +2184,7 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
out:
put_task_struct(task);
out_no_task:
return error;
return ERR_PTR(error);
}
static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
@ -2780,11 +2767,10 @@ void proc_flush_task(struct task_struct *task)
}
}
static struct dentry *proc_pid_instantiate(struct inode *dir,
struct dentry * dentry,
struct task_struct *task, const void *ptr)
static int proc_pid_instantiate(struct inode *dir,
struct dentry * dentry,
struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task);
@ -2804,14 +2790,14 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{
struct dentry *result = NULL;
int result = 0;
struct task_struct *task;
unsigned tgid;
struct pid_namespace *ns;
@ -2832,7 +2818,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsign
result = proc_pid_instantiate(dir, dentry, task, NULL);
put_task_struct(task);
out:
return result;
return ERR_PTR(result);
}
/*
@ -2884,21 +2870,21 @@ retry:
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
{
struct tgid_iter iter;
struct pid_namespace *ns;
struct pid_namespace *ns = file->f_dentry->d_sb->s_fs_info;
loff_t pos = ctx->pos;
if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
return 0;
if (pos == TGID_OFFSET - 1) {
if (!proc_fill_cache(file, ctx, "self", 4, NULL, NULL, NULL))
struct inode *inode = ns->proc_self->d_inode;
if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
return 0;
iter.tgid = 0;
} else {
iter.tgid = pos - TGID_OFFSET;
}
iter.task = NULL;
ns = file->f_dentry->d_sb->s_fs_info;
for (iter = next_tgid(ns, iter);
iter.task;
iter.tgid += 1, iter = next_tgid(ns, iter)) {
@ -3027,10 +3013,9 @@ static const struct inode_operations proc_tid_base_inode_operations = {
.setattr = proc_setattr,
};
static struct dentry *proc_task_instantiate(struct inode *dir,
static int proc_task_instantiate(struct inode *dir,
struct dentry *dentry, struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
inode = proc_pid_make_inode(dir->i_sb, task);
@ -3049,14 +3034,14 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
{
struct dentry *result = ERR_PTR(-ENOENT);
int result = -ENOENT;
struct task_struct *task;
struct task_struct *leader = get_proc_task(dir);
unsigned tid;
@ -3086,7 +3071,7 @@ out_drop_task:
out:
put_task_struct(leader);
out_no_task:
return result;
return ERR_PTR(result);
}
/*

View File

@ -167,11 +167,10 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
return ret;
}
static struct dentry *
static int
proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
unsigned fd = (unsigned long)ptr;
struct proc_inode *ei;
struct inode *inode;
@ -194,9 +193,9 @@ proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
static struct dentry *proc_lookupfd_common(struct inode *dir,
@ -204,7 +203,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
instantiate_t instantiate)
{
struct task_struct *task = get_proc_task(dir);
struct dentry *result = ERR_PTR(-ENOENT);
int result = -ENOENT;
unsigned fd = name_to_int(dentry);
if (!task)
@ -216,7 +215,7 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
out:
put_task_struct(task);
out_no_task:
return result;
return ERR_PTR(result);
}
static int proc_readfd_common(struct file *file, struct dir_context *ctx,
@ -300,11 +299,10 @@ const struct inode_operations proc_fd_inode_operations = {
.setattr = proc_setattr,
};
static struct dentry *
static int
proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
unsigned fd = (unsigned long)ptr;
struct proc_inode *ei;
struct inode *inode;
@ -324,9 +322,9 @@ proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
static struct dentry *

View File

@ -170,7 +170,7 @@ extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned
extern loff_t mem_lseek(struct file *, loff_t, int);
/* Lookups */
typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
typedef int instantiate_t(struct inode *, struct dentry *,
struct task_struct *, const void *);
extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int,
instantiate_t, struct task_struct *, const void *);

View File

@ -187,13 +187,12 @@ static const struct inode_operations proc_ns_link_inode_operations = {
.setattr = proc_setattr,
};
static struct dentry *proc_ns_instantiate(struct inode *dir,
static int proc_ns_instantiate(struct inode *dir,
struct dentry *dentry, struct task_struct *task, const void *ptr)
{
const struct proc_ns_operations *ns_ops = ptr;
struct inode *inode;
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-ENOENT);
inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
@ -208,9 +207,9 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, 0))
error = NULL;
return 0;
out:
return error;
return -ENOENT;
}
static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
@ -248,12 +247,12 @@ const struct file_operations proc_ns_dir_operations = {
static struct dentry *proc_ns_dir_lookup(struct inode *dir,
struct dentry *dentry, unsigned int flags)
{
struct dentry *error;
int error;
struct task_struct *task = get_proc_task(dir);
const struct proc_ns_operations **entry, **last;
unsigned int len = dentry->d_name.len;
error = ERR_PTR(-ENOENT);
error = -ENOENT;
if (!task)
goto out_no_task;
@ -272,7 +271,7 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,
out:
put_task_struct(task);
out_no_task:
return error;
return ERR_PTR(error);
}
const struct inode_operations proc_ns_dir_inode_operations = {

View File

@ -796,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p)
return res;
}
static int proc_sys_compare(const struct dentry *parent,
const struct inode *pinode,
const struct dentry *dentry, const struct inode *inode,
static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry,
unsigned int len, const char *str, const struct qstr *name)
{
struct ctl_table_header *head;
struct inode *inode;
/* Although proc doesn't have negative dentries, rcu-walk means
* that inode here can be NULL */
/* AV: can it, indeed? */
inode = ACCESS_ONCE(dentry->d_inode);
if (!inode)
return 1;
if (name->len != len)

View File

@ -41,8 +41,19 @@ static inline int unsigned_offsets(struct file *file)
return file->f_mode & FMODE_UNSIGNED_OFFSET;
}
static loff_t lseek_execute(struct file *file, struct inode *inode,
loff_t offset, loff_t maxsize)
/**
* vfs_setpos - update the file offset for lseek
* @file: file structure in question
* @offset: file offset to seek to
* @maxsize: maximum file size
*
* This is a low-level filesystem helper for updating the file offset to
* the value specified by @offset if the given offset is valid and it is
* not equal to the current file offset.
*
* Return the specified offset on success and -EINVAL on invalid offset.
*/
loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize)
{
if (offset < 0 && !unsigned_offsets(file))
return -EINVAL;
@ -55,6 +66,7 @@ static loff_t lseek_execute(struct file *file, struct inode *inode,
}
return offset;
}
EXPORT_SYMBOL(vfs_setpos);
/**
* generic_file_llseek_size - generic llseek implementation for regular files
@ -76,8 +88,6 @@ loff_t
generic_file_llseek_size(struct file *file, loff_t offset, int whence,
loff_t maxsize, loff_t eof)
{
struct inode *inode = file->f_mapping->host;
switch (whence) {
case SEEK_END:
offset += eof;
@ -97,8 +107,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
* like SEEK_SET.
*/
spin_lock(&file->f_lock);
offset = lseek_execute(file, inode, file->f_pos + offset,
maxsize);
offset = vfs_setpos(file, file->f_pos + offset, maxsize);
spin_unlock(&file->f_lock);
return offset;
case SEEK_DATA:
@ -120,7 +129,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int whence,
break;
}
return lseek_execute(file, inode, offset, maxsize);
return vfs_setpos(file, offset, maxsize);
}
EXPORT_SYMBOL(generic_file_llseek_size);
@ -144,6 +153,26 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
}
EXPORT_SYMBOL(generic_file_llseek);
/**
* fixed_size_llseek - llseek implementation for fixed-sized devices
* @file: file structure to seek on
* @offset: file offset to seek to
* @whence: type of seek
* @size: size of the file
*
*/
loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size)
{
switch (whence) {
case SEEK_SET: case SEEK_CUR: case SEEK_END:
return generic_file_llseek_size(file, offset, whence,
size, size);
default:
return -EINVAL;
}
}
EXPORT_SYMBOL(fixed_size_llseek);
/**
* noop_llseek - No Operation Performed llseek implementation
* @file: file structure to seek on
@ -296,7 +325,7 @@ out_putf:
* them to something that fits in "int" so that others
* won't have to do range checks all the time.
*/
int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count)
{
struct inode *inode;
loff_t pos;
@ -477,7 +506,8 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
file_pos_write(f.file, pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput(f);
}
return ret;
@ -492,7 +522,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_write(f.file, buf, count, &pos);
file_pos_write(f.file, pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput(f);
}
@ -780,7 +811,8 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_readv(f.file, vec, vlen, &pos);
file_pos_write(f.file, pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput(f);
}
@ -799,7 +831,8 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_writev(f.file, vec, vlen, &pos);
file_pos_write(f.file, pos);
if (ret >= 0)
file_pos_write(f.file, pos);
fdput(f);
}
@ -959,7 +992,8 @@ COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
return -EBADF;
pos = f.file->f_pos;
ret = compat_readv(f.file, vec, vlen, &pos);
f.file->f_pos = pos;
if (ret >= 0)
f.file->f_pos = pos;
fdput(f);
return ret;
}
@ -1025,7 +1059,8 @@ COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
return -EBADF;
pos = f.file->f_pos;
ret = compat_writev(f.file, vec, vlen, &pos);
f.file->f_pos = pos;
if (ret >= 0)
f.file->f_pos = pos;
fdput(f);
return ret;
}
@ -1129,7 +1164,9 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
if (in.file->f_flags & O_NONBLOCK)
fl = SPLICE_F_NONBLOCK;
#endif
file_start_write(out.file);
retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl);
file_end_write(out.file);
if (retval > 0) {
add_rchar(current, retval);

View File

@ -1098,27 +1098,13 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
{
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
loff_t *, size_t, unsigned int);
int ret;
if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
if (unlikely(out->f_flags & O_APPEND))
return -EINVAL;
ret = rw_verify_area(WRITE, out, ppos, len);
if (unlikely(ret < 0))
return ret;
if (out->f_op && out->f_op->splice_write)
splice_write = out->f_op->splice_write;
else
splice_write = default_file_splice_write;
file_start_write(out);
ret = splice_write(pipe, out, ppos, len, flags);
file_end_write(out);
return ret;
return splice_write(pipe, out, ppos, len, flags);
}
/*
@ -1307,6 +1293,16 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
};
long ret;
if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
if (unlikely(out->f_flags & O_APPEND))
return -EINVAL;
ret = rw_verify_area(WRITE, out, opos, len);
if (unlikely(ret < 0))
return ret;
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
if (ret > 0)
*ppos = sd.pos;
@ -1362,7 +1358,19 @@ static long do_splice(struct file *in, loff_t __user *off_in,
offset = out->f_pos;
}
if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
if (unlikely(out->f_flags & O_APPEND))
return -EINVAL;
ret = rw_verify_area(WRITE, out, &offset, len);
if (unlikely(ret < 0))
return ret;
file_start_write(out);
ret = do_splice_from(ipipe, out, &offset, len, flags);
file_end_write(out);
if (!off_out)
out->f_pos = offset;

View File

@ -27,8 +27,7 @@ static int add_nondir(struct dentry *dentry, struct inode *inode)
return err;
}
static int sysv_hash(const struct dentry *dentry, const struct inode *inode,
struct qstr *qstr)
static int sysv_hash(const struct dentry *dentry, struct qstr *qstr)
{
/* Truncate the name in place, avoids having to define a compare
function. */

View File

@ -594,6 +594,29 @@ static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
return 0;
}
static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct inode *inode;
struct udf_inode_info *iinfo;
int err;
inode = udf_new_inode(dir, mode, &err);
if (!inode)
return err;
iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
inode->i_data.a_ops = &udf_adinicb_aops;
else
inode->i_data.a_ops = &udf_aops;
inode->i_op = &udf_file_inode_operations;
inode->i_fop = &udf_file_operations;
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
return 0;
}
static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t rdev)
{
@ -1311,6 +1334,7 @@ const struct inode_operations udf_dir_inode_operations = {
.rmdir = udf_rmdir,
.mknod = udf_mknod,
.rename = udf_rename,
.tmpfile = udf_tmpfile,
};
const struct inode_operations udf_symlink_inode_operations = {
.readlink = generic_readlink,

View File

@ -1268,8 +1268,7 @@ xfs_seek_data(
}
out:
if (offset != file->f_pos)
file->f_pos = offset;
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock:
xfs_iunlock_map_shared(ip, lock);
@ -1377,8 +1376,7 @@ out:
* situation in particular.
*/
offset = min_t(loff_t, offset, isize);
if (offset != file->f_pos)
file->f_pos = offset;
offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
out_unlock:
xfs_iunlock_map_shared(ip, lock);

View File

@ -146,10 +146,8 @@ enum dentry_d_lock_class
struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
int (*d_hash)(const struct dentry *, const struct inode *,
struct qstr *);
int (*d_compare)(const struct dentry *, const struct inode *,
const struct dentry *, const struct inode *,
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
@ -246,6 +244,8 @@ extern struct dentry * d_make_root(struct inode *);
/* <clickety>-<click> the ramfs-type tree */
extern void d_genocide(struct dentry *);
extern void d_tmpfile(struct dentry *, struct inode *);
extern struct dentry *d_find_alias(struct inode *);
extern void d_prune_aliases(struct inode *);
@ -300,8 +300,7 @@ extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name,
unsigned *seq, struct inode *inode);
const struct qstr *name, unsigned *seq);
/**
* __d_rcu_to_refcount - take a refcount on dentry if sequence check is ok

View File

@ -908,6 +908,7 @@ struct file_lock_operations {
struct lock_manager_operations {
int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
unsigned long (*lm_owner_key)(struct file_lock *);
void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, struct file_lock *, int);
void (*lm_break)(struct file_lock *);
@ -926,9 +927,27 @@ int locks_in_grace(struct net *);
/* that will die - we need it for nfs_lock_info */
#include <linux/nfs_fs_i.h>
/*
* struct file_lock represents a generic "file lock". It's used to represent
* POSIX byte range locks, BSD (flock) locks, and leases. It's important to
* note that the same struct is used to represent both a request for a lock and
* the lock itself, but the same object is never used for both.
*
* FIXME: should we create a separate "struct lock_request" to help distinguish
* these two uses?
*
* The i_flock list is ordered by:
*
* 1) lock type -- FL_LEASEs first, then FL_FLOCK, and finally FL_POSIX
* 2) lock owner
* 3) lock range start
* 4) lock range end
*
* Obviously, the last two criteria only matter for POSIX locks.
*/
struct file_lock {
struct file_lock *fl_next; /* singly linked list for this inode */
struct list_head fl_link; /* doubly linked list of all locks */
struct hlist_node fl_link; /* node in global lists */
struct list_head fl_block; /* circular list of blocked processes */
fl_owner_t fl_owner;
unsigned int fl_flags;
@ -994,7 +1013,7 @@ extern void locks_release_private(struct file_lock *);
extern void posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file_lock *);
extern int vfs_test_lock(struct file *, struct file_lock *);
extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
@ -1006,9 +1025,6 @@ extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
extern void locks_delete_block(struct file_lock *waiter);
extern void lock_flocks(void);
extern void unlock_flocks(void);
#else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, struct flock __user *user)
{
@ -1084,8 +1100,7 @@ static inline int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
return -ENOLCK;
}
static inline int posix_unblock_lock(struct file *filp,
struct file_lock *waiter)
static inline int posix_unblock_lock(struct file_lock *waiter)
{
return -ENOENT;
}
@ -1150,19 +1165,6 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
{
return 1;
}
static inline void locks_delete_block(struct file_lock *waiter)
{
}
static inline void lock_flocks(void)
{
}
static inline void unlock_flocks(void)
{
}
#endif /* !CONFIG_FILE_LOCKING */
@ -1580,6 +1582,7 @@ struct inode_operations {
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
} ____cacheline_aligned;
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@ -1743,6 +1746,7 @@ struct super_operations {
#define I_REFERENCED (1 << 8)
#define __I_DIO_WAKEUP 9
#define I_DIO_WAKEUP (1 << I_DIO_WAKEUP)
#define I_LINKABLE (1 << 10)
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
@ -1896,7 +1900,6 @@ extern int current_umask(void);
extern struct kobject *fs_kobj;
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
extern int rw_verify_area(int, struct file *, loff_t *, size_t);
#define FLOCK_VERIFY_READ 1
#define FLOCK_VERIFY_WRITE 2
@ -2309,7 +2312,6 @@ extern struct file * open_exec(const char *);
/* fs/dcache.c -- generic fs support functions */
extern int is_subdir(struct dentry *, struct dentry *);
extern int path_is_under(struct path *, struct path *);
extern ino_t find_inode_number(struct dentry *, struct qstr *);
#include <linux/err.h>
@ -2424,9 +2426,12 @@ extern void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
extern loff_t noop_llseek(struct file *file, loff_t offset, int whence);
extern loff_t no_llseek(struct file *file, loff_t offset, int whence);
extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize);
extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence);
extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
int whence, loff_t maxsize, loff_t eof);
extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
int whence, loff_t size);
extern int generic_file_open(struct inode * inode, struct file * filp);
extern int nonseekable_open(struct inode * inode, struct file * filp);

View File

@ -38,7 +38,7 @@ static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u3
static inline int fsnotify_perm(struct file *file, int mask)
{
struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
struct inode *inode = file_inode(file);
__u32 fsnotify_mask = 0;
int ret;
@ -192,7 +192,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_access(struct file *file)
{
struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
struct inode *inode = file_inode(file);
__u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode))
@ -210,7 +210,7 @@ static inline void fsnotify_access(struct file *file)
static inline void fsnotify_modify(struct file *file)
{
struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
struct inode *inode = file_inode(file);
__u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode))
@ -228,7 +228,7 @@ static inline void fsnotify_modify(struct file *file)
static inline void fsnotify_open(struct file *file)
{
struct path *path = &file->f_path;
struct inode *inode = path->dentry->d_inode;
struct inode *inode = file_inode(file);
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))

View File

@ -84,6 +84,10 @@
#define O_PATH 010000000
#endif
#ifndef O_TMPFILE
#define O_TMPFILE 020000000
#endif
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif

View File

@ -1798,10 +1798,7 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
}
}
if (offset >= 0 && offset != file->f_pos) {
file->f_pos = offset;
file->f_version = 0;
}
offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
mutex_unlock(&inode->i_mutex);
return offset;
}
@ -1965,6 +1962,37 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
return error;
}
static int
shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct inode *inode;
int error = -ENOSPC;
inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE);
if (inode) {
error = security_inode_init_security(inode, dir,
NULL,
shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
return error;
}
}
#ifdef CONFIG_TMPFS_POSIX_ACL
error = generic_acl_init(inode, dir);
if (error) {
iput(inode);
return error;
}
#else
error = 0;
#endif
d_tmpfile(dentry, inode);
}
return error;
}
static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int error;
@ -2723,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
.rmdir = shmem_rmdir,
.mknod = shmem_mknod,
.rename = shmem_rename,
.tmpfile = shmem_tmpfile,
#endif
#ifdef CONFIG_TMPFS_XATTR
.setxattr = shmem_setxattr,

View File

@ -1330,7 +1330,7 @@ static int wait_for_gss_proxy(struct net *net, struct file *file)
static ssize_t write_gssp(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
struct net *net = PDE_DATA(file_inode(file));
char tbuf[20];
unsigned long i;
int res;
@ -1358,7 +1358,7 @@ static ssize_t write_gssp(struct file *file, const char __user *buf,
static ssize_t read_gssp(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
struct net *net = PDE_DATA(file_inode(file));
unsigned long p = *ppos;
char tbuf[10];
size_t len;

View File

@ -57,7 +57,7 @@ __setup("ima_hash=", hash_setup);
static void ima_rdwr_violation_check(struct file *file)
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct inode *inode = file_inode(file);
fmode_t mode = file->f_mode;
int must_measure;
bool send_tomtou = false, send_writers = false;

View File

@ -1547,6 +1547,18 @@ static inline int path_has_perm(const struct cred *cred,
return inode_has_perm(cred, inode, av, &ad, 0);
}
/* Same as path_has_perm, but uses the inode from the file struct. */
static inline int file_path_has_perm(const struct cred *cred,
struct file *file,
u32 av)
{
struct common_audit_data ad;
ad.type = LSM_AUDIT_DATA_PATH;
ad.u.path = file->f_path;
return inode_has_perm(cred, file_inode(file), av, &ad, 0);
}
/* Check whether a task can use an open file descriptor to
access an inode in a given way. Check access to the
descriptor itself, and then use dentry_has_perm to
@ -2141,14 +2153,14 @@ static inline void flush_unauthorized_files(const struct cred *cred,
struct tty_file_private *file_priv;
/* Revalidate access to controlling tty.
Use path_has_perm on the tty path directly rather
than using file_has_perm, as this particular open
file may belong to another process and we are only
interested in the inode-based check here. */
Use file_path_has_perm on the tty path directly
rather than using file_has_perm, as this particular
open file may belong to another process and we are
only interested in the inode-based check here. */
file_priv = list_first_entry(&tty->tty_files,
struct tty_file_private, list);
file = file_priv->file;
if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE))
if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
drop_tty = 1;
}
spin_unlock(&tty_files_lock);
@ -3259,7 +3271,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
return path_has_perm(cred, &file->f_path, open_file_to_av(file));
return file_path_has_perm(cred, file, open_file_to_av(file));
}
/* task security operations */

View File

@ -1589,29 +1589,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
}
/* WARNING: Don't forget to fput back the file */
static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
static bool is_pcm_file(struct file *file)
{
struct file *file;
struct inode *inode;
struct inode *inode = file_inode(file);
unsigned int minor;
file = fget_light(fd, fput_needed);
if (!file)
return NULL;
inode = file_inode(file);
if (!S_ISCHR(inode->i_mode) ||
imajor(inode) != snd_major) {
fput_light(file, *fput_needed);
return NULL;
}
if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
return false;
minor = iminor(inode);
if (!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) &&
!snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE)) {
fput_light(file, *fput_needed);
return NULL;
}
return file;
return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
}
/*
@ -1620,16 +1607,18 @@ static struct file *snd_pcm_file_fd(int fd, int *fput_needed)
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
{
int res = 0;
struct file *file;
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream1;
struct snd_pcm_group *group;
int fput_needed;
struct fd f = fdget(fd);
file = snd_pcm_file_fd(fd, &fput_needed);
if (!file)
if (!f.file)
return -EBADFD;
pcm_file = file->private_data;
if (!is_pcm_file(f.file)) {
res = -EBADFD;
goto _badf;
}
pcm_file = f.file->private_data;
substream1 = pcm_file->substream;
group = kmalloc(sizeof(*group), GFP_KERNEL);
if (!group) {
@ -1663,8 +1652,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
up_write(&snd_pcm_link_rwsem);
_nolock:
snd_card_unref(substream1->pcm->card);
fput_light(file, fput_needed);
kfree(group);
_badf:
fdput(f);
return res;
}