You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'xfs-for-linus-v3.12-rc1' of git://oss.sgi.com/xfs/xfs
Pull xfs updates from Ben Myers: "For 3.12-rc1 there are a number of bugfixes in addition to work to ease usage of shared code between libxfs and the kernel, the rest of the work to enable project and group quotas to be used simultaneously, performance optimisations in the log and the CIL, directory entry file type support, fixes for log space reservations, some spelling/grammar cleanups, and the addition of user namespace support. - introduce readahead to log recovery - add directory entry file type support - fix a number of spelling errors in comments - introduce new Q_XGETQSTATV quotactl for project quotas - add USER_NS support - log space reservation rework - CIL optimisations - kernel/userspace libxfs rework" * tag 'xfs-for-linus-v3.12-rc1' of git://oss.sgi.com/xfs/xfs: (112 commits) xfs: XFS_MOUNT_QUOTA_ALL needed by userspace xfs: dtype changed xfs_dir2_sfe_put_ino to xfs_dir3_sfe_put_ino Fix wrong flag ASSERT in xfs_attr_shortform_getvalue xfs: finish removing IOP_* macros. xfs: inode log reservations are too small xfs: check correct status variable for xfs_inobt_get_rec() call xfs: inode buffers may not be valid during recovery readahead xfs: check LSN ordering for v5 superblocks during recovery xfs: btree block LSN escaping to disk uninitialised XFS: Assertion failed: first <= last && last < BBTOB(bp->b_length), file: fs/xfs/xfs_trans_buf.c, line: 568 xfs: fix bad dquot buffer size in log recovery readahead xfs: don't account buffer cancellation during log recovery readahead xfs: check for underflow in xfs_iformat_fork() xfs: xfs_dir3_sfe_put_ino can be static xfs: introduce object readahead to log recovery xfs: Simplify xfs_ail_min() with list_first_entry_or_null() xfs: Register hotcpu notifier after initialization xfs: add xfs sb v4 support for dirent filetype field xfs: Add write support for dirent filetype field xfs: Add read-only support for dirent filetype field ...
This commit is contained in:
@@ -620,12 +620,16 @@ spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
|
|||||||
case Opt_uid:
|
case Opt_uid:
|
||||||
if (match_int(&args[0], &option))
|
if (match_int(&args[0], &option))
|
||||||
return 0;
|
return 0;
|
||||||
root->i_uid = option;
|
root->i_uid = make_kuid(current_user_ns(), option);
|
||||||
|
if (!uid_valid(root->i_uid))
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
case Opt_gid:
|
case Opt_gid:
|
||||||
if (match_int(&args[0], &option))
|
if (match_int(&args[0], &option))
|
||||||
return 0;
|
return 0;
|
||||||
root->i_gid = option;
|
root->i_gid = make_kgid(current_user_ns(), option);
|
||||||
|
if (!gid_valid(root->i_gid))
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
case Opt_mode:
|
case Opt_mode:
|
||||||
if (match_octal(&args[0], &option))
|
if (match_octal(&args[0], &option))
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
|
|||||||
case Q_SYNC:
|
case Q_SYNC:
|
||||||
case Q_GETINFO:
|
case Q_GETINFO:
|
||||||
case Q_XGETQSTAT:
|
case Q_XGETQSTAT:
|
||||||
|
case Q_XGETQSTATV:
|
||||||
case Q_XQUOTASYNC:
|
case Q_XQUOTASYNC:
|
||||||
break;
|
break;
|
||||||
/* allow to query information for dquots we "own" */
|
/* allow to query information for dquots we "own" */
|
||||||
@@ -217,6 +218,31 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int quota_getxstatev(struct super_block *sb, void __user *addr)
|
||||||
|
{
|
||||||
|
struct fs_quota_statv fqs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!sb->s_qcop->get_xstatev)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
memset(&fqs, 0, sizeof(fqs));
|
||||||
|
if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* If this kernel doesn't support user specified version, fail */
|
||||||
|
switch (fqs.qs_version) {
|
||||||
|
case FS_QSTATV_VERSION1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ret = sb->s_qcop->get_xstatev(sb, &fqs);
|
||||||
|
if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
|
||||||
|
return -EFAULT;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
static int quota_setxquota(struct super_block *sb, int type, qid_t id,
|
||||||
void __user *addr)
|
void __user *addr)
|
||||||
{
|
{
|
||||||
@@ -293,6 +319,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
|
|||||||
return quota_setxstate(sb, cmd, addr);
|
return quota_setxstate(sb, cmd, addr);
|
||||||
case Q_XGETQSTAT:
|
case Q_XGETQSTAT:
|
||||||
return quota_getxstate(sb, addr);
|
return quota_getxstate(sb, addr);
|
||||||
|
case Q_XGETQSTATV:
|
||||||
|
return quota_getxstatev(sb, addr);
|
||||||
case Q_XSETQLIM:
|
case Q_XSETQLIM:
|
||||||
return quota_setxquota(sb, type, id, addr);
|
return quota_setxquota(sb, type, id, addr);
|
||||||
case Q_XGETQUOTA:
|
case Q_XGETQUOTA:
|
||||||
@@ -317,6 +345,7 @@ static int quotactl_cmd_write(int cmd)
|
|||||||
case Q_GETINFO:
|
case Q_GETINFO:
|
||||||
case Q_SYNC:
|
case Q_SYNC:
|
||||||
case Q_XGETQSTAT:
|
case Q_XGETQSTAT:
|
||||||
|
case Q_XGETQSTATV:
|
||||||
case Q_XGETQUOTA:
|
case Q_XGETQUOTA:
|
||||||
case Q_XQUOTASYNC:
|
case Q_XQUOTASYNC:
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+13
-7
@@ -27,9 +27,12 @@ xfs-y += xfs_trace.o
|
|||||||
|
|
||||||
# highlevel code
|
# highlevel code
|
||||||
xfs-y += xfs_aops.o \
|
xfs-y += xfs_aops.o \
|
||||||
|
xfs_attr_inactive.o \
|
||||||
|
xfs_attr_list.o \
|
||||||
xfs_bit.o \
|
xfs_bit.o \
|
||||||
|
xfs_bmap_util.o \
|
||||||
xfs_buf.o \
|
xfs_buf.o \
|
||||||
xfs_dfrag.o \
|
xfs_dir2_readdir.o \
|
||||||
xfs_discard.o \
|
xfs_discard.o \
|
||||||
xfs_error.o \
|
xfs_error.o \
|
||||||
xfs_export.o \
|
xfs_export.o \
|
||||||
@@ -44,11 +47,11 @@ xfs-y += xfs_aops.o \
|
|||||||
xfs_iops.o \
|
xfs_iops.o \
|
||||||
xfs_itable.o \
|
xfs_itable.o \
|
||||||
xfs_message.o \
|
xfs_message.o \
|
||||||
|
xfs_mount.o \
|
||||||
xfs_mru_cache.o \
|
xfs_mru_cache.o \
|
||||||
xfs_rename.o \
|
|
||||||
xfs_super.o \
|
xfs_super.o \
|
||||||
xfs_utils.o \
|
xfs_symlink.o \
|
||||||
xfs_vnodeops.o \
|
xfs_trans.o \
|
||||||
xfs_xattr.o \
|
xfs_xattr.o \
|
||||||
kmem.o \
|
kmem.o \
|
||||||
uuid.o
|
uuid.o
|
||||||
@@ -73,10 +76,13 @@ xfs-y += xfs_alloc.o \
|
|||||||
xfs_ialloc_btree.o \
|
xfs_ialloc_btree.o \
|
||||||
xfs_icreate_item.o \
|
xfs_icreate_item.o \
|
||||||
xfs_inode.o \
|
xfs_inode.o \
|
||||||
|
xfs_inode_fork.o \
|
||||||
|
xfs_inode_buf.o \
|
||||||
xfs_log_recover.o \
|
xfs_log_recover.o \
|
||||||
xfs_mount.o \
|
xfs_log_rlimit.o \
|
||||||
xfs_symlink.o \
|
xfs_sb.o \
|
||||||
xfs_trans.o
|
xfs_symlink_remote.o \
|
||||||
|
xfs_trans_resv.o
|
||||||
|
|
||||||
# low-level transaction/log code
|
# low-level transaction/log code
|
||||||
xfs-y += xfs_log.o \
|
xfs-y += xfs_log.o \
|
||||||
|
|||||||
+19
-5
@@ -16,11 +16,13 @@
|
|||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include "xfs.h"
|
#include "xfs.h"
|
||||||
|
#include "xfs_log_format.h"
|
||||||
|
#include "xfs_trans_resv.h"
|
||||||
#include "xfs_acl.h"
|
#include "xfs_acl.h"
|
||||||
#include "xfs_attr.h"
|
#include "xfs_attr.h"
|
||||||
#include "xfs_bmap_btree.h"
|
#include "xfs_bmap_btree.h"
|
||||||
#include "xfs_inode.h"
|
#include "xfs_inode.h"
|
||||||
#include "xfs_vnodeops.h"
|
#include "xfs_ag.h"
|
||||||
#include "xfs_sb.h"
|
#include "xfs_sb.h"
|
||||||
#include "xfs_mount.h"
|
#include "xfs_mount.h"
|
||||||
#include "xfs_trace.h"
|
#include "xfs_trace.h"
|
||||||
@@ -68,14 +70,15 @@ xfs_acl_from_disk(
|
|||||||
|
|
||||||
switch (acl_e->e_tag) {
|
switch (acl_e->e_tag) {
|
||||||
case ACL_USER:
|
case ACL_USER:
|
||||||
|
acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id));
|
||||||
|
break;
|
||||||
case ACL_GROUP:
|
case ACL_GROUP:
|
||||||
acl_e->e_id = be32_to_cpu(ace->ae_id);
|
acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id));
|
||||||
break;
|
break;
|
||||||
case ACL_USER_OBJ:
|
case ACL_USER_OBJ:
|
||||||
case ACL_GROUP_OBJ:
|
case ACL_GROUP_OBJ:
|
||||||
case ACL_MASK:
|
case ACL_MASK:
|
||||||
case ACL_OTHER:
|
case ACL_OTHER:
|
||||||
acl_e->e_id = ACL_UNDEFINED_ID;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
@@ -101,7 +104,18 @@ xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
|
|||||||
acl_e = &acl->a_entries[i];
|
acl_e = &acl->a_entries[i];
|
||||||
|
|
||||||
ace->ae_tag = cpu_to_be32(acl_e->e_tag);
|
ace->ae_tag = cpu_to_be32(acl_e->e_tag);
|
||||||
ace->ae_id = cpu_to_be32(acl_e->e_id);
|
switch (acl_e->e_tag) {
|
||||||
|
case ACL_USER:
|
||||||
|
ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid));
|
||||||
|
break;
|
||||||
|
case ACL_GROUP:
|
||||||
|
ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ace->ae_perm = cpu_to_be16(acl_e->e_perm);
|
ace->ae_perm = cpu_to_be16(acl_e->e_perm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -360,7 +374,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
|
if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
|
||||||
return value ? -EACCES : 0;
|
return value ? -EACCES : 0;
|
||||||
if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
|
if (!inode_owner_or_capable(inode))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
|
|||||||
@@ -226,59 +226,6 @@ typedef struct xfs_agfl {
|
|||||||
__be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */
|
__be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */
|
||||||
} xfs_agfl_t;
|
} xfs_agfl_t;
|
||||||
|
|
||||||
/*
|
|
||||||
* Per-ag incore structure, copies of information in agf and agi,
|
|
||||||
* to improve the performance of allocation group selection.
|
|
||||||
*/
|
|
||||||
#define XFS_PAGB_NUM_SLOTS 128
|
|
||||||
|
|
||||||
typedef struct xfs_perag {
|
|
||||||
struct xfs_mount *pag_mount; /* owner filesystem */
|
|
||||||
xfs_agnumber_t pag_agno; /* AG this structure belongs to */
|
|
||||||
atomic_t pag_ref; /* perag reference count */
|
|
||||||
char pagf_init; /* this agf's entry is initialized */
|
|
||||||
char pagi_init; /* this agi's entry is initialized */
|
|
||||||
char pagf_metadata; /* the agf is preferred to be metadata */
|
|
||||||
char pagi_inodeok; /* The agi is ok for inodes */
|
|
||||||
__uint8_t pagf_levels[XFS_BTNUM_AGF];
|
|
||||||
/* # of levels in bno & cnt btree */
|
|
||||||
__uint32_t pagf_flcount; /* count of blocks in freelist */
|
|
||||||
xfs_extlen_t pagf_freeblks; /* total free blocks */
|
|
||||||
xfs_extlen_t pagf_longest; /* longest free space */
|
|
||||||
__uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
|
|
||||||
xfs_agino_t pagi_freecount; /* number of free inodes */
|
|
||||||
xfs_agino_t pagi_count; /* number of allocated inodes */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inode allocation search lookup optimisation.
|
|
||||||
* If the pagino matches, the search for new inodes
|
|
||||||
* doesn't need to search the near ones again straight away
|
|
||||||
*/
|
|
||||||
xfs_agino_t pagl_pagino;
|
|
||||||
xfs_agino_t pagl_leftrec;
|
|
||||||
xfs_agino_t pagl_rightrec;
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
spinlock_t pagb_lock; /* lock for pagb_tree */
|
|
||||||
struct rb_root pagb_tree; /* ordered tree of busy extents */
|
|
||||||
|
|
||||||
atomic_t pagf_fstrms; /* # of filestreams active in this AG */
|
|
||||||
|
|
||||||
spinlock_t pag_ici_lock; /* incore inode cache lock */
|
|
||||||
struct radix_tree_root pag_ici_root; /* incore inode cache root */
|
|
||||||
int pag_ici_reclaimable; /* reclaimable inodes */
|
|
||||||
struct mutex pag_ici_reclaim_lock; /* serialisation point */
|
|
||||||
unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */
|
|
||||||
|
|
||||||
/* buffer cache index */
|
|
||||||
spinlock_t pag_buf_lock; /* lock for pag_buf_tree */
|
|
||||||
struct rb_root pag_buf_tree; /* ordered tree of active buffers */
|
|
||||||
|
|
||||||
/* for rcu-safe freeing */
|
|
||||||
struct rcu_head rcu_head;
|
|
||||||
#endif
|
|
||||||
int pagb_count; /* pagb slots in use */
|
|
||||||
} xfs_perag_t;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* tags for inode radix tree
|
* tags for inode radix tree
|
||||||
*/
|
*/
|
||||||
|
|||||||
+3
-3
@@ -878,7 +878,7 @@ xfs_alloc_ag_vextent_near(
|
|||||||
xfs_agblock_t ltnew; /* useful start bno of left side */
|
xfs_agblock_t ltnew; /* useful start bno of left side */
|
||||||
xfs_extlen_t rlen; /* length of returned extent */
|
xfs_extlen_t rlen; /* length of returned extent */
|
||||||
int forced = 0;
|
int forced = 0;
|
||||||
#if defined(DEBUG) && defined(__KERNEL__)
|
#ifdef DEBUG
|
||||||
/*
|
/*
|
||||||
* Randomly don't execute the first algorithm.
|
* Randomly don't execute the first algorithm.
|
||||||
*/
|
*/
|
||||||
@@ -938,8 +938,8 @@ restart:
|
|||||||
xfs_extlen_t blen=0;
|
xfs_extlen_t blen=0;
|
||||||
xfs_agblock_t bnew=0;
|
xfs_agblock_t bnew=0;
|
||||||
|
|
||||||
#if defined(DEBUG) && defined(__KERNEL__)
|
#ifdef DEBUG
|
||||||
if (!dofirst)
|
if (dofirst)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
|
|||||||
+18
-5
@@ -28,9 +28,9 @@
|
|||||||
#include "xfs_alloc.h"
|
#include "xfs_alloc.h"
|
||||||
#include "xfs_error.h"
|
#include "xfs_error.h"
|
||||||
#include "xfs_iomap.h"
|
#include "xfs_iomap.h"
|
||||||
#include "xfs_vnodeops.h"
|
|
||||||
#include "xfs_trace.h"
|
#include "xfs_trace.h"
|
||||||
#include "xfs_bmap.h"
|
#include "xfs_bmap.h"
|
||||||
|
#include "xfs_bmap_util.h"
|
||||||
#include <linux/aio.h>
|
#include <linux/aio.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/mpage.h>
|
#include <linux/mpage.h>
|
||||||
@@ -108,7 +108,7 @@ xfs_setfilesize_trans_alloc(
|
|||||||
|
|
||||||
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
|
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
|
||||||
|
|
||||||
error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
|
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0);
|
||||||
if (error) {
|
if (error) {
|
||||||
xfs_trans_cancel(tp, 0);
|
xfs_trans_cancel(tp, 0);
|
||||||
return error;
|
return error;
|
||||||
@@ -440,7 +440,7 @@ xfs_start_page_writeback(
|
|||||||
end_page_writeback(page);
|
end_page_writeback(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
|
static inline int xfs_bio_add_buffer(struct bio *bio, struct buffer_head *bh)
|
||||||
{
|
{
|
||||||
return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
|
return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
|
||||||
}
|
}
|
||||||
@@ -514,7 +514,7 @@ xfs_submit_ioend(
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bio_add_buffer(bio, bh) != bh->b_size) {
|
if (xfs_bio_add_buffer(bio, bh) != bh->b_size) {
|
||||||
xfs_submit_ioend_bio(wbc, ioend, bio);
|
xfs_submit_ioend_bio(wbc, ioend, bio);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
@@ -1498,13 +1498,26 @@ xfs_vm_write_failed(
|
|||||||
loff_t pos,
|
loff_t pos,
|
||||||
unsigned len)
|
unsigned len)
|
||||||
{
|
{
|
||||||
loff_t block_offset = pos & PAGE_MASK;
|
loff_t block_offset;
|
||||||
loff_t block_start;
|
loff_t block_start;
|
||||||
loff_t block_end;
|
loff_t block_end;
|
||||||
loff_t from = pos & (PAGE_CACHE_SIZE - 1);
|
loff_t from = pos & (PAGE_CACHE_SIZE - 1);
|
||||||
loff_t to = from + len;
|
loff_t to = from + len;
|
||||||
struct buffer_head *bh, *head;
|
struct buffer_head *bh, *head;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The request pos offset might be 32 or 64 bit, this is all fine
|
||||||
|
* on 64-bit platform. However, for 64-bit pos request on 32-bit
|
||||||
|
* platform, the high 32-bit will be masked off if we evaluate the
|
||||||
|
* block_offset via (pos & PAGE_MASK) because the PAGE_MASK is
|
||||||
|
* 0xfffff000 as an unsigned long, hence the result is incorrect
|
||||||
|
* which could cause the following ASSERT failed in most cases.
|
||||||
|
* In order to avoid this, we can evaluate the block_offset of the
|
||||||
|
* start of the page by using shifts rather than masks the mismatch
|
||||||
|
* problem.
|
||||||
|
*/
|
||||||
|
block_offset = (pos >> PAGE_CACHE_SHIFT) << PAGE_CACHE_SHIFT;
|
||||||
|
|
||||||
ASSERT(block_offset + from == pos);
|
ASSERT(block_offset + from == pos);
|
||||||
|
|
||||||
head = page_buffers(page);
|
head = page_buffers(page);
|
||||||
|
|||||||
+21
-406
File diff suppressed because it is too large
Load Diff
@@ -141,5 +141,14 @@ typedef struct xfs_attr_list_context {
|
|||||||
*/
|
*/
|
||||||
int xfs_attr_inactive(struct xfs_inode *dp);
|
int xfs_attr_inactive(struct xfs_inode *dp);
|
||||||
int xfs_attr_list_int(struct xfs_attr_list_context *);
|
int xfs_attr_list_int(struct xfs_attr_list_context *);
|
||||||
|
int xfs_inode_hasattr(struct xfs_inode *ip);
|
||||||
|
int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
|
||||||
|
unsigned char *value, int *valuelenp, int flags);
|
||||||
|
int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
|
||||||
|
unsigned char *value, int valuelen, int flags);
|
||||||
|
int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
|
||||||
|
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
|
||||||
|
int flags, struct attrlist_cursor_kern *cursor);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __XFS_ATTR_H__ */
|
#endif /* __XFS_ATTR_H__ */
|
||||||
|
|||||||
@@ -0,0 +1,453 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
|
||||||
|
* Copyright (c) 2013 Red Hat, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it would 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include "xfs.h"
|
||||||
|
#include "xfs_fs.h"
|
||||||
|
#include "xfs_format.h"
|
||||||
|
#include "xfs_bit.h"
|
||||||
|
#include "xfs_log.h"
|
||||||
|
#include "xfs_trans.h"
|
||||||
|
#include "xfs_sb.h"
|
||||||
|
#include "xfs_ag.h"
|
||||||
|
#include "xfs_mount.h"
|
||||||
|
#include "xfs_da_btree.h"
|
||||||
|
#include "xfs_bmap_btree.h"
|
||||||
|
#include "xfs_alloc_btree.h"
|
||||||
|
#include "xfs_ialloc_btree.h"
|
||||||
|
#include "xfs_alloc.h"
|
||||||
|
#include "xfs_btree.h"
|
||||||
|
#include "xfs_attr_remote.h"
|
||||||
|
#include "xfs_dinode.h"
|
||||||
|
#include "xfs_inode.h"
|
||||||
|
#include "xfs_inode_item.h"
|
||||||
|
#include "xfs_bmap.h"
|
||||||
|
#include "xfs_attr.h"
|
||||||
|
#include "xfs_attr_leaf.h"
|
||||||
|
#include "xfs_error.h"
|
||||||
|
#include "xfs_quota.h"
|
||||||
|
#include "xfs_trace.h"
|
||||||
|
#include "xfs_trans_priv.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look at all the extents for this logical region,
|
||||||
|
* invalidate any buffers that are incore/in transactions.
|
||||||
|
*/
|
||||||
|
STATIC int
|
||||||
|
xfs_attr3_leaf_freextent(
|
||||||
|
struct xfs_trans **trans,
|
||||||
|
struct xfs_inode *dp,
|
||||||
|
xfs_dablk_t blkno,
|
||||||
|
int blkcnt)
|
||||||
|
{
|
||||||
|
struct xfs_bmbt_irec map;
|
||||||
|
struct xfs_buf *bp;
|
||||||
|
xfs_dablk_t tblkno;
|
||||||
|
xfs_daddr_t dblkno;
|
||||||
|
int tblkcnt;
|
||||||
|
int dblkcnt;
|
||||||
|
int nmap;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Roll through the "value", invalidating the attribute value's
|
||||||
|
* blocks.
|
||||||
|
*/
|
||||||
|
tblkno = blkno;
|
||||||
|
tblkcnt = blkcnt;
|
||||||
|
while (tblkcnt > 0) {
|
||||||
|
/*
|
||||||
|
* Try to remember where we decided to put the value.
|
||||||
|
*/
|
||||||
|
nmap = 1;
|
||||||
|
error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt,
|
||||||
|
&map, &nmap, XFS_BMAPI_ATTRFORK);
|
||||||
|
if (error) {
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
ASSERT(nmap == 1);
|
||||||
|
ASSERT(map.br_startblock != DELAYSTARTBLOCK);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's a hole, these are already unmapped
|
||||||
|
* so there's nothing to invalidate.
|
||||||
|
*/
|
||||||
|
if (map.br_startblock != HOLESTARTBLOCK) {
|
||||||
|
|
||||||
|
dblkno = XFS_FSB_TO_DADDR(dp->i_mount,
|
||||||
|
map.br_startblock);
|
||||||
|
dblkcnt = XFS_FSB_TO_BB(dp->i_mount,
|
||||||
|
map.br_blockcount);
|
||||||
|
bp = xfs_trans_get_buf(*trans,
|
||||||
|
dp->i_mount->m_ddev_targp,
|
||||||
|
dblkno, dblkcnt, 0);
|
||||||
|
if (!bp)
|
||||||
|
return ENOMEM;
|
||||||
|
xfs_trans_binval(*trans, bp);
|
||||||
|
/*
|
||||||
|
* Roll to next transaction.
|
||||||
|
*/
|
||||||
|
error = xfs_trans_roll(trans, dp);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
tblkno += map.br_blockcount;
|
||||||
|
tblkcnt -= map.br_blockcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate all of the "remote" value regions pointed to by a particular
|
||||||
|
* leaf block.
|
||||||
|
* Note that we must release the lock on the buffer so that we are not
|
||||||
|
* caught holding something that the logging code wants to flush to disk.
|
||||||
|
*/
|
||||||
|
STATIC int
|
||||||
|
xfs_attr3_leaf_inactive(
|
||||||
|
struct xfs_trans **trans,
|
||||||
|
struct xfs_inode *dp,
|
||||||
|
struct xfs_buf *bp)
|
||||||
|
{
|
||||||
|
struct xfs_attr_leafblock *leaf;
|
||||||
|
struct xfs_attr3_icleaf_hdr ichdr;
|
||||||
|
struct xfs_attr_leaf_entry *entry;
|
||||||
|
struct xfs_attr_leaf_name_remote *name_rmt;
|
||||||
|
struct xfs_attr_inactive_list *list;
|
||||||
|
struct xfs_attr_inactive_list *lp;
|
||||||
|
int error;
|
||||||
|
int count;
|
||||||
|
int size;
|
||||||
|
int tmp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
leaf = bp->b_addr;
|
||||||
|
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count the number of "remote" value extents.
|
||||||
|
*/
|
||||||
|
count = 0;
|
||||||
|
entry = xfs_attr3_leaf_entryp(leaf);
|
||||||
|
for (i = 0; i < ichdr.count; entry++, i++) {
|
||||||
|
if (be16_to_cpu(entry->nameidx) &&
|
||||||
|
((entry->flags & XFS_ATTR_LOCAL) == 0)) {
|
||||||
|
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
|
||||||
|
if (name_rmt->valueblk)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there are no "remote" values, we're done.
|
||||||
|
*/
|
||||||
|
if (count == 0) {
|
||||||
|
xfs_trans_brelse(*trans, bp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate storage for a list of all the "remote" value extents.
|
||||||
|
*/
|
||||||
|
size = count * sizeof(xfs_attr_inactive_list_t);
|
||||||
|
list = kmem_alloc(size, KM_SLEEP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Identify each of the "remote" value extents.
|
||||||
|
*/
|
||||||
|
lp = list;
|
||||||
|
entry = xfs_attr3_leaf_entryp(leaf);
|
||||||
|
for (i = 0; i < ichdr.count; entry++, i++) {
|
||||||
|
if (be16_to_cpu(entry->nameidx) &&
|
||||||
|
((entry->flags & XFS_ATTR_LOCAL) == 0)) {
|
||||||
|
name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
|
||||||
|
if (name_rmt->valueblk) {
|
||||||
|
lp->valueblk = be32_to_cpu(name_rmt->valueblk);
|
||||||
|
lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount,
|
||||||
|
be32_to_cpu(name_rmt->valuelen));
|
||||||
|
lp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xfs_trans_brelse(*trans, bp); /* unlock for trans. in freextent() */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate each of the "remote" value extents.
|
||||||
|
*/
|
||||||
|
error = 0;
|
||||||
|
for (lp = list, i = 0; i < count; i++, lp++) {
|
||||||
|
tmp = xfs_attr3_leaf_freextent(trans, dp,
|
||||||
|
lp->valueblk, lp->valuelen);
|
||||||
|
|
||||||
|
if (error == 0)
|
||||||
|
error = tmp; /* save only the 1st errno */
|
||||||
|
}
|
||||||
|
|
||||||
|
kmem_free(list);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recurse (gasp!) through the attribute nodes until we find leaves.
|
||||||
|
* We're doing a depth-first traversal in order to invalidate everything.
|
||||||
|
*/
|
||||||
|
STATIC int
|
||||||
|
xfs_attr3_node_inactive(
|
||||||
|
struct xfs_trans **trans,
|
||||||
|
struct xfs_inode *dp,
|
||||||
|
struct xfs_buf *bp,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
xfs_da_blkinfo_t *info;
|
||||||
|
xfs_da_intnode_t *node;
|
||||||
|
xfs_dablk_t child_fsb;
|
||||||
|
xfs_daddr_t parent_blkno, child_blkno;
|
||||||
|
int error, i;
|
||||||
|
struct xfs_buf *child_bp;
|
||||||
|
struct xfs_da_node_entry *btree;
|
||||||
|
struct xfs_da3_icnode_hdr ichdr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since this code is recursive (gasp!) we must protect ourselves.
|
||||||
|
*/
|
||||||
|
if (level > XFS_DA_NODE_MAXDEPTH) {
|
||||||
|
xfs_trans_brelse(*trans, bp); /* no locks for later trans */
|
||||||
|
return XFS_ERROR(EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = bp->b_addr;
|
||||||
|
xfs_da3_node_hdr_from_disk(&ichdr, node);
|
||||||
|
parent_blkno = bp->b_bn;
|
||||||
|
if (!ichdr.count) {
|
||||||
|
xfs_trans_brelse(*trans, bp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
btree = xfs_da3_node_tree_p(node);
|
||||||
|
child_fsb = be32_to_cpu(btree[0].before);
|
||||||
|
xfs_trans_brelse(*trans, bp); /* no locks for later trans */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is the node level just above the leaves, simply loop
|
||||||
|
* over the leaves removing all of them. If this is higher up
|
||||||
|
* in the tree, recurse downward.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ichdr.count; i++) {
|
||||||
|
/*
|
||||||
|
* Read the subsidiary block to see what we have to work with.
|
||||||
|
* Don't do this in a transaction. This is a depth-first
|
||||||
|
* traversal of the tree so we may deal with many blocks
|
||||||
|
* before we come back to this one.
|
||||||
|
*/
|
||||||
|
error = xfs_da3_node_read(*trans, dp, child_fsb, -2, &child_bp,
|
||||||
|
XFS_ATTR_FORK);
|
||||||
|
if (error)
|
||||||
|
return(error);
|
||||||
|
if (child_bp) {
|
||||||
|
/* save for re-read later */
|
||||||
|
child_blkno = XFS_BUF_ADDR(child_bp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate the subtree, however we have to.
|
||||||
|
*/
|
||||||
|
info = child_bp->b_addr;
|
||||||
|
switch (info->magic) {
|
||||||
|
case cpu_to_be16(XFS_DA_NODE_MAGIC):
|
||||||
|
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
|
||||||
|
error = xfs_attr3_node_inactive(trans, dp,
|
||||||
|
child_bp, level + 1);
|
||||||
|
break;
|
||||||
|
case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
|
||||||
|
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
|
||||||
|
error = xfs_attr3_leaf_inactive(trans, dp,
|
||||||
|
child_bp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = XFS_ERROR(EIO);
|
||||||
|
xfs_trans_brelse(*trans, child_bp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the subsidiary block from the cache
|
||||||
|
* and from the log.
|
||||||
|
*/
|
||||||
|
error = xfs_da_get_buf(*trans, dp, 0, child_blkno,
|
||||||
|
&child_bp, XFS_ATTR_FORK);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
xfs_trans_binval(*trans, child_bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're not done, re-read the parent to get the next
|
||||||
|
* child block number.
|
||||||
|
*/
|
||||||
|
if (i + 1 < ichdr.count) {
|
||||||
|
error = xfs_da3_node_read(*trans, dp, 0, parent_blkno,
|
||||||
|
&bp, XFS_ATTR_FORK);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
child_fsb = be32_to_cpu(btree[i + 1].before);
|
||||||
|
xfs_trans_brelse(*trans, bp);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Atomically commit the whole invalidate stuff.
|
||||||
|
*/
|
||||||
|
error = xfs_trans_roll(trans, dp);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indiscriminately delete the entire attribute fork
|
||||||
|
*
|
||||||
|
* Recurse (gasp!) through the attribute nodes until we find leaves.
|
||||||
|
* We're doing a depth-first traversal in order to invalidate everything.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xfs_attr3_root_inactive(
|
||||||
|
struct xfs_trans **trans,
|
||||||
|
struct xfs_inode *dp)
|
||||||
|
{
|
||||||
|
struct xfs_da_blkinfo *info;
|
||||||
|
struct xfs_buf *bp;
|
||||||
|
xfs_daddr_t blkno;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read block 0 to see what we have to work with.
|
||||||
|
* We only get here if we have extents, since we remove
|
||||||
|
* the extents in reverse order the extent containing
|
||||||
|
* block 0 must still be there.
|
||||||
|
*/
|
||||||
|
error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
blkno = bp->b_bn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate the tree, even if the "tree" is only a single leaf block.
|
||||||
|
* This is a depth-first traversal!
|
||||||
|
*/
|
||||||
|
info = bp->b_addr;
|
||||||
|
switch (info->magic) {
|
||||||
|
case cpu_to_be16(XFS_DA_NODE_MAGIC):
|
||||||
|
case cpu_to_be16(XFS_DA3_NODE_MAGIC):
|
||||||
|
error = xfs_attr3_node_inactive(trans, dp, bp, 1);
|
||||||
|
break;
|
||||||
|
case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
|
||||||
|
case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
|
||||||
|
error = xfs_attr3_leaf_inactive(trans, dp, bp);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = XFS_ERROR(EIO);
|
||||||
|
xfs_trans_brelse(*trans, bp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Invalidate the incore copy of the root block.
|
||||||
|
*/
|
||||||
|
error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
xfs_trans_binval(*trans, bp); /* remove from cache */
|
||||||
|
/*
|
||||||
|
* Commit the invalidate and start the next transaction.
|
||||||
|
*/
|
||||||
|
error = xfs_trans_roll(trans, dp);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfs_attr_inactive(xfs_inode_t *dp)
|
||||||
|
{
|
||||||
|
xfs_trans_t *trans;
|
||||||
|
xfs_mount_t *mp;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
mp = dp->i_mount;
|
||||||
|
ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
|
||||||
|
|
||||||
|
xfs_ilock(dp, XFS_ILOCK_SHARED);
|
||||||
|
if (!xfs_inode_hasattr(dp) ||
|
||||||
|
dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||||
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start our first transaction of the day.
|
||||||
|
*
|
||||||
|
* All future transactions during this code must be "chained" off
|
||||||
|
* this one via the trans_dup() call. All transactions will contain
|
||||||
|
* the inode, and the inode will always be marked with trans_ihold().
|
||||||
|
* Since the inode will be locked in all transactions, we must log
|
||||||
|
* the inode in every transaction to let it float upward through
|
||||||
|
* the log.
|
||||||
|
*/
|
||||||
|
trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
|
||||||
|
error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0);
|
||||||
|
if (error) {
|
||||||
|
xfs_trans_cancel(trans, 0);
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
|
xfs_ilock(dp, XFS_ILOCK_EXCL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No need to make quota reservations here. We expect to release some
|
||||||
|
* blocks, not allocate, in the common case.
|
||||||
|
*/
|
||||||
|
xfs_trans_ijoin(trans, dp, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decide on what work routines to call based on the inode size.
|
||||||
|
*/
|
||||||
|
if (!xfs_inode_hasattr(dp) ||
|
||||||
|
dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
||||||
|
error = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
error = xfs_attr3_root_inactive(&trans, dp);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
|
||||||
|
xfs_iunlock(dp, XFS_ILOCK_EXCL);
|
||||||
|
|
||||||
|
return(error);
|
||||||
|
|
||||||
|
out:
|
||||||
|
xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
|
||||||
|
xfs_iunlock(dp, XFS_ILOCK_EXCL);
|
||||||
|
return(error);
|
||||||
|
}
|
||||||
+2
-655
File diff suppressed because it is too large
Load Diff
@@ -333,6 +333,8 @@ int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
|
|||||||
struct xfs_buf **bpp);
|
struct xfs_buf **bpp);
|
||||||
void xfs_attr3_leaf_hdr_from_disk(struct xfs_attr3_icleaf_hdr *to,
|
void xfs_attr3_leaf_hdr_from_disk(struct xfs_attr3_icleaf_hdr *to,
|
||||||
struct xfs_attr_leafblock *from);
|
struct xfs_attr_leafblock *from);
|
||||||
|
void xfs_attr3_leaf_hdr_to_disk(struct xfs_attr_leafblock *to,
|
||||||
|
struct xfs_attr3_icleaf_hdr *from);
|
||||||
|
|
||||||
extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops;
|
extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
|||||||
#include "xfs_bit.h"
|
#include "xfs_bit.h"
|
||||||
#include "xfs_log.h"
|
#include "xfs_log.h"
|
||||||
#include "xfs_trans.h"
|
#include "xfs_trans.h"
|
||||||
|
#include "xfs_trans_priv.h"
|
||||||
#include "xfs_sb.h"
|
#include "xfs_sb.h"
|
||||||
#include "xfs_ag.h"
|
#include "xfs_ag.h"
|
||||||
#include "xfs_mount.h"
|
#include "xfs_mount.h"
|
||||||
@@ -33,6 +34,7 @@
|
|||||||
#include "xfs_alloc.h"
|
#include "xfs_alloc.h"
|
||||||
#include "xfs_inode_item.h"
|
#include "xfs_inode_item.h"
|
||||||
#include "xfs_bmap.h"
|
#include "xfs_bmap.h"
|
||||||
|
#include "xfs_bmap_util.h"
|
||||||
#include "xfs_attr.h"
|
#include "xfs_attr.h"
|
||||||
#include "xfs_attr_leaf.h"
|
#include "xfs_attr_leaf.h"
|
||||||
#include "xfs_attr_remote.h"
|
#include "xfs_attr_remote.h"
|
||||||
@@ -237,7 +239,7 @@ xfs_attr_rmtval_copyout(
|
|||||||
xfs_ino_t ino,
|
xfs_ino_t ino,
|
||||||
int *offset,
|
int *offset,
|
||||||
int *valuelen,
|
int *valuelen,
|
||||||
char **dst)
|
__uint8_t **dst)
|
||||||
{
|
{
|
||||||
char *src = bp->b_addr;
|
char *src = bp->b_addr;
|
||||||
xfs_daddr_t bno = bp->b_bn;
|
xfs_daddr_t bno = bp->b_bn;
|
||||||
@@ -249,7 +251,7 @@ xfs_attr_rmtval_copyout(
|
|||||||
int hdr_size = 0;
|
int hdr_size = 0;
|
||||||
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
|
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
|
||||||
|
|
||||||
byte_cnt = min_t(int, *valuelen, byte_cnt);
|
byte_cnt = min(*valuelen, byte_cnt);
|
||||||
|
|
||||||
if (xfs_sb_version_hascrc(&mp->m_sb)) {
|
if (xfs_sb_version_hascrc(&mp->m_sb)) {
|
||||||
if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset,
|
if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset,
|
||||||
@@ -284,7 +286,7 @@ xfs_attr_rmtval_copyin(
|
|||||||
xfs_ino_t ino,
|
xfs_ino_t ino,
|
||||||
int *offset,
|
int *offset,
|
||||||
int *valuelen,
|
int *valuelen,
|
||||||
char **src)
|
__uint8_t **src)
|
||||||
{
|
{
|
||||||
char *dst = bp->b_addr;
|
char *dst = bp->b_addr;
|
||||||
xfs_daddr_t bno = bp->b_bn;
|
xfs_daddr_t bno = bp->b_bn;
|
||||||
@@ -337,7 +339,7 @@ xfs_attr_rmtval_get(
|
|||||||
struct xfs_mount *mp = args->dp->i_mount;
|
struct xfs_mount *mp = args->dp->i_mount;
|
||||||
struct xfs_buf *bp;
|
struct xfs_buf *bp;
|
||||||
xfs_dablk_t lblkno = args->rmtblkno;
|
xfs_dablk_t lblkno = args->rmtblkno;
|
||||||
char *dst = args->value;
|
__uint8_t *dst = args->value;
|
||||||
int valuelen = args->valuelen;
|
int valuelen = args->valuelen;
|
||||||
int nmap;
|
int nmap;
|
||||||
int error;
|
int error;
|
||||||
@@ -401,7 +403,7 @@ xfs_attr_rmtval_set(
|
|||||||
struct xfs_bmbt_irec map;
|
struct xfs_bmbt_irec map;
|
||||||
xfs_dablk_t lblkno;
|
xfs_dablk_t lblkno;
|
||||||
xfs_fileoff_t lfileoff = 0;
|
xfs_fileoff_t lfileoff = 0;
|
||||||
char *src = args->value;
|
__uint8_t *src = args->value;
|
||||||
int blkcnt;
|
int blkcnt;
|
||||||
int valuelen;
|
int valuelen;
|
||||||
int nmap;
|
int nmap;
|
||||||
@@ -543,11 +545,6 @@ xfs_attr_rmtval_remove(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Roll through the "value", invalidating the attribute value's blocks.
|
* Roll through the "value", invalidating the attribute value's blocks.
|
||||||
* Note that args->rmtblkcnt is the minimum number of data blocks we'll
|
|
||||||
* see for a CRC enabled remote attribute. Each extent will have a
|
|
||||||
* header, and so we may have more blocks than we realise here. If we
|
|
||||||
* fail to map the blocks correctly, we'll have problems with the buffer
|
|
||||||
* lookups.
|
|
||||||
*/
|
*/
|
||||||
lblkno = args->rmtblkno;
|
lblkno = args->rmtblkno;
|
||||||
blkcnt = args->rmtblkcnt;
|
blkcnt = args->rmtblkcnt;
|
||||||
@@ -628,4 +625,3 @@ xfs_attr_rmtval_remove(
|
|||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-806
File diff suppressed because it is too large
Load Diff
+1
-55
@@ -107,41 +107,6 @@ static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
|
|||||||
(flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK);
|
(flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Argument structure for xfs_bmap_alloc.
|
|
||||||
*/
|
|
||||||
typedef struct xfs_bmalloca {
|
|
||||||
xfs_fsblock_t *firstblock; /* i/o first block allocated */
|
|
||||||
struct xfs_bmap_free *flist; /* bmap freelist */
|
|
||||||
struct xfs_trans *tp; /* transaction pointer */
|
|
||||||
struct xfs_inode *ip; /* incore inode pointer */
|
|
||||||
struct xfs_bmbt_irec prev; /* extent before the new one */
|
|
||||||
struct xfs_bmbt_irec got; /* extent after, or delayed */
|
|
||||||
|
|
||||||
xfs_fileoff_t offset; /* offset in file filling in */
|
|
||||||
xfs_extlen_t length; /* i/o length asked/allocated */
|
|
||||||
xfs_fsblock_t blkno; /* starting block of new extent */
|
|
||||||
|
|
||||||
struct xfs_btree_cur *cur; /* btree cursor */
|
|
||||||
xfs_extnum_t idx; /* current extent index */
|
|
||||||
int nallocs;/* number of extents alloc'd */
|
|
||||||
int logflags;/* flags for transaction logging */
|
|
||||||
|
|
||||||
xfs_extlen_t total; /* total blocks needed for xaction */
|
|
||||||
xfs_extlen_t minlen; /* minimum allocation size (blocks) */
|
|
||||||
xfs_extlen_t minleft; /* amount must be left after alloc */
|
|
||||||
char eof; /* set if allocating past last extent */
|
|
||||||
char wasdel; /* replacing a delayed allocation */
|
|
||||||
char userdata;/* set if is user data */
|
|
||||||
char aeof; /* allocated space at eof */
|
|
||||||
char conv; /* overwriting unwritten extents */
|
|
||||||
char stack_switch;
|
|
||||||
int flags;
|
|
||||||
struct completion *done;
|
|
||||||
struct work_struct work;
|
|
||||||
int result;
|
|
||||||
} xfs_bmalloca_t;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags for xfs_bmap_add_extent*.
|
* Flags for xfs_bmap_add_extent*.
|
||||||
*/
|
*/
|
||||||
@@ -162,7 +127,7 @@ typedef struct xfs_bmalloca {
|
|||||||
{ BMAP_RIGHT_FILLING, "RF" }, \
|
{ BMAP_RIGHT_FILLING, "RF" }, \
|
||||||
{ BMAP_ATTRFORK, "ATTR" }
|
{ BMAP_ATTRFORK, "ATTR" }
|
||||||
|
|
||||||
#if defined(__KERNEL) && defined(DEBUG)
|
#ifdef DEBUG
|
||||||
void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
|
void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
|
||||||
int whichfork, unsigned long caller_ip);
|
int whichfork, unsigned long caller_ip);
|
||||||
#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \
|
#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \
|
||||||
@@ -205,23 +170,4 @@ int xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
|
|||||||
xfs_extnum_t num);
|
xfs_extnum_t num);
|
||||||
uint xfs_default_attroffset(struct xfs_inode *ip);
|
uint xfs_default_attroffset(struct xfs_inode *ip);
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
/* bmap to userspace formatter - copy to user & advance pointer */
|
|
||||||
typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
|
|
||||||
|
|
||||||
int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
|
|
||||||
int *committed);
|
|
||||||
int xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
|
|
||||||
xfs_bmap_format_t formatter, void *arg);
|
|
||||||
int xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
|
|
||||||
int whichfork, int *eof);
|
|
||||||
int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
|
|
||||||
int whichfork, int *count);
|
|
||||||
int xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
|
|
||||||
xfs_fileoff_t start_fsb, xfs_fileoff_t length);
|
|
||||||
|
|
||||||
xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
|
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
#endif /* __XFS_BMAP_H__ */
|
#endif /* __XFS_BMAP_H__ */
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "xfs.h"
|
#include "xfs.h"
|
||||||
#include "xfs_fs.h"
|
#include "xfs_fs.h"
|
||||||
#include "xfs_types.h"
|
#include "xfs_format.h"
|
||||||
#include "xfs_bit.h"
|
#include "xfs_bit.h"
|
||||||
#include "xfs_log.h"
|
#include "xfs_log.h"
|
||||||
#include "xfs_trans.h"
|
#include "xfs_trans.h"
|
||||||
@@ -722,7 +722,7 @@ xfs_bmbt_key_diff(
|
|||||||
cur->bc_rec.b.br_startoff;
|
cur->bc_rec.b.br_startoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static bool
|
||||||
xfs_bmbt_verify(
|
xfs_bmbt_verify(
|
||||||
struct xfs_buf *bp)
|
struct xfs_buf *bp)
|
||||||
{
|
{
|
||||||
@@ -775,7 +775,6 @@ xfs_bmbt_verify(
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -789,7 +788,6 @@ xfs_bmbt_read_verify(
|
|||||||
bp->b_target->bt_mount, bp->b_addr);
|
bp->b_target->bt_mount, bp->b_addr);
|
||||||
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
xfs_buf_ioerror(bp, EFSCORRUPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2000-2006 Silicon Graphics, Inc.
|
||||||
|
* All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it would 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#ifndef __XFS_BMAP_UTIL_H__
|
||||||
|
#define __XFS_BMAP_UTIL_H__
|
||||||
|
|
||||||
|
/* Kernel only BMAP related definitions and functions */
|
||||||
|
|
||||||
|
struct xfs_bmbt_irec;
|
||||||
|
struct xfs_bmap_free_item;
|
||||||
|
struct xfs_ifork;
|
||||||
|
struct xfs_inode;
|
||||||
|
struct xfs_mount;
|
||||||
|
struct xfs_trans;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Argument structure for xfs_bmap_alloc.
|
||||||
|
*/
|
||||||
|
struct xfs_bmalloca {
|
||||||
|
xfs_fsblock_t *firstblock; /* i/o first block allocated */
|
||||||
|
struct xfs_bmap_free *flist; /* bmap freelist */
|
||||||
|
struct xfs_trans *tp; /* transaction pointer */
|
||||||
|
struct xfs_inode *ip; /* incore inode pointer */
|
||||||
|
struct xfs_bmbt_irec prev; /* extent before the new one */
|
||||||
|
struct xfs_bmbt_irec got; /* extent after, or delayed */
|
||||||
|
|
||||||
|
xfs_fileoff_t offset; /* offset in file filling in */
|
||||||
|
xfs_extlen_t length; /* i/o length asked/allocated */
|
||||||
|
xfs_fsblock_t blkno; /* starting block of new extent */
|
||||||
|
|
||||||
|
struct xfs_btree_cur *cur; /* btree cursor */
|
||||||
|
xfs_extnum_t idx; /* current extent index */
|
||||||
|
int nallocs;/* number of extents alloc'd */
|
||||||
|
int logflags;/* flags for transaction logging */
|
||||||
|
|
||||||
|
xfs_extlen_t total; /* total blocks needed for xaction */
|
||||||
|
xfs_extlen_t minlen; /* minimum allocation size (blocks) */
|
||||||
|
xfs_extlen_t minleft; /* amount must be left after alloc */
|
||||||
|
char eof; /* set if allocating past last extent */
|
||||||
|
char wasdel; /* replacing a delayed allocation */
|
||||||
|
char userdata;/* set if is user data */
|
||||||
|
char aeof; /* allocated space at eof */
|
||||||
|
char conv; /* overwriting unwritten extents */
|
||||||
|
char stack_switch;
|
||||||
|
int flags;
|
||||||
|
struct completion *done;
|
||||||
|
struct work_struct work;
|
||||||
|
int result;
|
||||||
|
};
|
||||||
|
|
||||||
|
int xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
|
||||||
|
int *committed);
|
||||||
|
int xfs_bmap_rtalloc(struct xfs_bmalloca *ap);
|
||||||
|
int xfs_bmapi_allocate(struct xfs_bmalloca *args);
|
||||||
|
int __xfs_bmapi_allocate(struct xfs_bmalloca *args);
|
||||||
|
int xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
|
||||||
|
int whichfork, int *eof);
|
||||||
|
int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
|
||||||
|
int whichfork, int *count);
|
||||||
|
int xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
|
||||||
|
xfs_fileoff_t start_fsb, xfs_fileoff_t length);
|
||||||
|
|
||||||
|
/* bmap to userspace formatter - copy to user & advance pointer */
|
||||||
|
typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
|
||||||
|
int xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
|
||||||
|
xfs_bmap_format_t formatter, void *arg);
|
||||||
|
|
||||||
|
/* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */
|
||||||
|
void xfs_bmap_del_free(struct xfs_bmap_free *flist,
|
||||||
|
struct xfs_bmap_free_item *prev,
|
||||||
|
struct xfs_bmap_free_item *free);
|
||||||
|
int xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp,
|
||||||
|
struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz,
|
||||||
|
int rt, int eof, int delay, int convert,
|
||||||
|
xfs_fileoff_t *offp, xfs_extlen_t *lenp);
|
||||||
|
void xfs_bmap_adjacent(struct xfs_bmalloca *ap);
|
||||||
|
int xfs_bmap_last_extent(struct xfs_trans *tp, struct xfs_inode *ip,
|
||||||
|
int whichfork, struct xfs_bmbt_irec *rec,
|
||||||
|
int *is_empty);
|
||||||
|
|
||||||
|
/* preallocation and hole punch interface */
|
||||||
|
int xfs_change_file_space(struct xfs_inode *ip, int cmd,
|
||||||
|
xfs_flock64_t *bf, xfs_off_t offset,
|
||||||
|
int attr_flags);
|
||||||
|
|
||||||
|
/* EOF block manipulation functions */
|
||||||
|
bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
|
||||||
|
int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
|
||||||
|
bool need_iolock);
|
||||||
|
|
||||||
|
int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
|
||||||
|
struct xfs_swapext *sx);
|
||||||
|
|
||||||
|
xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
|
||||||
|
|
||||||
|
#endif /* __XFS_BMAP_UTIL_H__ */
|
||||||
+4
-3
@@ -510,7 +510,7 @@ xfs_btree_ptr_addr(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a the root block which is stored in the inode.
|
* Get the root block which is stored in the inode.
|
||||||
*
|
*
|
||||||
* For now this btree implementation assumes the btree root is always
|
* For now this btree implementation assumes the btree root is always
|
||||||
* stored in the if_broot field of an inode fork.
|
* stored in the if_broot field of an inode fork.
|
||||||
@@ -978,6 +978,7 @@ xfs_btree_init_block_int(
|
|||||||
buf->bb_u.l.bb_owner = cpu_to_be64(owner);
|
buf->bb_u.l.bb_owner = cpu_to_be64(owner);
|
||||||
uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
|
uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
|
||||||
buf->bb_u.l.bb_pad = 0;
|
buf->bb_u.l.bb_pad = 0;
|
||||||
|
buf->bb_u.l.bb_lsn = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* owner is a 32 bit value on short blocks */
|
/* owner is a 32 bit value on short blocks */
|
||||||
@@ -989,6 +990,7 @@ xfs_btree_init_block_int(
|
|||||||
buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
|
buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
|
||||||
buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
|
buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
|
||||||
uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
|
uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
|
||||||
|
buf->bb_u.s.bb_lsn = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1684,7 +1686,7 @@ xfs_lookup_get_search_key(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup the record. The cursor is made to point to it, based on dir.
|
* Lookup the record. The cursor is made to point to it, based on dir.
|
||||||
* Return 0 if can't find any such record, 1 for success.
|
* stat is set to 0 if can't find any such record, 1 for success.
|
||||||
*/
|
*/
|
||||||
int /* error */
|
int /* error */
|
||||||
xfs_btree_lookup(
|
xfs_btree_lookup(
|
||||||
@@ -2756,7 +2758,6 @@ xfs_btree_make_block_unfull(
|
|||||||
|
|
||||||
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
|
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
|
||||||
/* A root block that can be made bigger. */
|
/* A root block that can be made bigger. */
|
||||||
|
|
||||||
xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork);
|
xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork);
|
||||||
} else {
|
} else {
|
||||||
/* A root block that needs replacing */
|
/* A root block that needs replacing */
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user