Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Conflicts were easy to resolve using immediate context mostly, except the cls_u32.c one where I simply too the entire HEAD chunk. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -514,6 +514,8 @@ static int afs_alloc_anon_key(struct afs_cell *cell)
|
||||
*/
|
||||
static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
|
||||
{
|
||||
struct hlist_node **p;
|
||||
struct afs_cell *pcell;
|
||||
int ret;
|
||||
|
||||
if (!cell->anonymous_key) {
|
||||
@@ -534,7 +536,18 @@ static int afs_activate_cell(struct afs_net *net, struct afs_cell *cell)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&net->proc_cells_lock);
|
||||
list_add_tail(&cell->proc_link, &net->proc_cells);
|
||||
for (p = &net->proc_cells.first; *p; p = &(*p)->next) {
|
||||
pcell = hlist_entry(*p, struct afs_cell, proc_link);
|
||||
if (strcmp(cell->name, pcell->name) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
cell->proc_link.pprev = p;
|
||||
cell->proc_link.next = *p;
|
||||
rcu_assign_pointer(*p, &cell->proc_link.next);
|
||||
if (cell->proc_link.next)
|
||||
cell->proc_link.next->pprev = &cell->proc_link.next;
|
||||
|
||||
afs_dynroot_mkdir(net, cell);
|
||||
mutex_unlock(&net->proc_cells_lock);
|
||||
return 0;
|
||||
@@ -550,7 +563,7 @@ static void afs_deactivate_cell(struct afs_net *net, struct afs_cell *cell)
|
||||
afs_proc_cell_remove(cell);
|
||||
|
||||
mutex_lock(&net->proc_cells_lock);
|
||||
list_del_init(&cell->proc_link);
|
||||
hlist_del_rcu(&cell->proc_link);
|
||||
afs_dynroot_rmdir(net, cell);
|
||||
mutex_unlock(&net->proc_cells_lock);
|
||||
|
||||
|
@@ -265,7 +265,7 @@ int afs_dynroot_populate(struct super_block *sb)
|
||||
return -ERESTARTSYS;
|
||||
|
||||
net->dynroot_sb = sb;
|
||||
list_for_each_entry(cell, &net->proc_cells, proc_link) {
|
||||
hlist_for_each_entry(cell, &net->proc_cells, proc_link) {
|
||||
ret = afs_dynroot_mkdir(net, cell);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
@@ -244,7 +244,7 @@ struct afs_net {
|
||||
seqlock_t cells_lock;
|
||||
|
||||
struct mutex proc_cells_lock;
|
||||
struct list_head proc_cells;
|
||||
struct hlist_head proc_cells;
|
||||
|
||||
/* Known servers. Theoretically each fileserver can only be in one
|
||||
* cell, but in practice, people create aliases and subsets and there's
|
||||
@@ -322,7 +322,7 @@ struct afs_cell {
|
||||
struct afs_net *net;
|
||||
struct key *anonymous_key; /* anonymous user key for this cell */
|
||||
struct work_struct manager; /* Manager for init/deinit/dns */
|
||||
struct list_head proc_link; /* /proc cell list link */
|
||||
struct hlist_node proc_link; /* /proc cell list link */
|
||||
#ifdef CONFIG_AFS_FSCACHE
|
||||
struct fscache_cookie *cache; /* caching cookie */
|
||||
#endif
|
||||
|
@@ -87,7 +87,7 @@ static int __net_init afs_net_init(struct net *net_ns)
|
||||
timer_setup(&net->cells_timer, afs_cells_timer, 0);
|
||||
|
||||
mutex_init(&net->proc_cells_lock);
|
||||
INIT_LIST_HEAD(&net->proc_cells);
|
||||
INIT_HLIST_HEAD(&net->proc_cells);
|
||||
|
||||
seqlock_init(&net->fs_lock);
|
||||
net->fs_servers = RB_ROOT;
|
||||
|
@@ -33,9 +33,8 @@ static inline struct afs_net *afs_seq2net_single(struct seq_file *m)
|
||||
static int afs_proc_cells_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
|
||||
struct afs_net *net = afs_seq2net(m);
|
||||
|
||||
if (v == &net->proc_cells) {
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
/* display header on line 1 */
|
||||
seq_puts(m, "USE NAME\n");
|
||||
return 0;
|
||||
@@ -50,12 +49,12 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
|
||||
__acquires(rcu)
|
||||
{
|
||||
rcu_read_lock();
|
||||
return seq_list_start_head(&afs_seq2net(m)->proc_cells, *_pos);
|
||||
return seq_hlist_start_head_rcu(&afs_seq2net(m)->proc_cells, *_pos);
|
||||
}
|
||||
|
||||
static void *afs_proc_cells_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(v, &afs_seq2net(m)->proc_cells, pos);
|
||||
return seq_hlist_next_rcu(v, &afs_seq2net(m)->proc_cells, pos);
|
||||
}
|
||||
|
||||
static void afs_proc_cells_stop(struct seq_file *m, void *v)
|
||||
|
@@ -199,9 +199,11 @@ static struct afs_server *afs_install_server(struct afs_net *net,
|
||||
|
||||
write_sequnlock(&net->fs_addr_lock);
|
||||
ret = 0;
|
||||
goto out;
|
||||
|
||||
exists:
|
||||
afs_get_server(server);
|
||||
out:
|
||||
write_sequnlock(&net->fs_lock);
|
||||
return server;
|
||||
}
|
||||
|
@@ -975,6 +975,10 @@ static void gfs2_iomap_journaled_page_done(struct inode *inode, loff_t pos,
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
|
||||
if (!page_has_buffers(page)) {
|
||||
create_empty_buffers(page, inode->i_sb->s_blocksize,
|
||||
(1 << BH_Dirty)|(1 << BH_Uptodate));
|
||||
}
|
||||
gfs2_page_add_databufs(ip, page, offset_in_page(pos), copied);
|
||||
}
|
||||
|
||||
|
@@ -1220,35 +1220,92 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unlock both inodes after they've been prepped for a range clone. */
|
||||
STATIC void
|
||||
xfs_reflink_remap_unlock(
|
||||
struct file *file_in,
|
||||
struct file *file_out)
|
||||
{
|
||||
struct inode *inode_in = file_inode(file_in);
|
||||
struct xfs_inode *src = XFS_I(inode_in);
|
||||
struct inode *inode_out = file_inode(file_out);
|
||||
struct xfs_inode *dest = XFS_I(inode_out);
|
||||
bool same_inode = (inode_in == inode_out);
|
||||
|
||||
xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
|
||||
if (!same_inode)
|
||||
xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
|
||||
inode_unlock(inode_out);
|
||||
if (!same_inode)
|
||||
inode_unlock_shared(inode_in);
|
||||
}
|
||||
|
||||
/*
|
||||
* Link a range of blocks from one file to another.
|
||||
* If we're reflinking to a point past the destination file's EOF, we must
|
||||
* zero any speculative post-EOF preallocations that sit between the old EOF
|
||||
* and the destination file offset.
|
||||
*/
|
||||
int
|
||||
xfs_reflink_remap_range(
|
||||
static int
|
||||
xfs_reflink_zero_posteof(
|
||||
struct xfs_inode *ip,
|
||||
loff_t pos)
|
||||
{
|
||||
loff_t isize = i_size_read(VFS_I(ip));
|
||||
|
||||
if (pos <= isize)
|
||||
return 0;
|
||||
|
||||
trace_xfs_zero_eof(ip, isize, pos - isize);
|
||||
return iomap_zero_range(VFS_I(ip), isize, pos - isize, NULL,
|
||||
&xfs_iomap_ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare two files for range cloning. Upon a successful return both inodes
|
||||
* will have the iolock and mmaplock held, the page cache of the out file will
|
||||
* be truncated, and any leases on the out file will have been broken. This
|
||||
* function borrows heavily from xfs_file_aio_write_checks.
|
||||
*
|
||||
* The VFS allows partial EOF blocks to "match" for dedupe even though it hasn't
|
||||
* checked that the bytes beyond EOF physically match. Hence we cannot use the
|
||||
* EOF block in the source dedupe range because it's not a complete block match,
|
||||
* hence can introduce a corruption into the file that has it's block replaced.
|
||||
*
|
||||
* In similar fashion, the VFS file cloning also allows partial EOF blocks to be
|
||||
* "block aligned" for the purposes of cloning entire files. However, if the
|
||||
* source file range includes the EOF block and it lands within the existing EOF
|
||||
* of the destination file, then we can expose stale data from beyond the source
|
||||
* file EOF in the destination file.
|
||||
*
|
||||
* XFS doesn't support partial block sharing, so in both cases we have check
|
||||
* these cases ourselves. For dedupe, we can simply round the length to dedupe
|
||||
* down to the previous whole block and ignore the partial EOF block. While this
|
||||
* means we can't dedupe the last block of a file, this is an acceptible
|
||||
* tradeoff for simplicity on implementation.
|
||||
*
|
||||
* For cloning, we want to share the partial EOF block if it is also the new EOF
|
||||
* block of the destination file. If the partial EOF block lies inside the
|
||||
* existing destination EOF, then we have to abort the clone to avoid exposing
|
||||
* stale data in the destination file. Hence we reject these clone attempts with
|
||||
* -EINVAL in this case.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_reflink_remap_prep(
|
||||
struct file *file_in,
|
||||
loff_t pos_in,
|
||||
struct file *file_out,
|
||||
loff_t pos_out,
|
||||
u64 len,
|
||||
u64 *len,
|
||||
bool is_dedupe)
|
||||
{
|
||||
struct inode *inode_in = file_inode(file_in);
|
||||
struct xfs_inode *src = XFS_I(inode_in);
|
||||
struct inode *inode_out = file_inode(file_out);
|
||||
struct xfs_inode *dest = XFS_I(inode_out);
|
||||
struct xfs_mount *mp = src->i_mount;
|
||||
bool same_inode = (inode_in == inode_out);
|
||||
xfs_fileoff_t sfsbno, dfsbno;
|
||||
xfs_filblks_t fsblen;
|
||||
xfs_extlen_t cowextsize;
|
||||
u64 blkmask = i_blocksize(inode_in) - 1;
|
||||
ssize_t ret;
|
||||
|
||||
if (!xfs_sb_version_hasreflink(&mp->m_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return -EIO;
|
||||
|
||||
/* Lock both files against IO */
|
||||
ret = xfs_iolock_two_inodes_and_break_layout(inode_in, inode_out);
|
||||
if (ret)
|
||||
@@ -1270,33 +1327,115 @@ xfs_reflink_remap_range(
|
||||
goto out_unlock;
|
||||
|
||||
ret = vfs_clone_file_prep_inodes(inode_in, pos_in, inode_out, pos_out,
|
||||
&len, is_dedupe);
|
||||
len, is_dedupe);
|
||||
if (ret <= 0)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* If the dedupe data matches, chop off the partial EOF block
|
||||
* from the source file so we don't try to dedupe the partial
|
||||
* EOF block.
|
||||
*/
|
||||
if (is_dedupe) {
|
||||
*len &= ~blkmask;
|
||||
} else if (*len & blkmask) {
|
||||
/*
|
||||
* The user is attempting to share a partial EOF block,
|
||||
* if it's inside the destination EOF then reject it.
|
||||
*/
|
||||
if (pos_out + *len < i_size_read(inode_out)) {
|
||||
ret = -EINVAL;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attach dquots to dest inode before changing block map */
|
||||
ret = xfs_qm_dqattach(dest);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
|
||||
|
||||
/*
|
||||
* Clear out post-eof preallocations because we don't have page cache
|
||||
* backing the delayed allocations and they'll never get freed on
|
||||
* their own.
|
||||
* Zero existing post-eof speculative preallocations in the destination
|
||||
* file.
|
||||
*/
|
||||
if (xfs_can_free_eofblocks(dest, true)) {
|
||||
ret = xfs_free_eofblocks(dest);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = xfs_reflink_zero_posteof(dest, pos_out);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
/* Set flags and remap blocks. */
|
||||
ret = xfs_reflink_set_inode_flag(src, dest);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
/* Zap any page cache for the destination file's range. */
|
||||
truncate_inode_pages_range(&inode_out->i_data, pos_out,
|
||||
PAGE_ALIGN(pos_out + *len) - 1);
|
||||
|
||||
/* If we're altering the file contents... */
|
||||
if (!is_dedupe) {
|
||||
/*
|
||||
* ...update the timestamps (which will grab the ilock again
|
||||
* from xfs_fs_dirty_inode, so we have to call it before we
|
||||
* take the ilock).
|
||||
*/
|
||||
if (!(file_out->f_mode & FMODE_NOCMTIME)) {
|
||||
ret = file_update_time(file_out);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* ...clear the security bits if the process is not being run
|
||||
* by root. This keeps people from modifying setuid and setgid
|
||||
* binaries.
|
||||
*/
|
||||
ret = file_remove_privs(file_out);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
return 1;
|
||||
out_unlock:
|
||||
xfs_reflink_remap_unlock(file_in, file_out);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link a range of blocks from one file to another.
|
||||
*/
|
||||
int
|
||||
xfs_reflink_remap_range(
|
||||
struct file *file_in,
|
||||
loff_t pos_in,
|
||||
struct file *file_out,
|
||||
loff_t pos_out,
|
||||
u64 len,
|
||||
bool is_dedupe)
|
||||
{
|
||||
struct inode *inode_in = file_inode(file_in);
|
||||
struct xfs_inode *src = XFS_I(inode_in);
|
||||
struct inode *inode_out = file_inode(file_out);
|
||||
struct xfs_inode *dest = XFS_I(inode_out);
|
||||
struct xfs_mount *mp = src->i_mount;
|
||||
xfs_fileoff_t sfsbno, dfsbno;
|
||||
xfs_filblks_t fsblen;
|
||||
xfs_extlen_t cowextsize;
|
||||
ssize_t ret;
|
||||
|
||||
if (!xfs_sb_version_hasreflink(&mp->m_sb))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (XFS_FORCED_SHUTDOWN(mp))
|
||||
return -EIO;
|
||||
|
||||
/* Prepare and then clone file data. */
|
||||
ret = xfs_reflink_remap_prep(file_in, pos_in, file_out, pos_out,
|
||||
&len, is_dedupe);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out);
|
||||
|
||||
dfsbno = XFS_B_TO_FSBT(mp, pos_out);
|
||||
sfsbno = XFS_B_TO_FSBT(mp, pos_in);
|
||||
fsblen = XFS_B_TO_FSB(mp, len);
|
||||
@@ -1305,10 +1444,6 @@ xfs_reflink_remap_range(
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
/* Zap any page cache for the destination file's range. */
|
||||
truncate_inode_pages_range(&inode_out->i_data, pos_out,
|
||||
PAGE_ALIGN(pos_out + len) - 1);
|
||||
|
||||
/*
|
||||
* Carry the cowextsize hint from src to dest if we're sharing the
|
||||
* entire source file to the entire destination file, the source file
|
||||
@@ -1325,12 +1460,7 @@ xfs_reflink_remap_range(
|
||||
is_dedupe);
|
||||
|
||||
out_unlock:
|
||||
xfs_iunlock(dest, XFS_MMAPLOCK_EXCL);
|
||||
if (!same_inode)
|
||||
xfs_iunlock(src, XFS_MMAPLOCK_SHARED);
|
||||
inode_unlock(inode_out);
|
||||
if (!same_inode)
|
||||
inode_unlock_shared(inode_in);
|
||||
xfs_reflink_remap_unlock(file_in, file_out);
|
||||
if (ret)
|
||||
trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_);
|
||||
return ret;
|
||||
|
Reference in New Issue
Block a user