Commit 790eac56 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 0b0585c3 48bde8d3
......@@ -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:
......
......@@ -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.
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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,
......
......@@ -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. */
......
......@@ -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,
......
......@@ -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,
......
......@@ -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;
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
......
......@@ -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,
......
......@@ -167,26 +167,8 @@ static int open(struct inode *inode, struct file *file)
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,
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
}
/*
......
......@@ -1165,22 +1165,8 @@ lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
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);
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment