Skip to content

Commit

Permalink
Merge branch 'xfs-O_TMPFILE-support' into for-next
Browse files Browse the repository at this point in the history
Conflicts:
	fs/xfs/xfs_trans_resv.c
	- fix for XFS_INODE_CLUSTER_SIZE macro removal
  • Loading branch information
dchinner committed Mar 13, 2014
2 parents 5f44e4c + ab29743 commit fe986f9
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 15 deletions.
123 changes: 117 additions & 6 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include "xfs_bmap_util.h"
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_dinode.h"
#include "xfs_filestream.h"
#include "xfs_cksum.h"
#include "xfs_trace.h"
Expand All @@ -62,6 +61,8 @@ kmem_zone_t *xfs_inode_zone;

STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);

STATIC int xfs_iunlink_remove(xfs_trans_t *, xfs_inode_t *);

/*
* helper function to extract extent size hint from inode
*/
Expand Down Expand Up @@ -1115,7 +1116,7 @@ xfs_bumplink(
{
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);

ASSERT(ip->i_d.di_nlink > 0);
ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE));
ip->i_d.di_nlink++;
inc_nlink(VFS_I(ip));
if ((ip->i_d.di_version == 1) &&
Expand Down Expand Up @@ -1165,10 +1166,7 @@ xfs_create(
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);

if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = xfs_get_projid(dp);
else
prid = XFS_PROJID_DEFAULT;
prid = xfs_get_initial_prid(dp);

/*
* Make sure that we have allocated dquot(s) on disk.
Expand Down Expand Up @@ -1332,6 +1330,113 @@ xfs_create(
return error;
}

int
xfs_create_tmpfile(
struct xfs_inode *dp,
struct dentry *dentry,
umode_t mode)
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_inode *ip = NULL;
struct xfs_trans *tp = NULL;
int error;
uint cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
prid_t prid;
struct xfs_dquot *udqp = NULL;
struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
struct xfs_trans_res *tres;
uint resblks;

if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);

prid = xfs_get_initial_prid(dp);

/*
* Make sure that we have allocated dquot(s) on disk.
*/
error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()),
xfs_kgid_to_gid(current_fsgid()), prid,
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
&udqp, &gdqp, &pdqp);
if (error)
return error;

resblks = XFS_IALLOC_SPACE_RES(mp);
tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TMPFILE);

tres = &M_RES(mp)->tr_create_tmpfile;
error = xfs_trans_reserve(tp, tres, resblks, 0);
if (error == ENOSPC) {
/* No space at all so try a "no-allocation" reservation */
resblks = 0;
error = xfs_trans_reserve(tp, tres, 0, 0);
}
if (error) {
cancel_flags = 0;
goto out_trans_cancel;
}

error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
pdqp, resblks, 1, 0);
if (error)
goto out_trans_cancel;

error = xfs_dir_ialloc(&tp, dp, mode, 1, 0,
prid, resblks > 0, &ip, NULL);
if (error) {
if (error == ENOSPC)
goto out_trans_cancel;
goto out_trans_abort;
}

if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(tp);

/*
* Attach the dquot(s) to the inodes and modify them incore.
* These ids of the inode couldn't have changed since the new
* inode has been locked ever since it was created.
*/
xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);

ip->i_d.di_nlink--;
d_tmpfile(dentry, VFS_I(ip));
error = xfs_iunlink(tp, ip);
if (error)
goto out_trans_abort;

error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto out_release_inode;

xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);

return 0;

out_trans_abort:
cancel_flags |= XFS_TRANS_ABORT;
out_trans_cancel:
xfs_trans_cancel(tp, cancel_flags);
out_release_inode:
/*
* Wait until after the current transaction is aborted to
* release the inode. This prevents recursive transactions
* and deadlocks from xfs_inactive.
*/
if (ip)
IRELE(ip);

xfs_qm_dqrele(udqp);
xfs_qm_dqrele(gdqp);
xfs_qm_dqrele(pdqp);

return error;
}

int
xfs_link(
xfs_inode_t *tdp,
Expand Down Expand Up @@ -1397,6 +1502,12 @@ xfs_link(

xfs_bmap_init(&free_list, &first_block);

if (sip->i_d.di_nlink == 0) {
error = xfs_iunlink_remove(tp, sip);
if (error)
goto abort_return;
}

error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
&first_block, &free_list, resblks);
if (error)
Expand Down
12 changes: 12 additions & 0 deletions fs/xfs/xfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "xfs_inode_buf.h"
#include "xfs_inode_fork.h"
#include "xfs_dinode.h"

/*
* Kernel only inode definitions
Expand Down Expand Up @@ -192,6 +193,15 @@ xfs_set_projid(struct xfs_inode *ip,
ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff);
}

static inline prid_t
xfs_get_initial_prid(struct xfs_inode *dp)
{
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
return xfs_get_projid(dp);

return XFS_PROJID_DEFAULT;
}

/*
* In-core inode flags.
*/
Expand Down Expand Up @@ -323,6 +333,8 @@ int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode **ipp, struct xfs_name *ci_name);
int xfs_create(struct xfs_inode *dp, struct xfs_name *name,
umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp);
int xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry,
umode_t mode);
int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode *ip);
int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
Expand Down
16 changes: 16 additions & 0 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "xfs_da_btree.h"
#include "xfs_dir2_priv.h"
#include "xfs_dinode.h"
#include "xfs_trans_space.h"

#include <linux/capability.h>
#include <linux/xattr.h>
Expand Down Expand Up @@ -1046,6 +1047,19 @@ xfs_vn_fiemap(
return 0;
}

STATIC int
xfs_vn_tmpfile(
struct inode *dir,
struct dentry *dentry,
umode_t mode)
{
int error;

error = xfs_create_tmpfile(XFS_I(dir), dentry, mode);

return -error;
}

static const struct inode_operations xfs_inode_operations = {
.get_acl = xfs_get_acl,
.set_acl = xfs_set_acl,
Expand Down Expand Up @@ -1084,6 +1098,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
.tmpfile = xfs_vn_tmpfile,
};

static const struct inode_operations xfs_dir_ci_inode_operations = {
Expand Down Expand Up @@ -1111,6 +1126,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
.removexattr = generic_removexattr,
.listxattr = xfs_vn_listxattr,
.update_time = xfs_vn_update_time,
.tmpfile = xfs_vn_tmpfile,
};

