2009-04-07 10:01:34 +08:00
|
|
|
/*
|
|
|
|
* namei.c - NILFS pathname lookup operations.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
2016-05-24 07:23:09 +08:00
|
|
|
* Modified for NILFS by Amagai Yoshiji and Ryusuke Konishi.
|
2009-04-07 10:01:34 +08:00
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* linux/fs/ext2/namei.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1992, 1993, 1994, 1995
|
|
|
|
* Remy Card (card@masi.ibp.fr)
|
|
|
|
* Laboratoire MASI - Institut Blaise Pascal
|
|
|
|
* Universite Pierre et Marie Curie (Paris VI)
|
|
|
|
*
|
|
|
|
* from
|
|
|
|
*
|
|
|
|
* linux/fs/minix/namei.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
|
|
*
|
|
|
|
* Big-endian to little-endian byte-swapping/bitmaps by
|
|
|
|
* David S. Miller (davem@caip.rutgers.edu), 1995
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include "nilfs.h"
|
2010-08-26 23:23:02 +08:00
|
|
|
#include "export.h"
|
2009-04-07 10:01:34 +08:00
|
|
|
|
2010-08-26 23:23:02 +08:00
|
|
|
#define NILFS_FID_SIZE_NON_CONNECTABLE \
|
|
|
|
(offsetof(struct nilfs_fid, parent_gen) / 4)
|
|
|
|
#define NILFS_FID_SIZE_CONNECTABLE (sizeof(struct nilfs_fid) / 4)
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)
|
|
|
|
{
|
|
|
|
int err = nilfs_add_link(dentry, inode);
|
2016-05-24 07:23:25 +08:00
|
|
|
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!err) {
|
|
|
|
d_instantiate(dentry, inode);
|
2014-12-11 07:54:34 +08:00
|
|
|
unlock_new_inode(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
inode_dec_link_count(inode);
|
2014-12-11 07:54:34 +08:00
|
|
|
unlock_new_inode(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
iput(inode);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Methods themselves.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct dentry *
|
2012-06-11 05:13:09 +08:00
|
|
|
nilfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
ino_t ino;
|
|
|
|
|
|
|
|
if (dentry->d_name.len > NILFS_NAME_LEN)
|
|
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
|
|
|
2010-02-01 10:02:09 +08:00
|
|
|
ino = nilfs_inode_by_name(dir, &dentry->d_name);
|
2011-07-09 09:20:11 +08:00
|
|
|
inode = ino ? nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino) : NULL;
|
2009-04-07 10:01:34 +08:00
|
|
|
return d_splice_alias(inode, dentry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* By the time this is called, we already have created
|
|
|
|
* the directory cache entry for the new file, but it
|
|
|
|
* is so far negative - it has no inode.
|
|
|
|
*
|
|
|
|
* If the create succeeds, we fill in the inode information
|
|
|
|
* with d_instantiate().
|
|
|
|
*/
|
2011-07-26 13:42:34 +08:00
|
|
|
static int nilfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
2012-06-11 06:05:36 +08:00
|
|
|
bool excl)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct nilfs_transaction_info ti;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
inode = nilfs_new_inode(dir, mode);
|
|
|
|
err = PTR_ERR(inode);
|
|
|
|
if (!IS_ERR(inode)) {
|
|
|
|
inode->i_op = &nilfs_file_inode_operations;
|
|
|
|
inode->i_fop = &nilfs_file_operations;
|
|
|
|
inode->i_mapping->a_ops = &nilfs_aops;
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
err = nilfs_add_nondir(dentry, inode);
|
|
|
|
}
|
2009-04-07 10:01:45 +08:00
|
|
|
if (!err)
|
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
|
|
|
else
|
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-07-26 13:52:52 +08:00
|
|
|
nilfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct nilfs_transaction_info ti;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
inode = nilfs_new_inode(dir, mode);
|
|
|
|
err = PTR_ERR(inode);
|
|
|
|
if (!IS_ERR(inode)) {
|
|
|
|
init_special_inode(inode, inode->i_mode, rdev);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
err = nilfs_add_nondir(dentry, inode);
|
|
|
|
}
|
2009-04-07 10:01:45 +08:00
|
|
|
if (!err)
|
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
|
|
|
else
|
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int nilfs_symlink(struct inode *dir, struct dentry *dentry,
|
|
|
|
const char *symname)
|
|
|
|
{
|
|
|
|
struct nilfs_transaction_info ti;
|
|
|
|
struct super_block *sb = dir->i_sb;
|
2016-05-24 07:23:39 +08:00
|
|
|
unsigned int l = strlen(symname) + 1;
|
2009-04-07 10:01:34 +08:00
|
|
|
struct inode *inode;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
if (l > sb->s_blocksize)
|
|
|
|
return -ENAMETOOLONG;
|
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2017-11-18 07:29:46 +08:00
|
|
|
inode = nilfs_new_inode(dir, S_IFLNK | 0777);
|
2009-04-07 10:01:34 +08:00
|
|
|
err = PTR_ERR(inode);
|
|
|
|
if (IS_ERR(inode))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* slow symlink */
|
|
|
|
inode->i_op = &nilfs_symlink_inode_operations;
|
2015-11-17 14:07:57 +08:00
|
|
|
inode_nohighmem(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
inode->i_mapping->a_ops = &nilfs_aops;
|
|
|
|
err = page_symlink(inode, symname, l);
|
|
|
|
if (err)
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
/* mark_inode_dirty(inode); */
|
2009-11-27 18:41:06 +08:00
|
|
|
/* page_symlink() do this */
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_add_nondir(dentry, inode);
|
|
|
|
out:
|
2009-04-07 10:01:45 +08:00
|
|
|
if (!err)
|
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
|
|
|
else
|
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
out_fail:
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(inode);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2014-12-11 07:54:34 +08:00
|
|
|
unlock_new_inode(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
iput(inode);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
|
struct dentry *dentry)
|
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct inode *inode = d_inode(old_dentry);
|
2009-04-07 10:01:34 +08:00
|
|
|
struct nilfs_transaction_info ti;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2016-09-14 22:48:04 +08:00
|
|
|
inode->i_ctime = current_time(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
inode_inc_link_count(inode);
|
2010-10-23 23:11:40 +08:00
|
|
|
ihold(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
2014-12-11 07:54:34 +08:00
|
|
|
err = nilfs_add_link(dentry, inode);
|
|
|
|
if (!err) {
|
|
|
|
d_instantiate(dentry, inode);
|
2009-04-07 10:01:45 +08:00
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
2014-12-11 07:54:34 +08:00
|
|
|
} else {
|
|
|
|
inode_dec_link_count(inode);
|
|
|
|
iput(inode);
|
2009-04-07 10:01:45 +08:00
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
2014-12-11 07:54:34 +08:00
|
|
|
}
|
2009-04-07 10:01:45 +08:00
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
2011-07-26 13:41:39 +08:00
|
|
|
static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct nilfs_transaction_info ti;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 1);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2009-11-27 18:41:08 +08:00
|
|
|
inc_nlink(dir);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
inode = nilfs_new_inode(dir, S_IFDIR | mode);
|
|
|
|
err = PTR_ERR(inode);
|
|
|
|
if (IS_ERR(inode))
|
|
|
|
goto out_dir;
|
|
|
|
|
|
|
|
inode->i_op = &nilfs_dir_inode_operations;
|
|
|
|
inode->i_fop = &nilfs_dir_operations;
|
|
|
|
inode->i_mapping->a_ops = &nilfs_aops;
|
|
|
|
|
2009-11-27 18:41:08 +08:00
|
|
|
inc_nlink(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_make_empty(inode, dir);
|
|
|
|
if (err)
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
err = nilfs_add_link(dentry, inode);
|
|
|
|
if (err)
|
|
|
|
goto out_fail;
|
|
|
|
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
d_instantiate(dentry, inode);
|
2014-12-11 07:54:34 +08:00
|
|
|
unlock_new_inode(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
out:
|
2009-04-07 10:01:45 +08:00
|
|
|
if (!err)
|
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
|
|
|
else
|
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
out_fail:
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(inode);
|
|
|
|
drop_nlink(inode);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2014-12-11 07:54:34 +08:00
|
|
|
unlock_new_inode(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
iput(inode);
|
|
|
|
out_dir:
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(dir);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(dir);
|
2009-04-07 10:01:34 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2009-11-27 18:41:10 +08:00
|
|
|
static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct nilfs_dir_entry *de;
|
|
|
|
struct page *page;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = -ENOENT;
|
2010-02-01 10:02:09 +08:00
|
|
|
de = nilfs_find_entry(dir, &dentry->d_name, &page);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!de)
|
|
|
|
goto out;
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(dentry);
|
2009-04-07 10:01:34 +08:00
|
|
|
err = -EIO;
|
|
|
|
if (le64_to_cpu(de->inode) != inode->i_ino)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (!inode->i_nlink) {
|
2016-08-03 05:05:14 +08:00
|
|
|
nilfs_msg(inode->i_sb, KERN_WARNING,
|
|
|
|
"deleting nonexistent file (ino=%lu), %d",
|
|
|
|
inode->i_ino, inode->i_nlink);
|
2011-10-28 20:13:29 +08:00
|
|
|
set_nlink(inode, 1);
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
err = nilfs_delete_entry(de, page);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
inode->i_ctime = dir->i_ctime;
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
err = 0;
|
|
|
|
out:
|
2009-11-27 18:41:10 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int nilfs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
|
{
|
|
|
|
struct nilfs_transaction_info ti;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = nilfs_do_unlink(dir, dentry);
|
|
|
|
|
|
|
|
if (!err) {
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(dir);
|
2015-03-18 06:25:59 +08:00
|
|
|
nilfs_mark_inode_dirty(d_inode(dentry));
|
2009-04-07 10:01:45 +08:00
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
2009-11-27 18:41:10 +08:00
|
|
|
} else
|
2009-04-07 10:01:45 +08:00
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct inode *inode = d_inode(dentry);
|
2009-04-07 10:01:34 +08:00
|
|
|
struct nilfs_transaction_info ti;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = -ENOTEMPTY;
|
|
|
|
if (nilfs_empty_dir(inode)) {
|
2009-11-27 18:41:10 +08:00
|
|
|
err = nilfs_do_unlink(dir, dentry);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!err) {
|
|
|
|
inode->i_size = 0;
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(inode);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(inode);
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(dir);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(dir);
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
}
|
2009-04-07 10:01:45 +08:00
|
|
|
if (!err)
|
|
|
|
err = nilfs_transaction_commit(dir->i_sb);
|
|
|
|
else
|
|
|
|
nilfs_transaction_abort(dir->i_sb);
|
|
|
|
|
|
|
|
return err;
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
fs: support RENAME_NOREPLACE for local filesystems
This is trivial to do:
- add flags argument to foo_rename()
- check if flags doesn't have any other than RENAME_NOREPLACE
- assign foo_rename() to .rename2 instead of .rename
Filesystems converted:
affs, bfs, exofs, ext2, hfs, hfsplus, jffs2, jfs, logfs, minix, msdos,
nilfs2, omfs, reiserfs, sysvfs, ubifs, udf, ufs, vfat.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Acked-by: Boaz Harrosh <ooo@electrozaur.com>
Acked-by: Richard Weinberger <richard@nod.at>
Acked-by: Bob Copeland <me@bobcopeland.com>
Acked-by: Jan Kara <jack@suse.cz>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Mikulas Patocka <mpatocka@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Christoph Hellwig <hch@infradead.org>
2016-09-27 17:03:57 +08:00
|
|
|
struct inode *new_dir, struct dentry *new_dentry,
|
|
|
|
unsigned int flags)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct inode *old_inode = d_inode(old_dentry);
|
|
|
|
struct inode *new_inode = d_inode(new_dentry);
|
2009-04-07 10:01:34 +08:00
|
|
|
struct page *dir_page = NULL;
|
|
|
|
struct nilfs_dir_entry *dir_de = NULL;
|
|
|
|
struct page *old_page;
|
|
|
|
struct nilfs_dir_entry *old_de;
|
|
|
|
struct nilfs_transaction_info ti;
|
|
|
|
int err;
|
|
|
|
|
fs: support RENAME_NOREPLACE for local filesystems
This is trivial to do:
- add flags argument to foo_rename()
- check if flags doesn't have any other than RENAME_NOREPLACE
- assign foo_rename() to .rename2 instead of .rename
Filesystems converted:
affs, bfs, exofs, ext2, hfs, hfsplus, jffs2, jfs, logfs, minix, msdos,
nilfs2, omfs, reiserfs, sysvfs, ubifs, udf, ufs, vfat.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Acked-by: Boaz Harrosh <ooo@electrozaur.com>
Acked-by: Richard Weinberger <richard@nod.at>
Acked-by: Bob Copeland <me@bobcopeland.com>
Acked-by: Jan Kara <jack@suse.cz>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Mikulas Patocka <mpatocka@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Christoph Hellwig <hch@infradead.org>
2016-09-27 17:03:57 +08:00
|
|
|
if (flags & ~RENAME_NOREPLACE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-04-07 10:01:34 +08:00
|
|
|
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
|
|
|
|
if (unlikely(err))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = -ENOENT;
|
2010-02-01 10:02:09 +08:00
|
|
|
old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_page);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!old_de)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (S_ISDIR(old_inode->i_mode)) {
|
|
|
|
err = -EIO;
|
|
|
|
dir_de = nilfs_dotdot(old_inode, &dir_page);
|
|
|
|
if (!dir_de)
|
|
|
|
goto out_old;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_inode) {
|
|
|
|
struct page *new_page;
|
|
|
|
struct nilfs_dir_entry *new_de;
|
|
|
|
|
|
|
|
err = -ENOTEMPTY;
|
|
|
|
if (dir_de && !nilfs_empty_dir(new_inode))
|
|
|
|
goto out_dir;
|
|
|
|
|
|
|
|
err = -ENOENT;
|
2010-02-01 10:02:09 +08:00
|
|
|
new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_page);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!new_de)
|
|
|
|
goto out_dir;
|
|
|
|
nilfs_set_link(new_dir, new_de, new_page, old_inode);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(new_dir);
|
2016-09-14 22:48:04 +08:00
|
|
|
new_inode->i_ctime = current_time(new_inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (dir_de)
|
|
|
|
drop_nlink(new_inode);
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(new_inode);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(new_inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
} else {
|
|
|
|
err = nilfs_add_link(new_dentry, old_inode);
|
2011-03-03 01:01:13 +08:00
|
|
|
if (err)
|
2009-04-07 10:01:34 +08:00
|
|
|
goto out_dir;
|
2009-11-27 18:41:08 +08:00
|
|
|
if (dir_de) {
|
|
|
|
inc_nlink(new_dir);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(new_dir);
|
2009-11-27 18:41:08 +08:00
|
|
|
}
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Like most other Unix systems, set the ctime for inodes on a
|
|
|
|
* rename.
|
|
|
|
*/
|
2016-09-14 22:48:04 +08:00
|
|
|
old_inode->i_ctime = current_time(old_inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
nilfs_delete_entry(old_de, old_page);
|
|
|
|
|
|
|
|
if (dir_de) {
|
|
|
|
nilfs_set_link(old_inode, dir_de, dir_page, new_dir);
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(old_dir);
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(old_dir);
|
|
|
|
nilfs_mark_inode_dirty(old_inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
2009-04-07 10:01:45 +08:00
|
|
|
err = nilfs_transaction_commit(old_dir->i_sb);
|
2009-04-07 10:01:34 +08:00
|
|
|
return err;
|
|
|
|
|
|
|
|
out_dir:
|
|
|
|
if (dir_de) {
|
|
|
|
kunmap(dir_page);
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
put_page(dir_page);
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
|
|
|
out_old:
|
|
|
|
kunmap(old_page);
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
put_page(old_page);
|
2009-04-07 10:01:34 +08:00
|
|
|
out:
|
2009-04-07 10:01:45 +08:00
|
|
|
nilfs_transaction_abort(old_dir->i_sb);
|
2009-04-07 10:01:34 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-08-26 23:23:02 +08:00
|
|
|
/*
|
|
|
|
* Export operations
|
|
|
|
*/
|
|
|
|
static struct dentry *nilfs_get_parent(struct dentry *child)
|
|
|
|
{
|
|
|
|
unsigned long ino;
|
|
|
|
struct inode *inode;
|
2012-05-11 04:14:12 +08:00
|
|
|
struct qstr dotdot = QSTR_INIT("..", 2);
|
2010-08-26 23:23:02 +08:00
|
|
|
struct nilfs_root *root;
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
ino = nilfs_inode_by_name(d_inode(child), &dotdot);
|
2010-08-26 23:23:02 +08:00
|
|
|
if (!ino)
|
|
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
root = NILFS_I(d_inode(child))->i_root;
|
2010-08-26 23:23:02 +08:00
|
|
|
|
2016-04-10 13:33:30 +08:00
|
|
|
inode = nilfs_iget(child->d_sb, root, ino);
|
2010-08-26 23:23:02 +08:00
|
|
|
if (IS_ERR(inode))
|
|
|
|
return ERR_CAST(inode);
|
|
|
|
|
|
|
|
return d_obtain_alias(inode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno,
|
|
|
|
u64 ino, u32 gen)
|
|
|
|
{
|
|
|
|
struct nilfs_root *root;
|
|
|
|
struct inode *inode;
|
|
|
|
|
|
|
|
if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO)
|
|
|
|
return ERR_PTR(-ESTALE);
|
|
|
|
|
2011-03-09 10:05:08 +08:00
|
|
|
root = nilfs_lookup_root(sb->s_fs_info, cno);
|
2010-08-26 23:23:02 +08:00
|
|
|
if (!root)
|
|
|
|
return ERR_PTR(-ESTALE);
|
|
|
|
|
|
|
|
inode = nilfs_iget(sb, root, ino);
|
|
|
|
nilfs_put_root(root);
|
|
|
|
|
|
|
|
if (IS_ERR(inode))
|
|
|
|
return ERR_CAST(inode);
|
|
|
|
if (gen && inode->i_generation != gen) {
|
|
|
|
iput(inode);
|
|
|
|
return ERR_PTR(-ESTALE);
|
|
|
|
}
|
|
|
|
return d_obtain_alias(inode);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
|
|
|
|
int fh_len, int fh_type)
|
|
|
|
{
|
|
|
|
struct nilfs_fid *fid = (struct nilfs_fid *)fh;
|
|
|
|
|
2015-06-26 06:03:45 +08:00
|
|
|
if (fh_len < NILFS_FID_SIZE_NON_CONNECTABLE ||
|
2010-08-26 23:23:02 +08:00
|
|
|
(fh_type != FILEID_NILFS_WITH_PARENT &&
|
|
|
|
fh_type != FILEID_NILFS_WITHOUT_PARENT))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh,
|
|
|
|
int fh_len, int fh_type)
|
|
|
|
{
|
|
|
|
struct nilfs_fid *fid = (struct nilfs_fid *)fh;
|
|
|
|
|
2015-06-26 06:03:45 +08:00
|
|
|
if (fh_len < NILFS_FID_SIZE_CONNECTABLE ||
|
2010-08-26 23:23:02 +08:00
|
|
|
fh_type != FILEID_NILFS_WITH_PARENT)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen);
|
|
|
|
}
|
|
|
|
|
2012-04-03 02:34:06 +08:00
|
|
|
static int nilfs_encode_fh(struct inode *inode, __u32 *fh, int *lenp,
|
|
|
|
struct inode *parent)
|
2010-08-26 23:23:02 +08:00
|
|
|
{
|
|
|
|
struct nilfs_fid *fid = (struct nilfs_fid *)fh;
|
|
|
|
struct nilfs_root *root = NILFS_I(inode)->i_root;
|
|
|
|
int type;
|
|
|
|
|
2012-04-03 02:34:06 +08:00
|
|
|
if (parent && *lenp < NILFS_FID_SIZE_CONNECTABLE) {
|
|
|
|
*lenp = NILFS_FID_SIZE_CONNECTABLE;
|
2013-02-17 14:48:11 +08:00
|
|
|
return FILEID_INVALID;
|
2012-04-03 02:34:06 +08:00
|
|
|
}
|
|
|
|
if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE) {
|
|
|
|
*lenp = NILFS_FID_SIZE_NON_CONNECTABLE;
|
2013-02-17 14:48:11 +08:00
|
|
|
return FILEID_INVALID;
|
2012-04-03 02:34:06 +08:00
|
|
|
}
|
2010-08-26 23:23:02 +08:00
|
|
|
|
|
|
|
fid->cno = root->cno;
|
|
|
|
fid->ino = inode->i_ino;
|
|
|
|
fid->gen = inode->i_generation;
|
|
|
|
|
2012-04-03 02:34:06 +08:00
|
|
|
if (parent) {
|
2010-08-26 23:23:02 +08:00
|
|
|
fid->parent_ino = parent->i_ino;
|
|
|
|
fid->parent_gen = parent->i_generation;
|
|
|
|
type = FILEID_NILFS_WITH_PARENT;
|
|
|
|
*lenp = NILFS_FID_SIZE_CONNECTABLE;
|
|
|
|
} else {
|
|
|
|
type = FILEID_NILFS_WITHOUT_PARENT;
|
|
|
|
*lenp = NILFS_FID_SIZE_NON_CONNECTABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2009-09-22 08:01:11 +08:00
|
|
|
const struct inode_operations nilfs_dir_inode_operations = {
|
2009-04-07 10:01:34 +08:00
|
|
|
.create = nilfs_create,
|
|
|
|
.lookup = nilfs_lookup,
|
|
|
|
.link = nilfs_link,
|
|
|
|
.unlink = nilfs_unlink,
|
|
|
|
.symlink = nilfs_symlink,
|
|
|
|
.mkdir = nilfs_mkdir,
|
|
|
|
.rmdir = nilfs_rmdir,
|
|
|
|
.mknod = nilfs_mknod,
|
|
|
|
.rename = nilfs_rename,
|
|
|
|
.setattr = nilfs_setattr,
|
|
|
|
.permission = nilfs_permission,
|
2010-12-26 15:38:43 +08:00
|
|
|
.fiemap = nilfs_fiemap,
|
2009-04-07 10:01:34 +08:00
|
|
|
};
|
|
|
|
|
2009-09-22 08:01:11 +08:00
|
|
|
const struct inode_operations nilfs_special_inode_operations = {
|
2009-04-07 10:01:34 +08:00
|
|
|
.setattr = nilfs_setattr,
|
|
|
|
.permission = nilfs_permission,
|
|
|
|
};
|
|
|
|
|
2009-09-22 08:01:11 +08:00
|
|
|
const struct inode_operations nilfs_symlink_inode_operations = {
|
2015-11-17 23:20:54 +08:00
|
|
|
.get_link = page_get_link,
|
2010-08-15 22:33:57 +08:00
|
|
|
.permission = nilfs_permission,
|
2009-04-07 10:01:34 +08:00
|
|
|
};
|
2010-08-26 23:23:02 +08:00
|
|
|
|
|
|
|
const struct export_operations nilfs_export_ops = {
|
|
|
|
.encode_fh = nilfs_encode_fh,
|
|
|
|
.fh_to_dentry = nilfs_fh_to_dentry,
|
|
|
|
.fh_to_parent = nilfs_fh_to_parent,
|
|
|
|
.get_parent = nilfs_get_parent,
|
|
|
|
};
|