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 vfs updates from Al Viro:
 "Stuff in here:

   - acct.c fixes and general rework of mnt_pin mechanism.  That allows
     to go for delayed-mntput stuff, which will permit mntput() on deep
     stack without worrying about stack overflows - fs shutdown will
     happen on shallow stack.  IOW, we can do Eric's umount-on-rmdir
     series without introducing tons of stack overflows on new mntput()
     call chains it introduces.
   - Bruce's d_splice_alias() patches
   - more Miklos' rename() stuff.
   - a couple of regression fixes (stable fodder, in the end of branch)
     and a fix for API idiocy in iov_iter.c.

  There definitely will be another pile, maybe even two.  I'd like to
  get Eric's series in this time, but even if we miss it, it'll go right
  in the beginning of for-next in the next cycle - the tricky part of
  prereqs is in this pile"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
  fix copy_tree() regression
  __generic_file_write_iter(): fix handling of sync error after DIO
  switch iov_iter_get_pages() to passing maximal number of pages
  fs: mark __d_obtain_alias static
  dcache: d_splice_alias should detect loops
  exportfs: update Exporting documentation
  dcache: d_find_alias needn't recheck IS_ROOT && DCACHE_DISCONNECTED
  dcache: remove unused d_find_alias parameter
  dcache: d_obtain_alias callers don't all want DISCONNECTED
  dcache: d_splice_alias should ignore DCACHE_DISCONNECTED
  dcache: d_splice_alias mustn't create directory aliases
  dcache: close d_move race in d_splice_alias
  dcache: move d_splice_alias
  namei: trivial fix to vfs_rename_dir comment
  VFS: allow ->d_manage() to declare -EISDIR in rcu_walk mode.
  cifs: support RENAME_NOREPLACE
  hostfs: support rename flags
  shmem: support RENAME_EXCHANGE
  shmem: support RENAME_NOREPLACE
  btrfs: add RENAME_NOREPLACE
  ...
  • Loading branch information
torvalds committed Aug 11, 2014
2 parents c7a19c7 + 12a5b52 commit f6f9933
Show file tree
Hide file tree
Showing 36 changed files with 645 additions and 465 deletions.
38 changes: 23 additions & 15 deletions Documentation/filesystems/nfs/Exporting
Original file line number Diff line number Diff line change
Expand Up @@ -66,23 +66,31 @@ b/ A per-superblock list "s_anon" of dentries which are the roots of

c/ Helper routines to allocate anonymous dentries, and to help attach
loose directory dentries at lookup time. They are:
d_alloc_anon(inode) will return a dentry for the given inode.
d_obtain_alias(inode) will return a dentry for the given inode.
If the inode already has a dentry, one of those is returned.
If it doesn't, a new anonymous (IS_ROOT and
DCACHE_DISCONNECTED) dentry is allocated and attached.
In the case of a directory, care is taken that only one dentry
can ever be attached.
d_splice_alias(inode, dentry) will make sure that there is a
dentry with the same name and parent as the given dentry, and
which refers to the given inode.
If the inode is a directory and already has a dentry, then that
dentry is d_moved over the given dentry.
If the passed dentry gets attached, care is taken that this is
mutually exclusive to a d_alloc_anon operation.
If the passed dentry is used, NULL is returned, else the used
dentry is returned. This corresponds to the calling pattern of
->lookup.

d_splice_alias(inode, dentry) or d_materialise_unique(dentry, inode)
will introduce a new dentry into the tree; either the passed-in
dentry or a preexisting alias for the given inode (such as an
anonymous one created by d_obtain_alias), if appropriate. The two
functions differ in their handling of directories with preexisting
aliases:
d_splice_alias will use any existing IS_ROOT dentry, but it will
return -EIO rather than try to move a dentry with a different
parent. This is appropriate for local filesystems, which
should never see such an alias unless the filesystem is
corrupted somehow (for example, if two on-disk directory
entries refer to the same directory.)
d_materialise_unique will attempt to move any dentry. This is
appropriate for distributed filesystems, where finding a
directory other than where we last cached it may be a normal
consequence of concurrent operations on other hosts.
Both functions return NULL when the passed-in dentry is used,
following the calling convention of ->lookup.


Filesystem Issues
-----------------
Expand Down Expand Up @@ -120,12 +128,12 @@ struct which has the following members:

fh_to_dentry (mandatory)
Given a filehandle fragment, this should find the implied object and
create a dentry for it (possibly with d_alloc_anon).
create a dentry for it (possibly with d_obtain_alias).

fh_to_parent (optional but strongly recommended)
Given a filehandle fragment, this should find the parent of the
implied object and create a dentry for it (possibly with d_alloc_anon).
May fail if the filehandle fragment is too small.
implied object and create a dentry for it (possibly with
d_obtain_alias). May fail if the filehandle fragment is too small.