static const struct inode_operations xfs_symlink_inode_operations = {
Expand Down
4 changes: 3 additions & 1 deletion fs/xfs/xfs_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,16 @@ extern const struct xfs_buf_ops xfs_symlink_buf_ops;
#define XFS_TRANS_SB_COUNT 41
#define XFS_TRANS_CHECKPOINT 42
#define XFS_TRANS_ICREATE 43
#define XFS_TRANS_TYPE_MAX 43
#define XFS_TRANS_CREATE_TMPFILE 44
#define XFS_TRANS_TYPE_MAX 44
/* new transaction types need to be reflected in xfs_logprint(8) */

#define XFS_TRANS_TYPES \
{ XFS_TRANS_SETATTR_NOT_SIZE, "SETATTR_NOT_SIZE" }, \
{ XFS_TRANS_SETATTR_SIZE, "SETATTR_SIZE" }, \
{ XFS_TRANS_INACTIVE, "INACTIVE" }, \
{ XFS_TRANS_CREATE, "CREATE" }, \
{ XFS_TRANS_CREATE_TMPFILE, "CREATE_TMPFILE" }, \
{ XFS_TRANS_CREATE_TRUNC, "CREATE_TRUNC" }, \
{ XFS_TRANS_TRUNCATE_FILE, "TRUNCATE_FILE" }, \
{ XFS_TRANS_REMOVE, "REMOVE" }, \
Expand Down
5 changes: 1 addition & 4 deletions fs/xfs/xfs_symlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,7 @@ xfs_symlink(
return XFS_ERROR(ENAMETOOLONG);

udqp = gdqp = NULL;
if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
prid = xfs_get_projid(dp);
else
prid = XFS_PROJID_DEFAULT;
prid = xfs_get_initial_prid(dp);

/*
* Make sure that we have allocated dquot(s) on disk.
Expand Down
54 changes: 50 additions & 4 deletions fs/xfs/xfs_trans_resv.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,19 @@ xfs_calc_rename_reservation(
XFS_FSB_TO_B(mp, 1))));
}

/*
* For removing an inode from unlinked list at first, we can modify:
* the agi hash list and counters: sector size
* the on disk inode before ours in the agi hash list: inode cluster size
*/
STATIC uint
xfs_calc_iunlink_remove_reservation(
struct xfs_mount *mp)
{
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size);
}

/*
* For creating a link to an inode:
* the parent directory inode: inode size
Expand All @@ -228,6 +241,7 @@ xfs_calc_link_reservation(
struct xfs_mount *mp)
{
return XFS_DQUOT_LOGRES(mp) +
xfs_calc_iunlink_remove_reservation(mp) +
MAX((xfs_calc_inode_res(mp, 2) +
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
XFS_FSB_TO_B(mp, 1))),
Expand All @@ -236,6 +250,18 @@ xfs_calc_link_reservation(
XFS_FSB_TO_B(mp, 1))));
}

/*
* For adding an inode to unlinked list we can modify:
* the agi hash list: sector size
* the unlinked inode: inode size
*/
STATIC uint
xfs_calc_iunlink_add_reservation(xfs_mount_t *mp)
{
return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
xfs_calc_inode_res(mp, 1);
}

/*
* For removing a directory entry we can modify:
* the parent directory inode: inode size
Expand All @@ -253,10 +279,11 @@ xfs_calc_remove_reservation(
struct xfs_mount *mp)
{
return XFS_DQUOT_LOGRES(mp) +
MAX((xfs_calc_inode_res(mp, 2) +
xfs_calc_iunlink_add_reservation(mp) +
MAX((xfs_calc_inode_res(mp, 1) +
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
XFS_FSB_TO_B(mp, 1))),
(xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
(xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
XFS_FSB_TO_B(mp, 1))));
}
Expand Down Expand Up @@ -351,6 +378,20 @@ xfs_calc_create_reservation(

}

STATIC uint
xfs_calc_create_tmpfile_reservation(
struct xfs_mount *mp)
{
uint res = XFS_DQUOT_LOGRES(mp);

if (xfs_sb_version_hascrc(&mp->m_sb))
res += xfs_calc_icreate_resv_alloc(mp);
else
res += xfs_calc_create_resv_alloc(mp);

return res + xfs_calc_iunlink_add_reservation(mp);
}

/*
* Making a new directory is the same as creating a new file.
*/
Expand Down Expand Up @@ -391,9 +432,9 @@ xfs_calc_ifree_reservation(
{
return XFS_DQUOT_LOGRES(mp) +
xfs_calc_inode_res(mp, 1) +
xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size) +
xfs_calc_iunlink_remove_reservation(mp) +
xfs_calc_buf_res(1, 0) +
xfs_calc_buf_res(2 + mp->m_ialloc_blks +
mp->m_in_maxlevels, 0) +
Expand Down Expand Up @@ -736,6 +777,11 @@ xfs_trans_resv_calc(
resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;

resp->tr_create_tmpfile.tr_logres =
xfs_calc_create_tmpfile_reservation(mp);
resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT;
resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES;

resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
Expand Down
2 changes: 2 additions & 0 deletions fs/xfs/xfs_trans_resv.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct xfs_trans_resv {
struct xfs_trans_res tr_remove; /* unlink trans */
struct xfs_trans_res tr_symlink; /* symlink trans */
struct xfs_trans_res tr_create; /* create trans */
struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */
struct xfs_trans_res tr_mkdir; /* mkdir trans */
struct xfs_trans_res tr_ifree; /* inode free trans */
struct xfs_trans_res tr_ichange; /* inode update trans */
Expand Down Expand Up @@ -99,6 +100,7 @@ struct xfs_trans_resv {
#define XFS_ITRUNCATE_LOG_COUNT 2
#define XFS_INACTIVE_LOG_COUNT 2
#define XFS_CREATE_LOG_COUNT 2
#define XFS_CREATE_TMPFILE_LOG_COUNT 2
#define XFS_MKDIR_LOG_COUNT 3
#define XFS_SYMLINK_LOG_COUNT 3
#define XFS_REMOVE_LOG_COUNT 2
Expand Down

0 comments on commit fe986f9

Please sign in to comment.