Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  ...
  • Loading branch information
torvalds committed Jul 3, 2013
2 parents 0b0585c + 48bde8d commit 790eac5
Show file tree
Hide file tree
Showing 98 changed files with 979 additions and 986 deletions.
35 changes: 24 additions & 11 deletions Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 13 additions & 11 deletions Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
Expand Down Expand Up @@ -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
========================

Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions arch/alpha/include/uapi/asm/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/arc/kernel/troubleshoot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions arch/parisc/include/uapi/asm/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 2 additions & 18 deletions arch/powerpc/kernel/proc_powerpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/include/uapi/asm/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
28 changes: 2 additions & 26 deletions drivers/char/ps3flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 3 additions & 25 deletions drivers/char/tile-srom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 1 addition & 19 deletions drivers/mtd/mtdchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
26 changes: 1 addition & 25 deletions drivers/mtd/ubi/cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,38 +155,14 @@ 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 */
ubi_err("updating");
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,
Expand Down
22 changes: 1 addition & 21 deletions drivers/net/ethernet/brocade/bna/bnad_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/wireless/ti/wlcore/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 790eac5

Please sign in to comment.