get_parent (optional but strongly recommended)
When given a dentry for a directory, this should return a dentry for
Expand Down
3 changes: 2 additions & 1 deletion Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,8 @@ struct dentry_operations {
If the 'rcu_walk' parameter is true, then the caller is doing a
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
and the caller can be asked to leave it and call again by returning
-ECHILD.
-ECHILD. -EISDIR may also be returned to tell pathwalk to
ignore d_automount or any mounts.

This function is only used if DCACHE_MANAGE_TRANSIT is set on the
dentry being transited from.
Expand Down
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o splice.o sync.o utimes.o \
stack.o fs_struct.o statfs.o
stack.o fs_struct.o statfs.o fs_pin.o

ifeq ($(CONFIG_BLOCK),y)
obj-y += buffer.o block_dev.o direct-io.o mpage.o
Expand Down
7 changes: 4 additions & 3 deletions fs/bad_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ static int bad_inode_mknod (struct inode *dir, struct dentry *dentry,
return -EIO;
}

static int bad_inode_rename (struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
static int bad_inode_rename2(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
return -EIO;
}
Expand Down Expand Up @@ -279,7 +280,7 @@ static const struct inode_operations bad_inode_ops =
.mkdir = bad_inode_mkdir,
.rmdir = bad_inode_rmdir,
.mknod = bad_inode_mknod,
.rename = bad_inode_rename,
.rename2 = bad_inode_rename2,
.readlink = bad_inode_readlink,
/* follow_link must be no-op, otherwise unmounting this inode
won't work */
Expand Down
12 changes: 11 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -8476,6 +8476,16 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return ret;
}

static int btrfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
if (flags & ~RENAME_NOREPLACE)
return -EINVAL;

return btrfs_rename(old_dir, old_dentry, new_dir, new_dentry);
}

static void btrfs_run_delalloc_work(struct btrfs_work *work)
{
struct btrfs_delalloc_work *delalloc_work;
Expand Down Expand Up @@ -9019,7 +9029,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.link = btrfs_link,
.mkdir = btrfs_mkdir,
.rmdir = btrfs_rmdir,
.rename = btrfs_rename,
.rename2 = btrfs_rename2,
.symlink = btrfs_symlink,
.setattr = btrfs_setattr,
.mknod = btrfs_mknod,
Expand Down
9 changes: 1 addition & 8 deletions fs/btrfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,6 @@ static struct dentry *get_default_root(struct super_block *sb,
struct btrfs_path *path;
struct btrfs_key location;
struct inode *inode;
struct dentry *dentry;
u64 dir_id;
int new = 0;

Expand Down Expand Up @@ -922,13 +921,7 @@ static struct dentry *get_default_root(struct super_block *sb,
return dget(sb->s_root);
}

dentry = d_obtain_alias(inode);
if (!IS_ERR(dentry)) {
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_DISCONNECTED;
spin_unlock(&dentry->d_lock);
}
return dentry;
return d_obtain_root(inode);
}

static int btrfs_fill_super(struct super_block *sb,
Expand Down
2 changes: 1 addition & 1 deletion fs/ceph/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
goto out;
}
} else {
root = d_obtain_alias(inode);
root = d_obtain_root(inode);
}
ceph_init_dentry(root);
dout("open_root_inode success, root dentry is %p\n", root);
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ const struct inode_operations cifs_dir_inode_ops = {
.link = cifs_hardlink,
.mkdir = cifs_mkdir,
.rmdir = cifs_rmdir,
.rename = cifs_rename,
.rename2 = cifs_rename2,
.permission = cifs_permission,
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
Expand Down
4 changes: 2 additions & 2 deletions fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
extern int cifs_mkdir(struct inode *, struct dentry *, umode_t);
extern int cifs_rmdir(struct inode *, struct dentry *);
extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *);
extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
struct dentry *, unsigned int);
extern int cifs_revalidate_file_attr(struct file *filp);
extern int cifs_revalidate_dentry_attr(struct dentry *);
extern int cifs_revalidate_file(struct file *filp);
Expand Down
14 changes: 12 additions & 2 deletions fs/cifs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1627,8 +1627,9 @@ cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
}

int
cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
struct inode *target_dir, struct dentry *target_dentry)
cifs_rename2(struct inode *source_dir, struct dentry *source_dentry,
struct inode *target_dir, struct dentry *target_dentry,
unsigned int flags)
{
char *from_name = NULL;
char *to_name = NULL;
Expand All @@ -1640,6 +1641,9 @@ cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
unsigned int xid;
int rc, tmprc;

if (flags & ~RENAME_NOREPLACE)
return -EINVAL;

cifs_sb = CIFS_SB(source_dir->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
Expand Down Expand Up @@ -1667,6 +1671,12 @@ cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
to_name);

/*
* No-replace is the natural behavior for CIFS, so skip unlink hacks.
*/
if (flags & RENAME_NOREPLACE)
goto cifs_rename_exit;

if (rc == -EEXIST && tcon->unix_ext) {
/*
* Are src and dst hardlinks of same inode? We can only tell
Expand Down
Loading

0 comments on commit f6f9933

Please sign in to comment.