2018-09-05 06:46:30 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2009-04-07 10:01:34 +08:00
|
|
|
/*
|
2021-11-09 10:35:01 +08:00
|
|
|
* NILFS pathname lookup operations.
|
2009-04-07 10:01:34 +08:00
|
|
|
*
|
|
|
|
* Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
|
|
|
|
*
|
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) {
|
2018-05-04 20:23:01 +08:00
|
|
|
d_instantiate_new(dentry, 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().
|
|
|
|
*/
|
2023-01-13 19:49:13 +08:00
|
|
|
static int nilfs_create(struct mnt_idmap *idmap, struct inode *dir,
|
2021-01-21 21:19:43 +08:00
|
|
|
struct dentry *dentry, umode_t mode, 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
|
2023-01-13 19:49:16 +08:00
|
|
|
nilfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
2021-01-21 21:19:43 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:14 +08:00
|
|
|
static int nilfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
2021-01-21 21:19:43 +08:00
|
|
|
struct dentry *dentry, const char *symname)
|
2009-04-07 10:01:34 +08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2023-07-06 03:01:24 +08:00
|
|
|
inode_set_ctime_current(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
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:15 +08:00
|
|
|
static int nilfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
2021-01-21 21:19:43 +08:00
|
|
|
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);
|
2018-05-04 20:23:01 +08:00
|
|
|
d_instantiate_new(dentry, 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;
|
2023-11-27 22:30:31 +08:00
|
|
|
struct folio *folio;
|
2009-04-07 10:01:45 +08:00
|
|
|
int err;
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
err = -ENOENT;
|
2023-11-27 22:30:31 +08:00
|
|
|
de = nilfs_find_entry(dir, &dentry->d_name, &folio);
|
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) {
|
2020-08-12 09:35:49 +08:00
|
|
|
nilfs_warn(inode->i_sb,
|
|
|
|
"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
|
|
|
}
|
2023-11-27 22:30:31 +08:00
|
|
|
err = nilfs_delete_entry(de, folio);
|
|
|
|
folio_release_kmap(folio, de);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2023-07-06 03:01:24 +08:00
|
|
|
inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
|
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
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:17 +08:00
|
|
|
static int nilfs_rename(struct mnt_idmap *idmap,
|
2021-01-21 21:19:43 +08:00
|
|
|
struct inode *old_dir, struct dentry *old_dentry,
|
|
|
|
struct inode *new_dir, struct dentry *new_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
|
|
|
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);
|
2023-11-27 22:30:31 +08:00
|
|
|
struct folio *dir_folio = NULL;
|
2009-04-07 10:01:34 +08:00
|
|
|
struct nilfs_dir_entry *dir_de = NULL;
|
2023-11-27 22:30:31 +08:00
|
|
|
struct folio *old_folio;
|
2009-04-07 10:01:34 +08:00
|
|
|
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;
|
2023-11-27 22:30:31 +08:00
|
|
|
old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_folio);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!old_de)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (S_ISDIR(old_inode->i_mode)) {
|
|
|
|
err = -EIO;
|
2023-11-27 22:30:31 +08:00
|
|
|
dir_de = nilfs_dotdot(old_inode, &dir_folio);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!dir_de)
|
|
|
|
goto out_old;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_inode) {
|
2023-11-27 22:30:31 +08:00
|
|
|
struct folio *new_folio;
|
2009-04-07 10:01:34 +08:00
|
|
|
struct nilfs_dir_entry *new_de;
|
|
|
|
|
|
|
|
err = -ENOTEMPTY;
|
|
|
|
if (dir_de && !nilfs_empty_dir(new_inode))
|
|
|
|
goto out_dir;
|
|
|
|
|
|
|
|
err = -ENOENT;
|
2023-11-27 22:30:31 +08:00
|
|
|
new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_folio);
|
2009-04-07 10:01:34 +08:00
|
|
|
if (!new_de)
|
|
|
|
goto out_dir;
|
2023-11-27 22:30:31 +08:00
|
|
|
nilfs_set_link(new_dir, new_de, new_folio, old_inode);
|
|
|
|
folio_release_kmap(new_folio, new_de);
|
2009-11-27 18:41:14 +08:00
|
|
|
nilfs_mark_inode_dirty(new_dir);
|
2023-07-06 03:01:24 +08:00
|
|
|
inode_set_ctime_current(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.
|
|
|
|
*/
|
2023-07-06 03:01:24 +08:00
|
|
|
inode_set_ctime_current(old_inode);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
2023-11-27 22:30:31 +08:00
|
|
|
nilfs_delete_entry(old_de, old_folio);
|
2009-04-07 10:01:34 +08:00
|
|
|
|
|
|
|
if (dir_de) {
|
2023-11-27 22:30:31 +08:00
|
|
|
nilfs_set_link(old_inode, dir_de, dir_folio, new_dir);
|
|
|
|
folio_release_kmap(dir_folio, dir_de);
|
2009-11-27 18:41:08 +08:00
|
|
|
drop_nlink(old_dir);
|
2009-04-07 10:01:34 +08:00
|
|
|
}
|
2023-11-27 22:30:31 +08:00
|
|
|
folio_release_kmap(old_folio, old_de);
|
2023-11-27 22:30:21 +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:
|
nilfs2: move page release outside of nilfs_delete_entry and nilfs_set_link
Patch series "nilfs2: Folio conversions for directory paths".
This series applies page->folio conversions to nilfs2 directory
operations. This reduces hidden compound_head() calls and also converts
deprecated kmap calls to kmap_local in the directory code.
Although nilfs2 does not yet support large folios, Matthew has done his
best here to include support for large folios, which will be needed for
devices with large block sizes.
This series corresponds to the second half of the original post [1], but
with two complementary patches inserted at the beginning and some
adjustments, to prevent a kmap_local constraint violation found during
testing with highmem mapping.
[1] https://lkml.kernel.org/r/20231106173903.1734114-1-willy@infradead.org
I have reviewed all changes and tested this for regular and small block
sizes, both on machines with and without highmem mapping. No issues
found.
This patch (of 17):
In a few directory operations, the call to nilfs_put_page() for a page
obtained using nilfs_find_entry() or nilfs_dotdot() is hidden in
nilfs_set_link() and nilfs_delete_entry(), making it difficult to track
page release and preventing change of its call position.
By moving nilfs_put_page() out of these functions, this makes the page
get/put correspondence clearer and makes it easier to swap
nilfs_put_page() calls (and kunmap calls within them) when modifying
multiple directory entries simultaneously in nilfs_rename().
Also, update comments for nilfs_set_link() and nilfs_delete_entry() to
reflect changes in their behavior.
To make nilfs_put_page() visible from namei.c, this moves its definition
to nilfs.h and replaces existing equivalents to use it, but the exposure
of that definition is temporary and will be removed on a later kmap ->
kmap_local conversion.
Link: https://lkml.kernel.org/r/20231127143036.2425-1-konishi.ryusuke@gmail.com
Link: https://lkml.kernel.org/r/20231127143036.2425-2-konishi.ryusuke@gmail.com
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-11-27 22:30:20 +08:00
|
|
|
if (dir_de)
|
2023-11-27 22:30:31 +08:00
|
|
|
folio_release_kmap(dir_folio, dir_de);
|
2009-04-07 10:01:34 +08:00
|
|
|
out_old:
|
2023-11-27 22:30:31 +08:00
|
|
|
folio_release_kmap(old_folio, old_de);
|
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 nilfs_root *root;
|
|
|
|
|
2021-04-16 07:46:50 +08:00
|
|
|
ino = nilfs_inode_by_name(d_inode(child), &dotdot_name);
|
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
|
|
|
|
2023-11-11 14:55:03 +08:00
|
|
|
return d_obtain_alias(nilfs_iget(child->d_sb, root, ino));
|
2010-08-26 23:23:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2021-04-07 20:36:44 +08:00
|
|
|
.fileattr_get = nilfs_fileattr_get,
|
|
|
|
.fileattr_set = nilfs_fileattr_set,
|
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,
|
|
|
|
};
|