2019-05-31 15:09:56 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2006-01-16 23:50:04 +07:00
|
|
|
/*
|
|
|
|
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
2006-05-19 02:09:15 +07:00
|
|
|
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2006-04-24 21:07:13 +07:00
|
|
|
* Implements Extendible Hashing as described in:
|
|
|
|
* "Extendible Hashing" by Fagin, et al in
|
|
|
|
* __ACM Trans. on Database Systems__, Sept 1979.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Here's the layout of dirents which is essentially the same as that of ext2
|
|
|
|
* within a single block. The field de_name_len is the number of bytes
|
|
|
|
* actually required for the name (no null terminator). The field de_rec_len
|
|
|
|
* is the number of bytes allocated to the dirent. The offset of the next
|
|
|
|
* dirent in the block is (dirent + dirent->de_rec_len). When a dirent is
|
|
|
|
* deleted, the preceding dirent inherits its allocated space, ie
|
|
|
|
* prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained
|
|
|
|
* by adding de_rec_len to the current dirent, this essentially causes the
|
|
|
|
* deleted dirent to get jumped over when iterating through all the dirents.
|
|
|
|
*
|
|
|
|
* When deleting the first dirent in a block, there is no previous dirent so
|
|
|
|
* the field de_ino is set to zero to designate it as deleted. When allocating
|
|
|
|
* a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the
|
|
|
|
* first dirent has (de_ino == 0) and de_rec_len is large enough, this first
|
|
|
|
* dirent is allocated. Otherwise it must go through all the 'used' dirents
|
|
|
|
* searching for one in which the amount of total space minus the amount of
|
|
|
|
* used space will provide enough space for the new dirent.
|
|
|
|
*
|
|
|
|
* There are two types of blocks in which dirents reside. In a stuffed dinode,
|
|
|
|
* the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of
|
|
|
|
* the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the
|
|
|
|
* beginning of the leaf block. The dirents reside in leaves when
|
|
|
|
*
|
2008-11-04 17:05:22 +07:00
|
|
|
* dip->i_diskflags & GFS2_DIF_EXHASH is true
|
2006-04-24 21:07:13 +07:00
|
|
|
*
|
|
|
|
* Otherwise, the dirents are "linear", within a single stuffed dinode block.
|
|
|
|
*
|
|
|
|
* When the dirents are in leaves, the actual contents of the directory file are
|
|
|
|
* used as an array of 64-bit block pointers pointing to the leaf blocks. The
|
|
|
|
* dirents are NOT in the directory file itself. There can be more than one
|
|
|
|
* block pointer in the array that points to the same leaf. In fact, when a
|
|
|
|
* directory is first converted from linear to exhash, all of the pointers
|
|
|
|
* point to the same leaf.
|
|
|
|
*
|
|
|
|
* When a leaf is completely full, the size of the hash table can be
|
|
|
|
* doubled unless it is already at the maximum size which is hard coded into
|
|
|
|
* GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list,
|
|
|
|
* but never before the maximum hash table size has been reached.
|
|
|
|
*/
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2014-03-07 03:10:45 +07:00
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/buffer_head.h>
|
|
|
|
#include <linux/sort.h>
|
2006-02-28 05:23:27 +07:00
|
|
|
#include <linux/gfs2_ondisk.h>
|
2006-03-29 02:14:04 +07:00
|
|
|
#include <linux/crc32.h>
|
2006-04-18 21:09:15 +07:00
|
|
|
#include <linux/vmalloc.h>
|
2016-11-01 20:40:13 +07:00
|
|
|
#include <linux/bio.h>
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
#include "gfs2.h"
|
2006-02-28 05:23:27 +07:00
|
|
|
#include "incore.h"
|
2006-01-16 23:50:04 +07:00
|
|
|
#include "dir.h"
|
|
|
|
#include "glock.h"
|
|
|
|
#include "inode.h"
|
|
|
|
#include "meta_io.h"
|
|
|
|
#include "quota.h"
|
|
|
|
#include "rgrp.h"
|
|
|
|
#include "trans.h"
|
2006-01-30 20:31:50 +07:00
|
|
|
#include "bmap.h"
|
2006-02-28 05:23:27 +07:00
|
|
|
#include "util.h"
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-10-27 23:16:06 +07:00
|
|
|
#define MAX_RA_BLOCKS 32 /* max read-ahead blocks */
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
|
|
|
|
#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
#define GFS2_HASH_INDEX_MASK 0xffffc000
|
|
|
|
#define GFS2_USE_HASH_FLAG 0x2000
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2010-09-17 18:30:23 +07:00
|
|
|
struct qstr gfs2_qdot __read_mostly;
|
|
|
|
struct qstr gfs2_qdotdot __read_mostly;
|
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name, void *opaque);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
|
2006-04-24 21:07:13 +07:00
|
|
|
struct buffer_head **bhp)
|
2006-01-30 20:31:50 +07:00
|
|
|
{
|
|
|
|
struct buffer_head *bh;
|
|
|
|
|
2006-04-24 21:07:13 +07:00
|
|
|
bh = gfs2_meta_new(ip->i_gl, block);
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, bh);
|
2006-04-24 21:07:13 +07:00
|
|
|
gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
|
|
|
|
gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
|
2006-01-30 20:31:50 +07:00
|
|
|
*bhp = bh;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block,
|
2006-04-24 21:07:13 +07:00
|
|
|
struct buffer_head **bhp)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh;
|
|
|
|
int error;
|
2006-01-30 20:31:50 +07:00
|
|
|
|
2015-11-12 04:00:35 +07:00
|
|
|
error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, 0, &bh);
|
2006-04-24 21:07:13 +07:00
|
|
|
if (error)
|
|
|
|
return error;
|
2006-06-15 02:32:57 +07:00
|
|
|
if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
|
2006-04-24 21:07:13 +07:00
|
|
|
brelse(bh);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
*bhp = bh;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-01-30 20:31:50 +07:00
|
|
|
|
|
|
|
static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
|
|
|
|
unsigned int offset, unsigned int size)
|
|
|
|
{
|
|
|
|
struct buffer_head *dibh;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(ip, &dibh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, dibh);
|
2006-03-21 00:30:04 +07:00
|
|
|
memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
|
2010-08-11 15:53:11 +07:00
|
|
|
if (ip->i_inode.i_size < offset + size)
|
|
|
|
i_size_write(&ip->i_inode, offset + size);
|
2016-09-14 21:48:04 +07:00
|
|
|
ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(ip, dibh->b_data);
|
2006-01-30 20:31:50 +07:00
|
|
|
|
|
|
|
brelse(dibh);
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_write_data - Write directory information to the inode
|
|
|
|
* @ip: The GFS2 inode
|
|
|
|
* @buf: The buffer containing information to be written
|
|
|
|
* @offset: The file offset to start writing at
|
|
|
|
* @size: The amount of data to write
|
|
|
|
*
|
|
|
|
* Returns: The number of bytes correctly written or error code
|
|
|
|
*/
|
|
|
|
static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 offset, unsigned int size)
|
2006-01-30 20:31:50 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
2006-01-30 20:31:50 +07:00
|
|
|
struct buffer_head *dibh;
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 lblock, dblock;
|
|
|
|
u32 extlen = 0;
|
2006-01-30 20:31:50 +07:00
|
|
|
unsigned int o;
|
|
|
|
int copied = 0;
|
|
|
|
int error = 0;
|
2008-02-22 23:09:31 +07:00
|
|
|
int new = 0;
|
2006-01-30 20:31:50 +07:00
|
|
|
|
|
|
|
if (!size)
|
|
|
|
return 0;
|
|
|
|
|
2017-11-14 22:53:12 +07:00
|
|
|
if (gfs2_is_stuffed(ip) && offset + size <= gfs2_max_stuffed_size(ip))
|
2006-02-28 00:00:42 +07:00
|
|
|
return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset,
|
|
|
|
size);
|
2006-01-30 20:31:50 +07:00
|
|
|
|
|
|
|
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (gfs2_is_stuffed(ip)) {
|
2006-07-26 21:51:20 +07:00
|
|
|
error = gfs2_unstuff_dinode(ip, NULL);
|
2006-01-30 20:31:50 +07:00
|
|
|
if (error)
|
2006-03-21 00:30:04 +07:00
|
|
|
return error;
|
2006-01-30 20:31:50 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
lblock = offset;
|
|
|
|
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
|
|
|
|
|
|
|
|
while (copied < size) {
|
|
|
|
unsigned int amount;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
|
|
|
|
amount = size - copied;
|
|
|
|
if (amount > sdp->sd_sb.sb_bsize - o)
|
|
|
|
amount = sdp->sd_sb.sb_bsize - o;
|
|
|
|
|
|
|
|
if (!extlen) {
|
|
|
|
new = 1;
|
2006-06-15 02:32:57 +07:00
|
|
|
error = gfs2_extent_map(&ip->i_inode, lblock, &new,
|
2006-05-06 03:59:11 +07:00
|
|
|
&dblock, &extlen);
|
2006-01-30 20:31:50 +07:00
|
|
|
if (error)
|
|
|
|
goto fail;
|
|
|
|
error = -EIO;
|
|
|
|
if (gfs2_assert_withdraw(sdp, dblock))
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2006-04-24 21:07:13 +07:00
|
|
|
if (amount == sdp->sd_jbsize || new)
|
|
|
|
error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
|
|
|
|
else
|
|
|
|
error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
|
|
|
|
|
2006-01-30 20:31:50 +07:00
|
|
|
if (error)
|
|
|
|
goto fail;
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, bh);
|
2006-01-30 20:31:50 +07:00
|
|
|
memcpy(bh->b_data + o, buf, amount);
|
|
|
|
brelse(bh);
|
|
|
|
|
2006-08-02 02:28:57 +07:00
|
|
|
buf += amount;
|
2006-01-30 20:31:50 +07:00
|
|
|
copied += amount;
|
|
|
|
lblock++;
|
|
|
|
dblock++;
|
|
|
|
extlen--;
|
|
|
|
|
|
|
|
o = sizeof(struct gfs2_meta_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
error = gfs2_meta_inode_buffer(ip, &dibh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2010-08-11 15:53:11 +07:00
|
|
|
if (ip->i_inode.i_size < offset + copied)
|
|
|
|
i_size_write(&ip->i_inode, offset + copied);
|
2016-09-14 21:48:04 +07:00
|
|
|
ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
|
2006-01-30 20:31:50 +07:00
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, dibh);
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(ip, dibh->b_data);
|
2006-01-30 20:31:50 +07:00
|
|
|
brelse(dibh);
|
|
|
|
|
|
|
|
return copied;
|
|
|
|
fail:
|
|
|
|
if (copied)
|
|
|
|
goto out;
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2011-07-26 15:17:28 +07:00
|
|
|
static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, __be64 *buf,
|
|
|
|
unsigned int size)
|
2006-01-30 20:31:50 +07:00
|
|
|
{
|
|
|
|
struct buffer_head *dibh;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(ip, &dibh);
|
|
|
|
if (!error) {
|
2011-07-26 15:17:28 +07:00
|
|
|
memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), size);
|
2006-01-30 20:31:50 +07:00
|
|
|
brelse(dibh);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error) ? error : size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_read_data - Read a data from a directory inode
|
|
|
|
* @ip: The GFS2 Inode
|
|
|
|
* @buf: The buffer to place result into
|
|
|
|
* @size: Amount of data to transfer
|
|
|
|
*
|
|
|
|
* Returns: The amount of data actually copied or the error
|
|
|
|
*/
|
2011-07-26 15:17:28 +07:00
|
|
|
static int gfs2_dir_read_data(struct gfs2_inode *ip, __be64 *buf,
|
|
|
|
unsigned int size)
|
2006-01-30 20:31:50 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 lblock, dblock;
|
|
|
|
u32 extlen = 0;
|
2006-01-30 20:31:50 +07:00
|
|
|
unsigned int o;
|
|
|
|
int copied = 0;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (gfs2_is_stuffed(ip))
|
2011-07-26 15:17:28 +07:00
|
|
|
return gfs2_dir_read_stuffed(ip, buf, size);
|
2006-01-30 20:31:50 +07:00
|
|
|
|
|
|
|
if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-07-26 15:17:28 +07:00
|
|
|
lblock = 0;
|
2006-01-30 20:31:50 +07:00
|
|
|
o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
|
|
|
|
|
|
|
|
while (copied < size) {
|
|
|
|
unsigned int amount;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
int new;
|
|
|
|
|
|
|
|
amount = size - copied;
|
|
|
|
if (amount > sdp->sd_sb.sb_bsize - o)
|
|
|
|
amount = sdp->sd_sb.sb_bsize - o;
|
|
|
|
|
|
|
|
if (!extlen) {
|
|
|
|
new = 0;
|
2006-06-15 02:32:57 +07:00
|
|
|
error = gfs2_extent_map(&ip->i_inode, lblock, &new,
|
2006-05-06 03:59:11 +07:00
|
|
|
&dblock, &extlen);
|
2006-09-22 04:05:23 +07:00
|
|
|
if (error || !dblock)
|
2006-01-30 20:31:50 +07:00
|
|
|
goto fail;
|
2006-09-22 04:05:23 +07:00
|
|
|
BUG_ON(extlen < 1);
|
|
|
|
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
|
2006-10-19 21:02:07 +07:00
|
|
|
} else {
|
2015-11-12 04:00:35 +07:00
|
|
|
error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, 0, &bh);
|
2006-01-30 20:31:50 +07:00
|
|
|
if (error)
|
|
|
|
goto fail;
|
2006-09-22 04:05:23 +07:00
|
|
|
}
|
|
|
|
error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD);
|
|
|
|
if (error) {
|
|
|
|
brelse(bh);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
dblock++;
|
|
|
|
extlen--;
|
2006-01-30 20:31:50 +07:00
|
|
|
memcpy(buf, bh->b_data + o, amount);
|
|
|
|
brelse(bh);
|
2011-07-26 15:17:28 +07:00
|
|
|
buf += (amount/sizeof(__be64));
|
2006-01-30 20:31:50 +07:00
|
|
|
copied += amount;
|
|
|
|
lblock++;
|
|
|
|
o = sizeof(struct gfs2_meta_header);
|
|
|
|
}
|
|
|
|
|
|
|
|
return copied;
|
|
|
|
fail:
|
|
|
|
return (copied) ? copied : error;
|
|
|
|
}
|
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
/**
|
|
|
|
* gfs2_dir_get_hash_table - Get pointer to the dir hash table
|
|
|
|
* @ip: The inode in question
|
|
|
|
*
|
|
|
|
* Returns: The hash table or an error
|
|
|
|
*/
|
|
|
|
|
|
|
|
static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
|
|
|
|
{
|
|
|
|
struct inode *inode = &ip->i_inode;
|
|
|
|
int ret;
|
|
|
|
u32 hsize;
|
|
|
|
__be64 *hc;
|
|
|
|
|
|
|
|
BUG_ON(!(ip->i_diskflags & GFS2_DIF_EXHASH));
|
|
|
|
|
|
|
|
hc = ip->i_hash_cache;
|
|
|
|
if (hc)
|
|
|
|
return hc;
|
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
hsize = BIT(ip->i_depth);
|
2011-06-15 16:29:37 +07:00
|
|
|
hsize *= sizeof(__be64);
|
|
|
|
if (hsize != i_size_read(&ip->i_inode)) {
|
|
|
|
gfs2_consist_inode(ip);
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
}
|
|
|
|
|
2013-05-30 20:48:56 +07:00
|
|
|
hc = kmalloc(hsize, GFP_NOFS | __GFP_NOWARN);
|
|
|
|
if (hc == NULL)
|
|
|
|
hc = __vmalloc(hsize, GFP_NOFS, PAGE_KERNEL);
|
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
if (hc == NULL)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
2011-07-26 15:17:28 +07:00
|
|
|
ret = gfs2_dir_read_data(ip, hc, hsize);
|
2011-06-15 16:29:37 +07:00
|
|
|
if (ret < 0) {
|
2014-11-20 12:18:38 +07:00
|
|
|
kvfree(hc);
|
2011-06-15 16:29:37 +07:00
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
2014-11-20 12:19:47 +07:00
|
|
|
if (likely(!ip->i_hash_cache)) {
|
2011-06-15 16:29:37 +07:00
|
|
|
ip->i_hash_cache = hc;
|
2014-11-20 12:19:47 +07:00
|
|
|
hc = NULL;
|
|
|
|
}
|
2011-06-15 16:29:37 +07:00
|
|
|
spin_unlock(&inode->i_lock);
|
2014-11-20 12:19:47 +07:00
|
|
|
kvfree(hc);
|
2011-06-15 16:29:37 +07:00
|
|
|
|
|
|
|
return ip->i_hash_cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_hash_inval - Invalidate dir hash
|
|
|
|
* @ip: The directory inode
|
|
|
|
*
|
|
|
|
* Must be called with an exclusive glock, or during glock invalidation.
|
|
|
|
*/
|
|
|
|
void gfs2_dir_hash_inval(struct gfs2_inode *ip)
|
|
|
|
{
|
2015-10-29 22:03:41 +07:00
|
|
|
__be64 *hc;
|
|
|
|
|
|
|
|
spin_lock(&ip->i_inode.i_lock);
|
|
|
|
hc = ip->i_hash_cache;
|
2011-06-15 16:29:37 +07:00
|
|
|
ip->i_hash_cache = NULL;
|
2015-10-29 22:03:41 +07:00
|
|
|
spin_unlock(&ip->i_inode.i_lock);
|
|
|
|
|
2014-11-20 12:18:38 +07:00
|
|
|
kvfree(hc);
|
2011-06-15 16:29:37 +07:00
|
|
|
}
|
|
|
|
|
2006-11-18 00:27:44 +07:00
|
|
|
static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
|
|
|
|
{
|
|
|
|
return dent->de_inum.no_addr == 0 || dent->de_inum.no_formal_ino == 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name, int ret)
|
|
|
|
{
|
2006-11-18 00:27:44 +07:00
|
|
|
if (!gfs2_dirent_sentinel(dent) &&
|
2006-03-21 00:30:04 +07:00
|
|
|
be32_to_cpu(dent->de_hash) == name->hash &&
|
|
|
|
be16_to_cpu(dent->de_name_len) == name->len &&
|
2006-09-05 20:34:20 +07:00
|
|
|
memcmp(dent+1, name->name, name->len) == 0)
|
2006-03-21 00:30:04 +07:00
|
|
|
return ret;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gfs2_dirent_find(const struct gfs2_dirent *dent,
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
2006-03-21 00:30:04 +07:00
|
|
|
{
|
|
|
|
return __gfs2_dirent_find(dent, name, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
2006-03-21 00:30:04 +07:00
|
|
|
{
|
|
|
|
return __gfs2_dirent_find(dent, name, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* name->name holds ptr to start of block.
|
|
|
|
* name->len holds size of block.
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
2006-03-21 00:30:04 +07:00
|
|
|
static int gfs2_dirent_last(const struct gfs2_dirent *dent,
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
2006-03-21 00:30:04 +07:00
|
|
|
{
|
|
|
|
const char *start = name->name;
|
|
|
|
const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len);
|
|
|
|
if (name->len == (end - start))
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2015-12-01 21:30:34 +07:00
|
|
|
/* Look for the dirent that contains the offset specified in data. Once we
|
|
|
|
* find that dirent, there must be space available there for the new dirent */
|
|
|
|
static int gfs2_dirent_find_offset(const struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name,
|
|
|
|
void *ptr)
|
|
|
|
{
|
|
|
|
unsigned required = GFS2_DIRENT_SIZE(name->len);
|
|
|
|
unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
|
|
|
|
unsigned totlen = be16_to_cpu(dent->de_rec_len);
|
|
|
|
|
|
|
|
if (ptr < (void *)dent || ptr >= (void *)dent + totlen)
|
|
|
|
return 0;
|
|
|
|
if (gfs2_dirent_sentinel(dent))
|
|
|
|
actual = 0;
|
|
|
|
if (ptr < (void *)dent + actual)
|
|
|
|
return -1;
|
|
|
|
if ((void *)dent + totlen >= ptr + required)
|
|
|
|
return 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static int gfs2_dirent_find_space(const struct gfs2_dirent *dent,
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-03-21 00:30:04 +07:00
|
|
|
unsigned required = GFS2_DIRENT_SIZE(name->len);
|
|
|
|
unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
|
|
|
|
unsigned totlen = be16_to_cpu(dent->de_rec_len);
|
|
|
|
|
2006-11-18 00:27:44 +07:00
|
|
|
if (gfs2_dirent_sentinel(dent))
|
GFS2: rename causes kernel Oops
This patch fixes a kernel Oops in the GFS2 rename code.
The problem was in the way the gfs2 directory code was trying
to re-use sentinel directory entries.
In the failing case, gfs2's rename function was renaming a
file to another name that had the same non-trivial length.
The file being renamed happened to be the first directory
entry on the leaf block.
First, the rename code (gfs2_rename in ops_inode.c) found the
original directory entry and decided it could do its job by
simply replacing the directory entry with another. Therefore
it determined correctly that no block allocations were needed.
Next, the rename code deleted the old directory entry prior to
replacing it with the new name. Therefore, the soon-to-be
replaced directory entry was temporarily made into a directory
entry "sentinel" or a place holder at the start of a leaf block.
Lastly, it went to re-add the replacement directory entry in
that leaf block. However, when gfs2_dirent_find_space was
looking for space in the leaf block, it used the wrong value
for the sentinel. That threw off its calculations so later
it decides it can't really re-use the sentinel and therefore
must allocate a new leaf block. But because it previously decided
to re-use the directory entry, it didn't waste the time to
grab a new block allocation for the inode. Therefore, the
inode's i_alloc pointer was still NULL and it crashes trying to
reference it.
In the case of sentinel directory entries, the entire dirent is
reused, not just the "free space" portion of it, and therefore
the function gfs2_dirent_find_space should use the value 0
rather than GFS2_DIRENT_SIZE(0) for the actual dirent size.
Fixing this calculation enables the reproducer programs to work
properly.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-07-15 05:12:26 +07:00
|
|
|
actual = 0;
|
2006-09-05 19:30:40 +07:00
|
|
|
if (totlen - actual >= required)
|
2006-03-21 00:30:04 +07:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-29 02:14:04 +07:00
|
|
|
struct dirent_gather {
|
|
|
|
const struct gfs2_dirent **pdent;
|
|
|
|
unsigned offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int gfs2_dirent_gather(const struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct dirent_gather *g = opaque;
|
2006-11-18 00:27:44 +07:00
|
|
|
if (!gfs2_dirent_sentinel(dent)) {
|
2006-03-29 02:14:04 +07:00
|
|
|
g->pdent[g->offset++] = dent;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
/*
|
|
|
|
* Other possible things to check:
|
|
|
|
* - Inode located within filesystem size (and on valid block)
|
|
|
|
* - Valid directory entry type
|
|
|
|
* Not sure how heavy-weight we want to make this... could also check
|
|
|
|
* hash is correct for example, but that would take a lot of extra time.
|
|
|
|
* For now the most important thing is to check that the various sizes
|
|
|
|
* are correct.
|
|
|
|
*/
|
2018-10-03 20:47:36 +07:00
|
|
|
static int gfs2_check_dirent(struct gfs2_sbd *sdp,
|
|
|
|
struct gfs2_dirent *dent, unsigned int offset,
|
2006-03-21 00:30:04 +07:00
|
|
|
unsigned int size, unsigned int len, int first)
|
|
|
|
{
|
|
|
|
const char *msg = "gfs2_dirent too small";
|
|
|
|
if (unlikely(size < sizeof(struct gfs2_dirent)))
|
|
|
|
goto error;
|
|
|
|
msg = "gfs2_dirent misaligned";
|
|
|
|
if (unlikely(offset & 0x7))
|
|
|
|
goto error;
|
|
|
|
msg = "gfs2_dirent points beyond end of block";
|
|
|
|
if (unlikely(offset + size > len))
|
|
|
|
goto error;
|
|
|
|
msg = "zero inode number";
|
2006-11-18 00:27:44 +07:00
|
|
|
if (unlikely(!first && gfs2_dirent_sentinel(dent)))
|
2006-03-21 00:30:04 +07:00
|
|
|
goto error;
|
|
|
|
msg = "name length is greater than space in dirent";
|
2006-11-18 00:27:44 +07:00
|
|
|
if (!gfs2_dirent_sentinel(dent) &&
|
2006-03-21 00:30:04 +07:00
|
|
|
unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) >
|
|
|
|
size))
|
|
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
2018-10-03 20:47:36 +07:00
|
|
|
fs_warn(sdp, "%s: %s (%s)\n",
|
2014-03-07 03:10:45 +07:00
|
|
|
__func__, msg, first ? "first in block" : "not first in block");
|
2006-03-21 00:30:04 +07:00
|
|
|
return -EIO;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2018-10-03 20:47:36 +07:00
|
|
|
static int gfs2_dirent_offset(struct gfs2_sbd *sdp, const void *buf)
|
2006-03-21 00:30:04 +07:00
|
|
|
{
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct gfs2_meta_header *h = buf;
|
|
|
|
int offset;
|
2006-03-21 00:30:04 +07:00
|
|
|
|
|
|
|
BUG_ON(buf == NULL);
|
|
|
|
|
2006-03-31 03:46:23 +07:00
|
|
|
switch(be32_to_cpu(h->mh_type)) {
|
2006-03-21 00:30:04 +07:00
|
|
|
case GFS2_METATYPE_LF:
|
|
|
|
offset = sizeof(struct gfs2_leaf);
|
|
|
|
break;
|
|
|
|
case GFS2_METATYPE_DI:
|
|
|
|
offset = sizeof(struct gfs2_dinode);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto wrong_type;
|
|
|
|
}
|
2006-03-29 02:14:04 +07:00
|
|
|
return offset;
|
|
|
|
wrong_type:
|
2018-10-03 20:47:36 +07:00
|
|
|
fs_warn(sdp, "%s: wrong block type %u\n", __func__,
|
|
|
|
be32_to_cpu(h->mh_type));
|
2006-03-29 02:14:04 +07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
|
2006-03-29 02:14:04 +07:00
|
|
|
unsigned int len, gfs2_dscan_t scan,
|
|
|
|
const struct qstr *name,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
struct gfs2_dirent *dent, *prev;
|
|
|
|
unsigned offset;
|
|
|
|
unsigned size;
|
|
|
|
int ret = 0;
|
2006-03-21 00:30:04 +07:00
|
|
|
|
2018-10-03 20:47:36 +07:00
|
|
|
ret = gfs2_dirent_offset(GFS2_SB(inode), buf);
|
2006-03-29 02:14:04 +07:00
|
|
|
if (ret < 0)
|
|
|
|
goto consist_inode;
|
|
|
|
|
|
|
|
offset = ret;
|
2006-03-21 00:30:04 +07:00
|
|
|
prev = NULL;
|
2006-09-05 20:34:20 +07:00
|
|
|
dent = buf + offset;
|
2006-03-21 00:30:04 +07:00
|
|
|
size = be16_to_cpu(dent->de_rec_len);
|
2018-10-03 20:47:36 +07:00
|
|
|
if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size, len, 1))
|
2006-03-21 00:30:04 +07:00
|
|
|
goto consist_inode;
|
|
|
|
do {
|
2006-03-29 02:14:04 +07:00
|
|
|
ret = scan(dent, name, opaque);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
offset += size;
|
|
|
|
if (offset == len)
|
|
|
|
break;
|
|
|
|
prev = dent;
|
2006-09-05 20:34:20 +07:00
|
|
|
dent = buf + offset;
|
2006-03-21 00:30:04 +07:00
|
|
|
size = be16_to_cpu(dent->de_rec_len);
|
2018-10-03 20:47:36 +07:00
|
|
|
if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size,
|
|
|
|
len, 0))
|
2006-03-21 00:30:04 +07:00
|
|
|
goto consist_inode;
|
|
|
|
} while(1);
|
|
|
|
|
|
|
|
switch(ret) {
|
|
|
|
case 0:
|
|
|
|
return NULL;
|
|
|
|
case 1:
|
|
|
|
return dent;
|
|
|
|
case 2:
|
|
|
|
return prev ? prev : dent;
|
|
|
|
default:
|
|
|
|
BUG_ON(ret > 0);
|
|
|
|
return ERR_PTR(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
consist_inode:
|
2006-06-15 02:32:57 +07:00
|
|
|
gfs2_consist_inode(GFS2_I(inode));
|
2006-03-21 00:30:04 +07:00
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
}
|
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
static int dirent_check_reclen(struct gfs2_inode *dip,
|
|
|
|
const struct gfs2_dirent *d, const void *end_p)
|
|
|
|
{
|
|
|
|
const void *ptr = d;
|
|
|
|
u16 rec_len = be16_to_cpu(d->de_rec_len);
|
|
|
|
|
|
|
|
if (unlikely(rec_len < sizeof(struct gfs2_dirent)))
|
|
|
|
goto broken;
|
|
|
|
ptr += rec_len;
|
|
|
|
if (ptr < end_p)
|
|
|
|
return rec_len;
|
|
|
|
if (ptr == end_p)
|
|
|
|
return -ENOENT;
|
|
|
|
broken:
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/**
|
|
|
|
* dirent_next - Next dirent
|
|
|
|
* @dip: the directory
|
|
|
|
* @bh: The buffer
|
|
|
|
* @dent: Pointer to list of dirents
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code otherwise
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh,
|
|
|
|
struct gfs2_dirent **dent)
|
|
|
|
{
|
2006-09-05 20:34:20 +07:00
|
|
|
struct gfs2_dirent *cur = *dent, *tmp;
|
|
|
|
char *bh_end = bh->b_data + bh->b_size;
|
|
|
|
int ret;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
ret = dirent_check_reclen(dip, cur, bh_end);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2006-02-14 22:56:44 +07:00
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
tmp = (void *)cur + ret;
|
|
|
|
ret = dirent_check_reclen(dip, tmp, bh_end);
|
|
|
|
if (ret == -EIO)
|
|
|
|
return ret;
|
2006-02-14 22:56:44 +07:00
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/* Only the first dent could ever have de_inum.no_addr == 0 */
|
2006-11-18 00:27:44 +07:00
|
|
|
if (gfs2_dirent_sentinel(tmp)) {
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dent = tmp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* dirent_del - Delete a dirent
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
* @bh: The buffer
|
|
|
|
* @prev: The previous dirent
|
|
|
|
* @cur: The current dirent
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,
|
|
|
|
struct gfs2_dirent *prev, struct gfs2_dirent *cur)
|
|
|
|
{
|
2006-09-04 23:49:07 +07:00
|
|
|
u16 cur_rec_len, prev_rec_len;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-11-18 00:27:44 +07:00
|
|
|
if (gfs2_dirent_sentinel(cur)) {
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
/* If there is no prev entry, this is the first entry in the block.
|
|
|
|
The de_rec_len is already as big as it needs to be. Just zero
|
|
|
|
out the inode number and return. */
|
|
|
|
|
|
|
|
if (!prev) {
|
2006-11-18 00:27:44 +07:00
|
|
|
cur->de_inum.no_addr = 0;
|
|
|
|
cur->de_inum.no_formal_ino = 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Combine this dentry with the previous one. */
|
|
|
|
|
2006-02-13 23:21:47 +07:00
|
|
|
prev_rec_len = be16_to_cpu(prev->de_rec_len);
|
|
|
|
cur_rec_len = be16_to_cpu(cur->de_rec_len);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
if ((char *)prev + prev_rec_len != (char *)cur)
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size)
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
|
|
|
|
prev_rec_len += cur_rec_len;
|
2006-02-13 23:21:47 +07:00
|
|
|
prev->de_rec_len = cpu_to_be16(prev_rec_len);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2015-12-01 21:30:34 +07:00
|
|
|
|
|
|
|
static struct gfs2_dirent *do_init_dirent(struct inode *inode,
|
|
|
|
struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name,
|
|
|
|
struct buffer_head *bh,
|
|
|
|
unsigned offset)
|
|
|
|
{
|
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
|
struct gfs2_dirent *ndent;
|
|
|
|
unsigned totlen;
|
|
|
|
|
|
|
|
totlen = be16_to_cpu(dent->de_rec_len);
|
|
|
|
BUG_ON(offset + name->len > totlen);
|
|
|
|
gfs2_trans_add_meta(ip->i_gl, bh);
|
|
|
|
ndent = (struct gfs2_dirent *)((char *)dent + offset);
|
|
|
|
dent->de_rec_len = cpu_to_be16(offset);
|
|
|
|
gfs2_qstr2dirent(name, totlen - offset, ndent);
|
|
|
|
return ndent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
/*
|
|
|
|
* Takes a dent from which to grab space as an argument. Returns the
|
|
|
|
* newly created dent.
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
2006-04-28 21:59:12 +07:00
|
|
|
static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,
|
|
|
|
struct gfs2_dirent *dent,
|
|
|
|
const struct qstr *name,
|
|
|
|
struct buffer_head *bh)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2015-12-01 21:30:34 +07:00
|
|
|
unsigned offset = 0;
|
2006-03-21 00:30:04 +07:00
|
|
|
|
2006-11-18 00:27:44 +07:00
|
|
|
if (!gfs2_dirent_sentinel(dent))
|
2006-03-21 00:30:04 +07:00
|
|
|
offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
|
2015-12-01 21:30:34 +07:00
|
|
|
return do_init_dirent(inode, dent, name, bh, offset);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2015-12-01 21:30:34 +07:00
|
|
|
static struct gfs2_dirent *gfs2_dirent_split_alloc(struct inode *inode,
|
|
|
|
struct buffer_head *bh,
|
|
|
|
const struct qstr *name,
|
|
|
|
void *ptr)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
|
|
|
struct gfs2_dirent *dent;
|
2006-09-25 20:26:04 +07:00
|
|
|
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
|
2015-12-01 21:30:34 +07:00
|
|
|
gfs2_dirent_find_offset, name, ptr);
|
2019-06-05 21:24:24 +07:00
|
|
|
if (IS_ERR_OR_NULL(dent))
|
2006-03-21 00:30:04 +07:00
|
|
|
return dent;
|
2015-12-01 21:30:34 +07:00
|
|
|
return do_init_dirent(inode, dent, name, bh,
|
|
|
|
(unsigned)(ptr - (void *)dent));
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
|
2006-01-16 23:50:04 +07:00
|
|
|
struct buffer_head **bhp)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
2015-11-12 04:00:35 +07:00
|
|
|
error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, 0, bhp);
|
2006-06-15 02:32:57 +07:00
|
|
|
if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
|
2014-03-07 03:10:45 +07:00
|
|
|
/* pr_info("block num=%llu\n", leaf_no); */
|
2006-01-16 23:50:04 +07:00
|
|
|
error = -EIO;
|
2006-06-15 02:32:57 +07:00
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get_leaf_nr - Get a leaf number associated with the index
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
* @index:
|
|
|
|
* @leaf_out:
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code otherwise
|
|
|
|
*/
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
static int get_leaf_nr(struct gfs2_inode *dip, u32 index,
|
|
|
|
u64 *leaf_out)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2011-06-15 16:29:37 +07:00
|
|
|
__be64 *hash;
|
remove lots of IS_ERR_VALUE abuses
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.
However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
Andrzej Hajda has already fixed a lot of the worst abusers that
were causing actual bugs, but it would be nice to prevent any
users that are not passing 'unsigned long' arguments.
This patch changes all users of IS_ERR_VALUE() that I could find
on 32-bit ARM randconfig builds and x86 allmodconfig. For the
moment, this doesn't change the definition of IS_ERR_VALUE()
because there are probably still architecture specific users
elsewhere.
Almost all the warnings I got are for files that are better off
using 'if (err)' or 'if (err < 0)'.
The only legitimate user I could find that we get a warning for
is the (32-bit only) freescale fman driver, so I did not remove
the IS_ERR_VALUE() there but changed the type to 'unsigned long'.
For 9pfs, I just worked around one user whose calling conventions
are so obscure that I did not dare change the behavior.
I was using this definition for testing:
#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
which ends up making all 16-bit or wider types work correctly with
the most plausible interpretation of what IS_ERR_VALUE() was supposed
to return according to its users, but also causes a compile-time
warning for any users that do not pass an 'unsigned long' argument.
I suggested this approach earlier this year, but back then we ended
up deciding to just fix the users that are obviously broken. After
the initial warning that caused me to get involved in the discussion
(fs/gfs2/dir.c) showed up again in the mainline kernel, Linus
asked me to send the whole thing again.
[ Updated the 9p parts as per Al Viro - Linus ]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lkml.org/lkml/2016/1/7/363
Link: https://lkml.org/lkml/2016/5/27/486
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> # For nvmem part
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-05-28 04:23:25 +07:00
|
|
|
int error;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
hash = gfs2_dir_get_hash_table(dip);
|
remove lots of IS_ERR_VALUE abuses
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.
However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
Andrzej Hajda has already fixed a lot of the worst abusers that
were causing actual bugs, but it would be nice to prevent any
users that are not passing 'unsigned long' arguments.
This patch changes all users of IS_ERR_VALUE() that I could find
on 32-bit ARM randconfig builds and x86 allmodconfig. For the
moment, this doesn't change the definition of IS_ERR_VALUE()
because there are probably still architecture specific users
elsewhere.
Almost all the warnings I got are for files that are better off
using 'if (err)' or 'if (err < 0)'.
The only legitimate user I could find that we get a warning for
is the (32-bit only) freescale fman driver, so I did not remove
the IS_ERR_VALUE() there but changed the type to 'unsigned long'.
For 9pfs, I just worked around one user whose calling conventions
are so obscure that I did not dare change the behavior.
I was using this definition for testing:
#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
which ends up making all 16-bit or wider types work correctly with
the most plausible interpretation of what IS_ERR_VALUE() was supposed
to return according to its users, but also causes a compile-time
warning for any users that do not pass an 'unsigned long' argument.
I suggested this approach earlier this year, but back then we ended
up deciding to just fix the users that are obviously broken. After
the initial warning that caused me to get involved in the discussion
(fs/gfs2/dir.c) showed up again in the mainline kernel, Linus
asked me to send the whole thing again.
[ Updated the 9p parts as per Al Viro - Linus ]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lkml.org/lkml/2016/1/7/363
Link: https://lkml.org/lkml/2016/5/27/486
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> # For nvmem part
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-05-28 04:23:25 +07:00
|
|
|
error = PTR_ERR_OR_ZERO(hash);
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
*leaf_out = be64_to_cpu(*(hash + index));
|
|
|
|
|
|
|
|
return error;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
static int get_first_leaf(struct gfs2_inode *dip, u32 index,
|
2006-01-16 23:50:04 +07:00
|
|
|
struct buffer_head **bh_out)
|
|
|
|
{
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 leaf_no;
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
|
|
|
error = get_leaf_nr(dip, index, &leaf_no);
|
remove lots of IS_ERR_VALUE abuses
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.
However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
Andrzej Hajda has already fixed a lot of the worst abusers that
were causing actual bugs, but it would be nice to prevent any
users that are not passing 'unsigned long' arguments.
This patch changes all users of IS_ERR_VALUE() that I could find
on 32-bit ARM randconfig builds and x86 allmodconfig. For the
moment, this doesn't change the definition of IS_ERR_VALUE()
because there are probably still architecture specific users
elsewhere.
Almost all the warnings I got are for files that are better off
using 'if (err)' or 'if (err < 0)'.
The only legitimate user I could find that we get a warning for
is the (32-bit only) freescale fman driver, so I did not remove
the IS_ERR_VALUE() there but changed the type to 'unsigned long'.
For 9pfs, I just worked around one user whose calling conventions
are so obscure that I did not dare change the behavior.
I was using this definition for testing:
#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
which ends up making all 16-bit or wider types work correctly with
the most plausible interpretation of what IS_ERR_VALUE() was supposed
to return according to its users, but also causes a compile-time
warning for any users that do not pass an 'unsigned long' argument.
I suggested this approach earlier this year, but back then we ended
up deciding to just fix the users that are obviously broken. After
the initial warning that caused me to get involved in the discussion
(fs/gfs2/dir.c) showed up again in the mainline kernel, Linus
asked me to send the whole thing again.
[ Updated the 9p parts as per Al Viro - Linus ]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lkml.org/lkml/2016/1/7/363
Link: https://lkml.org/lkml/2016/5/27/486
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> # For nvmem part
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-05-28 04:23:25 +07:00
|
|
|
if (!error)
|
2006-01-16 23:50:04 +07:00
|
|
|
error = get_leaf(dip, leaf_no, bh_out);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
|
|
|
|
const struct qstr *name,
|
|
|
|
gfs2_dscan_t scan,
|
|
|
|
struct buffer_head **pbh)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-03-21 00:30:04 +07:00
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_dirent *dent;
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
2008-11-04 17:05:22 +07:00
|
|
|
if (ip->i_diskflags & GFS2_DIF_EXHASH) {
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *leaf;
|
2016-08-03 00:05:27 +07:00
|
|
|
unsigned int hsize = BIT(ip->i_depth);
|
|
|
|
unsigned int index;
|
2006-03-21 00:30:04 +07:00
|
|
|
u64 ln;
|
2010-08-11 15:53:11 +07:00
|
|
|
if (hsize * sizeof(u64) != i_size_read(inode)) {
|
2006-03-21 00:30:04 +07:00
|
|
|
gfs2_consist_inode(ip);
|
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
}
|
2006-09-25 20:26:04 +07:00
|
|
|
|
2008-02-01 16:23:44 +07:00
|
|
|
index = name->hash >> (32 - ip->i_depth);
|
2006-03-21 00:30:04 +07:00
|
|
|
error = get_first_leaf(ip, index, &bh);
|
|
|
|
if (error)
|
|
|
|
return ERR_PTR(error);
|
|
|
|
do {
|
|
|
|
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
|
2006-03-29 02:14:04 +07:00
|
|
|
scan, name, NULL);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (dent)
|
|
|
|
goto got_dent;
|
|
|
|
leaf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
ln = be64_to_cpu(leaf->lf_next);
|
2006-04-12 01:49:06 +07:00
|
|
|
brelse(bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (!ln)
|
|
|
|
break;
|
2006-09-25 20:26:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
error = get_leaf(ip, ln, &bh);
|
|
|
|
} while(!error);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
return error ? ERR_PTR(error) : NULL;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2006-09-25 20:26:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
error = gfs2_meta_inode_buffer(ip, &bh);
|
|
|
|
if (error)
|
|
|
|
return ERR_PTR(error);
|
2006-03-29 02:14:04 +07:00
|
|
|
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);
|
2006-03-21 00:30:04 +07:00
|
|
|
got_dent:
|
2019-06-05 21:24:24 +07:00
|
|
|
if (IS_ERR_OR_NULL(dent)) {
|
2006-04-08 03:28:07 +07:00
|
|
|
brelse(bh);
|
|
|
|
bh = NULL;
|
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
*pbh = bh;
|
|
|
|
return dent;
|
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
|
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2008-02-06 17:11:15 +07:00
|
|
|
unsigned int n = 1;
|
2009-05-20 16:48:47 +07:00
|
|
|
u64 bn;
|
|
|
|
int error;
|
|
|
|
struct buffer_head *bh;
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *leaf;
|
|
|
|
struct gfs2_dirent *dent;
|
vfs: change inode times to use struct timespec64
struct timespec is not y2038 safe. Transition vfs to use
y2038 safe struct timespec64 instead.
The change was made with the help of the following cocinelle
script. This catches about 80% of the changes.
All the header file and logic changes are included in the
first 5 rules. The rest are trivial substitutions.
I avoid changing any of the function signatures or any other
filesystem specific data structures to keep the patch simple
for review.
The script can be a little shorter by combining different cases.
But, this version was sufficient for my usecase.
virtual patch
@ depends on patch @
identifier now;
@@
- struct timespec
+ struct timespec64
current_time ( ... )
{
- struct timespec now = current_kernel_time();
+ struct timespec64 now = current_kernel_time64();
...
- return timespec_trunc(
+ return timespec64_trunc(
... );
}
@ depends on patch @
identifier xtime;
@@
struct \( iattr \| inode \| kstat \) {
...
- struct timespec xtime;
+ struct timespec64 xtime;
...
}
@ depends on patch @
identifier t;
@@
struct inode_operations {
...
int (*update_time) (...,
- struct timespec t,
+ struct timespec64 t,
...);
...
}
@ depends on patch @
identifier t;
identifier fn_update_time =~ "update_time$";
@@
fn_update_time (...,
- struct timespec *t,
+ struct timespec64 *t,
...) { ... }
@ depends on patch @
identifier t;
@@
lease_get_mtime( ... ,
- struct timespec *t
+ struct timespec64 *t
) { ... }
@te depends on patch forall@
identifier ts;
local idexpression struct inode *inode_node;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn_update_time =~ "update_time$";
identifier fn;
expression e, E3;
local idexpression struct inode *node1;
local idexpression struct inode *node2;
local idexpression struct iattr *attr1;
local idexpression struct iattr *attr2;
local idexpression struct iattr attr;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
@@
(
(
- struct timespec ts;
+ struct timespec64 ts;
|
- struct timespec ts = current_time(inode_node);
+ struct timespec64 ts = current_time(inode_node);
)
<+... when != ts
(
- timespec_equal(&inode_node->i_xtime, &ts)
+ timespec64_equal(&inode_node->i_xtime, &ts)
|
- timespec_equal(&ts, &inode_node->i_xtime)
+ timespec64_equal(&ts, &inode_node->i_xtime)
|
- timespec_compare(&inode_node->i_xtime, &ts)
+ timespec64_compare(&inode_node->i_xtime, &ts)
|
- timespec_compare(&ts, &inode_node->i_xtime)
+ timespec64_compare(&ts, &inode_node->i_xtime)
|
ts = current_time(e)
|
fn_update_time(..., &ts,...)
|
inode_node->i_xtime = ts
|
node1->i_xtime = ts
|
ts = inode_node->i_xtime
|
<+... attr1->ia_xtime ...+> = ts
|
ts = attr1->ia_xtime
|
ts.tv_sec
|
ts.tv_nsec
|
btrfs_set_stack_timespec_sec(..., ts.tv_sec)
|
btrfs_set_stack_timespec_nsec(..., ts.tv_nsec)
|
- ts = timespec64_to_timespec(
+ ts =
...
-)
|
- ts = ktime_to_timespec(
+ ts = ktime_to_timespec64(
...)
|
- ts = E3
+ ts = timespec_to_timespec64(E3)
|
- ktime_get_real_ts(&ts)
+ ktime_get_real_ts64(&ts)
|
fn(...,
- ts
+ timespec64_to_timespec(ts)
,...)
)
...+>
(
<... when != ts
- return ts;
+ return timespec64_to_timespec(ts);
...>
)
|
- timespec_equal(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_equal(&node1->i_xtime2, &node2->i_xtime2)
|
- timespec_equal(&node1->i_xtime1, &attr2->ia_xtime2)
+ timespec64_equal(&node1->i_xtime2, &attr2->ia_xtime2)
|
- timespec_compare(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_compare(&node1->i_xtime1, &node2->i_xtime2)
|
node1->i_xtime1 =
- timespec_trunc(attr1->ia_xtime1,
+ timespec64_trunc(attr1->ia_xtime1,
...)
|
- attr1->ia_xtime1 = timespec_trunc(attr2->ia_xtime2,
+ attr1->ia_xtime1 = timespec64_trunc(attr2->ia_xtime2,
...)
|
- ktime_get_real_ts(&attr1->ia_xtime1)
+ ktime_get_real_ts64(&attr1->ia_xtime1)
|
- ktime_get_real_ts(&attr.ia_xtime1)
+ ktime_get_real_ts64(&attr.ia_xtime1)
)
@ depends on patch @
struct inode *node;
struct iattr *attr;
identifier fn;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
expression e;
@@
(
- fn(node->i_xtime);
+ fn(timespec64_to_timespec(node->i_xtime));
|
fn(...,
- node->i_xtime);
+ timespec64_to_timespec(node->i_xtime));
|
- e = fn(attr->ia_xtime);
+ e = fn(timespec64_to_timespec(attr->ia_xtime));
)
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
fn (...,
- &attr->ia_xtime,
+ &ts,
...);
)
...+>
}
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
struct kstat *stat;
identifier ia_xtime =~ "^ia_[acm]time$";
identifier i_xtime =~ "^i_[acm]time$";
identifier xtime =~ "^[acm]time$";
identifier fn, ret;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(stat->xtime);
ret = fn (...,
- &stat->xtime);
+ &ts);
)
...+>
}
@ depends on patch @
struct inode *node;
struct inode *node2;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier i_xtime3 =~ "^i_[acm]time$";
struct iattr *attrp;
struct iattr *attrp2;
struct iattr attr ;
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
struct kstat *stat;
struct kstat stat1;
struct timespec64 ts;
identifier xtime =~ "^[acmb]time$";
expression e;
@@
(
( node->i_xtime2 \| attrp->ia_xtime2 \| attr.ia_xtime2 \) = node->i_xtime1 ;
|
node->i_xtime2 = \( node2->i_xtime1 \| timespec64_trunc(...) \);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
stat->xtime = node2->i_xtime1;
|
stat1.xtime = node2->i_xtime1;
|
( node->i_xtime2 \| attrp->ia_xtime2 \) = attrp->ia_xtime1 ;
|
( attrp->ia_xtime1 \| attr.ia_xtime1 \) = attrp2->ia_xtime2;
|
- e = node->i_xtime1;
+ e = timespec64_to_timespec( node->i_xtime1 );
|
- e = attrp->ia_xtime1;
+ e = timespec64_to_timespec( attrp->ia_xtime1 );
|
node->i_xtime1 = current_time(...);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
- node->i_xtime1 = e;
+ node->i_xtime1 = timespec_to_timespec64(e);
)
Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Cc: <anton@tuxera.com>
Cc: <balbi@kernel.org>
Cc: <bfields@fieldses.org>
Cc: <darrick.wong@oracle.com>
Cc: <dhowells@redhat.com>
Cc: <dsterba@suse.com>
Cc: <dwmw2@infradead.org>
Cc: <hch@lst.de>
Cc: <hirofumi@mail.parknet.co.jp>
Cc: <hubcap@omnibond.com>
Cc: <jack@suse.com>
Cc: <jaegeuk@kernel.org>
Cc: <jaharkes@cs.cmu.edu>
Cc: <jslaby@suse.com>
Cc: <keescook@chromium.org>
Cc: <mark@fasheh.com>
Cc: <miklos@szeredi.hu>
Cc: <nico@linaro.org>
Cc: <reiserfs-devel@vger.kernel.org>
Cc: <richard@nod.at>
Cc: <sage@redhat.com>
Cc: <sfrench@samba.org>
Cc: <swhiteho@redhat.com>
Cc: <tj@kernel.org>
Cc: <trond.myklebust@primarydata.com>
Cc: <tytso@mit.edu>
Cc: <viro@zeniv.linux.org.uk>
2018-05-09 09:36:02 +07:00
|
|
|
struct timespec64 tv = current_time(inode);
|
2009-05-20 16:48:47 +07:00
|
|
|
|
2011-11-18 22:58:32 +07:00
|
|
|
error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
|
2009-05-20 16:48:47 +07:00
|
|
|
if (error)
|
|
|
|
return NULL;
|
|
|
|
bh = gfs2_meta_new(ip->i_gl, bn);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (!bh)
|
|
|
|
return NULL;
|
2009-05-20 16:48:47 +07:00
|
|
|
|
2019-04-05 18:18:23 +07:00
|
|
|
gfs2_trans_remove_revoke(GFS2_SB(inode), bn, 1);
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
|
|
|
|
leaf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
leaf->lf_depth = cpu_to_be16(depth);
|
2006-09-05 20:34:20 +07:00
|
|
|
leaf->lf_entries = 0;
|
2006-10-14 22:49:30 +07:00
|
|
|
leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
|
2006-09-05 20:34:20 +07:00
|
|
|
leaf->lf_next = 0;
|
2014-01-08 19:14:57 +07:00
|
|
|
leaf->lf_inode = cpu_to_be64(ip->i_no_addr);
|
|
|
|
leaf->lf_dist = cpu_to_be32(1);
|
|
|
|
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
|
|
|
|
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
|
|
|
|
memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2));
|
2006-03-21 00:30:04 +07:00
|
|
|
dent = (struct gfs2_dirent *)(leaf+1);
|
2017-07-04 23:25:22 +07:00
|
|
|
gfs2_qstr2dirent(&empty_name, bh->b_size - sizeof(struct gfs2_leaf), dent);
|
2006-03-21 00:30:04 +07:00
|
|
|
*pbh = bh;
|
|
|
|
return leaf;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* dir_make_exhash - Convert a stuffed directory into an ExHash directory
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code otherwise
|
|
|
|
*/
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static int dir_make_exhash(struct inode *inode)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *dip = GFS2_I(inode);
|
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
2006-01-16 23:50:04 +07:00
|
|
|
struct gfs2_dirent *dent;
|
2006-03-21 00:30:04 +07:00
|
|
|
struct qstr args;
|
2006-01-16 23:50:04 +07:00
|
|
|
struct buffer_head *bh, *dibh;
|
|
|
|
struct gfs2_leaf *leaf;
|
|
|
|
int y;
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 x;
|
2006-10-14 21:46:30 +07:00
|
|
|
__be64 *lp;
|
|
|
|
u64 bn;
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(dip, &dibh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
/* Turn over a new leaf */
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
leaf = new_leaf(inode, &bh, 0);
|
|
|
|
if (!leaf)
|
|
|
|
return -ENOSPC;
|
|
|
|
bn = bh->b_blocknr;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
gfs2_assert(sdp, dip->i_entries < BIT(16));
|
2008-11-03 20:59:19 +07:00
|
|
|
leaf->lf_entries = cpu_to_be16(dip->i_entries);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
/* Copy dirents */
|
|
|
|
|
|
|
|
gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh,
|
|
|
|
sizeof(struct gfs2_dinode));
|
|
|
|
|
|
|
|
/* Find last entry */
|
|
|
|
|
|
|
|
x = 0;
|
2006-03-21 00:30:04 +07:00
|
|
|
args.len = bh->b_size - sizeof(struct gfs2_dinode) +
|
|
|
|
sizeof(struct gfs2_leaf);
|
|
|
|
args.name = bh->b_data;
|
2006-06-15 02:32:57 +07:00
|
|
|
dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size,
|
2006-03-29 02:14:04 +07:00
|
|
|
gfs2_dirent_last, &args, NULL);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (!dent) {
|
|
|
|
brelse(bh);
|
|
|
|
brelse(dibh);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
if (IS_ERR(dent)) {
|
|
|
|
brelse(bh);
|
|
|
|
brelse(dibh);
|
|
|
|
return PTR_ERR(dent);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust the last dirent's record length
|
|
|
|
(Remember that dent still points to the last entry.) */
|
|
|
|
|
2006-02-14 22:56:44 +07:00
|
|
|
dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) +
|
2006-01-16 23:50:04 +07:00
|
|
|
sizeof(struct gfs2_dinode) -
|
2006-02-14 22:56:44 +07:00
|
|
|
sizeof(struct gfs2_leaf));
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
brelse(bh);
|
|
|
|
|
|
|
|
/* We're done with the new leaf block, now setup the new
|
|
|
|
hash table. */
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, dibh);
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
|
|
|
|
|
2006-10-14 21:46:30 +07:00
|
|
|
lp = (__be64 *)(dibh->b_data + sizeof(struct gfs2_dinode));
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
for (x = sdp->sd_hash_ptrs; x--; lp++)
|
|
|
|
*lp = cpu_to_be64(bn);
|
|
|
|
|
2010-08-11 15:53:11 +07:00
|
|
|
i_size_write(inode, sdp->sd_sb.sb_bsize / 2);
|
2008-02-12 21:17:27 +07:00
|
|
|
gfs2_add_inode_blocks(&dip->i_inode, 1);
|
2008-11-04 17:05:22 +07:00
|
|
|
dip->i_diskflags |= GFS2_DIF_EXHASH;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
|
2008-02-01 16:23:44 +07:00
|
|
|
dip->i_depth = y;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(dip, dibh->b_data);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
brelse(dibh);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* dir_split_leaf - Split a leaf block into two
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
* @index:
|
|
|
|
* @leaf_no:
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code on failure
|
|
|
|
*/
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static int dir_split_leaf(struct inode *inode, const struct qstr *name)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *dip = GFS2_I(inode);
|
2006-01-16 23:50:04 +07:00
|
|
|
struct buffer_head *nbh, *obh, *dibh;
|
|
|
|
struct gfs2_leaf *nleaf, *oleaf;
|
2006-07-12 00:19:13 +07:00
|
|
|
struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new;
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 start, len, half_len, divider;
|
2006-10-14 21:46:30 +07:00
|
|
|
u64 bn, leaf_no;
|
|
|
|
__be64 *lp;
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 index;
|
2018-07-17 21:59:28 +07:00
|
|
|
int x;
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
2008-02-01 16:23:44 +07:00
|
|
|
index = name->hash >> (32 - dip->i_depth);
|
2006-03-21 00:30:04 +07:00
|
|
|
error = get_leaf_nr(dip, index, &leaf_no);
|
remove lots of IS_ERR_VALUE abuses
Most users of IS_ERR_VALUE() in the kernel are wrong, as they
pass an 'int' into a function that takes an 'unsigned long'
argument. This happens to work because the type is sign-extended
on 64-bit architectures before it gets converted into an
unsigned type.
However, anything that passes an 'unsigned short' or 'unsigned int'
argument into IS_ERR_VALUE() is guaranteed to be broken, as are
8-bit integers and types that are wider than 'unsigned long'.
Andrzej Hajda has already fixed a lot of the worst abusers that
were causing actual bugs, but it would be nice to prevent any
users that are not passing 'unsigned long' arguments.
This patch changes all users of IS_ERR_VALUE() that I could find
on 32-bit ARM randconfig builds and x86 allmodconfig. For the
moment, this doesn't change the definition of IS_ERR_VALUE()
because there are probably still architecture specific users
elsewhere.
Almost all the warnings I got are for files that are better off
using 'if (err)' or 'if (err < 0)'.
The only legitimate user I could find that we get a warning for
is the (32-bit only) freescale fman driver, so I did not remove
the IS_ERR_VALUE() there but changed the type to 'unsigned long'.
For 9pfs, I just worked around one user whose calling conventions
are so obscure that I did not dare change the behavior.
I was using this definition for testing:
#define IS_ERR_VALUE(x) ((unsigned long*)NULL == (typeof (x)*)NULL && \
unlikely((unsigned long long)(x) >= (unsigned long long)(typeof(x))-MAX_ERRNO))
which ends up making all 16-bit or wider types work correctly with
the most plausible interpretation of what IS_ERR_VALUE() was supposed
to return according to its users, but also causes a compile-time
warning for any users that do not pass an 'unsigned long' argument.
I suggested this approach earlier this year, but back then we ended
up deciding to just fix the users that are obviously broken. After
the initial warning that caused me to get involved in the discussion
(fs/gfs2/dir.c) showed up again in the mainline kernel, Linus
asked me to send the whole thing again.
[ Updated the 9p parts as per Al Viro - Linus ]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Andrzej Hajda <a.hajda@samsung.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: https://lkml.org/lkml/2016/1/7/363
Link: https://lkml.org/lkml/2016/5/27/486
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> # For nvmem part
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-05-28 04:23:25 +07:00
|
|
|
if (error)
|
2006-03-21 00:30:04 +07:00
|
|
|
return error;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
/* Get the old leaf block */
|
|
|
|
error = get_leaf(dip, leaf_no, &obh);
|
|
|
|
if (error)
|
2006-03-30 07:02:15 +07:00
|
|
|
return error;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
oleaf = (struct gfs2_leaf *)obh->b_data;
|
2008-02-01 16:23:44 +07:00
|
|
|
if (dip->i_depth == be16_to_cpu(oleaf->lf_depth)) {
|
2006-03-30 07:02:15 +07:00
|
|
|
brelse(obh);
|
|
|
|
return 1; /* can't split */
|
|
|
|
}
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, obh);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1);
|
|
|
|
if (!nleaf) {
|
|
|
|
brelse(obh);
|
|
|
|
return -ENOSPC;
|
|
|
|
}
|
|
|
|
bn = nbh->b_blocknr;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
/* Compute the start and len of leaf pointers in the hash table. */
|
2016-08-03 00:05:27 +07:00
|
|
|
len = BIT(dip->i_depth - be16_to_cpu(oleaf->lf_depth));
|
2006-01-16 23:50:04 +07:00
|
|
|
half_len = len >> 1;
|
|
|
|
if (!half_len) {
|
2018-10-03 20:47:36 +07:00
|
|
|
fs_warn(GFS2_SB(inode), "i_depth %u lf_depth %u index %u\n",
|
2014-03-07 03:10:45 +07:00
|
|
|
dip->i_depth, be16_to_cpu(oleaf->lf_depth), index);
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
error = -EIO;
|
|
|
|
goto fail_brelse;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = (index & ~(len - 1));
|
|
|
|
|
|
|
|
/* Change the pointers.
|
|
|
|
Don't bother distinguishing stuffed from non-stuffed.
|
|
|
|
This code is complicated enough already. */
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 03:55:00 +07:00
|
|
|
lp = kmalloc_array(half_len, sizeof(__be64), GFP_NOFS);
|
2010-07-21 09:45:03 +07:00
|
|
|
if (!lp) {
|
|
|
|
error = -ENOMEM;
|
|
|
|
goto fail_brelse;
|
|
|
|
}
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/* Change the pointers */
|
|
|
|
for (x = 0; x < half_len; x++)
|
|
|
|
lp[x] = cpu_to_be64(bn);
|
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
gfs2_dir_hash_inval(dip);
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64),
|
|
|
|
half_len * sizeof(u64));
|
|
|
|
if (error != half_len * sizeof(u64)) {
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error >= 0)
|
|
|
|
error = -EIO;
|
|
|
|
goto fail_lpfree;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(lp);
|
|
|
|
|
|
|
|
/* Compute the divider */
|
2008-02-01 16:23:44 +07:00
|
|
|
divider = (start + half_len) << (32 - dip->i_depth);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
/* Copy the entries */
|
2009-11-06 18:06:37 +07:00
|
|
|
dent = (struct gfs2_dirent *)(obh->b_data + sizeof(struct gfs2_leaf));
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
do {
|
|
|
|
next = dent;
|
|
|
|
if (dirent_next(dip, obh, &next))
|
|
|
|
next = NULL;
|
|
|
|
|
2006-11-18 00:27:44 +07:00
|
|
|
if (!gfs2_dirent_sentinel(dent) &&
|
2006-01-16 23:50:04 +07:00
|
|
|
be32_to_cpu(dent->de_hash) < divider) {
|
2006-03-21 00:30:04 +07:00
|
|
|
struct qstr str;
|
2015-12-01 21:30:34 +07:00
|
|
|
void *ptr = ((char *)dent - obh->b_data) + nbh->b_data;
|
2006-03-21 00:30:04 +07:00
|
|
|
str.name = (char*)(dent+1);
|
|
|
|
str.len = be16_to_cpu(dent->de_name_len);
|
|
|
|
str.hash = be32_to_cpu(dent->de_hash);
|
2015-12-01 21:30:34 +07:00
|
|
|
new = gfs2_dirent_split_alloc(inode, nbh, &str, ptr);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (IS_ERR(new)) {
|
|
|
|
error = PTR_ERR(new);
|
|
|
|
break;
|
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
new->de_inum = dent->de_inum; /* No endian worries */
|
|
|
|
new->de_type = dent->de_type; /* No endian worries */
|
2008-02-13 06:06:10 +07:00
|
|
|
be16_add_cpu(&nleaf->lf_entries, 1);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
dirent_del(dip, obh, prev, dent);
|
|
|
|
|
|
|
|
if (!oleaf->lf_entries)
|
|
|
|
gfs2_consist_inode(dip);
|
2008-02-13 06:06:10 +07:00
|
|
|
be16_add_cpu(&oleaf->lf_entries, -1);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
if (!prev)
|
|
|
|
prev = dent;
|
2006-03-21 00:30:04 +07:00
|
|
|
} else {
|
2006-01-16 23:50:04 +07:00
|
|
|
prev = dent;
|
2006-03-21 00:30:04 +07:00
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
dent = next;
|
2006-03-21 00:30:04 +07:00
|
|
|
} while (dent);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
oleaf->lf_depth = nleaf->lf_depth;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(dip, &dibh);
|
2006-06-15 02:32:57 +07:00
|
|
|
if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, dibh);
|
2008-02-12 21:17:27 +07:00
|
|
|
gfs2_add_inode_blocks(&dip->i_inode, 1);
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(dip, dibh->b_data);
|
2006-01-16 23:50:04 +07:00
|
|
|
brelse(dibh);
|
|
|
|
}
|
|
|
|
|
|
|
|
brelse(obh);
|
|
|
|
brelse(nbh);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
2006-03-30 07:02:15 +07:00
|
|
|
fail_lpfree:
|
2006-01-16 23:50:04 +07:00
|
|
|
kfree(lp);
|
|
|
|
|
2006-03-30 07:02:15 +07:00
|
|
|
fail_brelse:
|
2006-01-16 23:50:04 +07:00
|
|
|
brelse(obh);
|
|
|
|
brelse(nbh);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* dir_double_exhash - Double size of ExHash table
|
|
|
|
* @dip: The GFS2 dinode
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code on failure
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int dir_double_exhash(struct gfs2_inode *dip)
|
|
|
|
{
|
|
|
|
struct buffer_head *dibh;
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 hsize;
|
2011-06-15 16:29:37 +07:00
|
|
|
u32 hsize_bytes;
|
|
|
|
__be64 *hc;
|
|
|
|
__be64 *hc2, *h;
|
2006-01-16 23:50:04 +07:00
|
|
|
int x;
|
|
|
|
int error = 0;
|
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
hsize = BIT(dip->i_depth);
|
2011-06-15 16:29:37 +07:00
|
|
|
hsize_bytes = hsize * sizeof(__be64);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
hc = gfs2_dir_get_hash_table(dip);
|
|
|
|
if (IS_ERR(hc))
|
|
|
|
return PTR_ERR(hc);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 03:55:00 +07:00
|
|
|
hc2 = kmalloc_array(hsize_bytes, 2, GFP_NOFS | __GFP_NOWARN);
|
2013-05-30 20:48:56 +07:00
|
|
|
if (hc2 == NULL)
|
|
|
|
hc2 = __vmalloc(hsize_bytes * 2, GFP_NOFS, PAGE_KERNEL);
|
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
if (!hc2)
|
2010-07-21 09:45:03 +07:00
|
|
|
return -ENOMEM;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2013-06-14 19:39:18 +07:00
|
|
|
h = hc2;
|
2011-06-15 16:29:37 +07:00
|
|
|
error = gfs2_meta_inode_buffer(dip, &dibh);
|
|
|
|
if (error)
|
|
|
|
goto out_kfree;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
for (x = 0; x < hsize; x++) {
|
|
|
|
*h++ = *hc;
|
|
|
|
*h++ = *hc;
|
|
|
|
hc++;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
error = gfs2_dir_write_data(dip, (char *)hc2, 0, hsize_bytes * 2);
|
|
|
|
if (error != (hsize_bytes * 2))
|
|
|
|
goto fail;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
gfs2_dir_hash_inval(dip);
|
|
|
|
dip->i_hash_cache = hc2;
|
|
|
|
dip->i_depth++;
|
|
|
|
gfs2_dinode_out(dip, dibh->b_data);
|
|
|
|
brelse(dibh);
|
|
|
|
return 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-09-04 23:04:26 +07:00
|
|
|
fail:
|
2011-06-15 16:29:37 +07:00
|
|
|
/* Replace original hash table & size */
|
|
|
|
gfs2_dir_write_data(dip, (char *)hc, 0, hsize_bytes);
|
|
|
|
i_size_write(&dip->i_inode, hsize_bytes);
|
|
|
|
gfs2_dinode_out(dip, dibh->b_data);
|
|
|
|
brelse(dibh);
|
|
|
|
out_kfree:
|
2014-11-20 12:18:38 +07:00
|
|
|
kvfree(hc2);
|
2006-01-16 23:50:04 +07:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* compare_dents - compare directory entries by hash value
|
|
|
|
* @a: first dent
|
|
|
|
* @b: second dent
|
|
|
|
*
|
|
|
|
* When comparing the hash entries of @a to @b:
|
|
|
|
* gt: returns 1
|
|
|
|
* lt: returns -1
|
|
|
|
* eq: returns 0
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int compare_dents(const void *a, const void *b)
|
|
|
|
{
|
2006-09-05 20:34:20 +07:00
|
|
|
const struct gfs2_dirent *dent_a, *dent_b;
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 hash_a, hash_b;
|
2006-01-16 23:50:04 +07:00
|
|
|
int ret = 0;
|
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
dent_a = *(const struct gfs2_dirent **)a;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
hash_a = dent_a->de_cookie;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-09-05 20:34:20 +07:00
|
|
|
dent_b = *(const struct gfs2_dirent **)b;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
hash_b = dent_b->de_cookie;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
if (hash_a > hash_b)
|
|
|
|
ret = 1;
|
|
|
|
else if (hash_a < hash_b)
|
|
|
|
ret = -1;
|
|
|
|
else {
|
2006-02-14 22:56:44 +07:00
|
|
|
unsigned int len_a = be16_to_cpu(dent_a->de_name_len);
|
|
|
|
unsigned int len_b = be16_to_cpu(dent_b->de_name_len);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
if (len_a > len_b)
|
|
|
|
ret = 1;
|
|
|
|
else if (len_a < len_b)
|
|
|
|
ret = -1;
|
|
|
|
else
|
2006-09-05 20:34:20 +07:00
|
|
|
ret = memcmp(dent_a + 1, dent_b + 1, len_a);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* do_filldir_main - read out directory entries
|
|
|
|
* @dip: The GFS2 inode
|
2013-05-17 01:14:48 +07:00
|
|
|
* @ctx: what to feed the entries to
|
2006-01-16 23:50:04 +07:00
|
|
|
* @darr: an array of struct gfs2_dirent pointers to read
|
|
|
|
* @entries: the number of entries in darr
|
|
|
|
* @copied: pointer to int that's non-zero if a entry has been copied out
|
|
|
|
*
|
|
|
|
* Jump through some hoops to make sure that if there are hash collsions,
|
|
|
|
* they are read out at the beginning of a buffer. We want to minimize
|
|
|
|
* the possibility that they will fall into different readdir buffers or
|
|
|
|
* that someone will want to seek to that location.
|
|
|
|
*
|
2013-05-17 01:14:48 +07:00
|
|
|
* Returns: errno, >0 if the actor tells you to stop
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
static int do_filldir_main(struct gfs2_inode *dip, struct dir_context *ctx,
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
struct gfs2_dirent **darr, u32 entries,
|
|
|
|
u32 sort_start, int *copied)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-03-29 02:14:04 +07:00
|
|
|
const struct gfs2_dirent *dent, *dent_next;
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 off, off_next;
|
2006-01-16 23:50:04 +07:00
|
|
|
unsigned int x, y;
|
|
|
|
int run = 0;
|
|
|
|
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
if (sort_start < entries)
|
|
|
|
sort(&darr[sort_start], entries - sort_start,
|
|
|
|
sizeof(struct gfs2_dirent *), compare_dents, NULL);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
dent_next = darr[0];
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
off_next = dent_next->de_cookie;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
for (x = 0, y = 1; x < entries; x++, y++) {
|
|
|
|
dent = dent_next;
|
|
|
|
off = off_next;
|
|
|
|
|
|
|
|
if (y < entries) {
|
|
|
|
dent_next = darr[y];
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
off_next = dent_next->de_cookie;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
if (off < ctx->pos)
|
2006-01-16 23:50:04 +07:00
|
|
|
continue;
|
2013-05-17 01:14:48 +07:00
|
|
|
ctx->pos = off;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
if (off_next == off) {
|
|
|
|
if (*copied && !run)
|
|
|
|
return 1;
|
|
|
|
run = 1;
|
|
|
|
} else
|
|
|
|
run = 0;
|
|
|
|
} else {
|
2013-05-17 01:14:48 +07:00
|
|
|
if (off < ctx->pos)
|
2006-01-16 23:50:04 +07:00
|
|
|
continue;
|
2013-05-17 01:14:48 +07:00
|
|
|
ctx->pos = off;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
if (!dir_emit(ctx, (const char *)(dent + 1),
|
2006-02-14 22:56:44 +07:00
|
|
|
be16_to_cpu(dent->de_name_len),
|
2013-05-17 01:14:48 +07:00
|
|
|
be64_to_cpu(dent->de_inum.no_addr),
|
|
|
|
be16_to_cpu(dent->de_type)))
|
2006-01-16 23:50:04 +07:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
*copied = 1;
|
|
|
|
}
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
/* Increment the ctx->pos by one, so the next time we come into the
|
2006-01-16 23:50:04 +07:00
|
|
|
do_filldir fxn, we get the next entry instead of the last one in the
|
|
|
|
current leaf */
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
ctx->pos++;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-28 23:56:23 +07:00
|
|
|
static void *gfs2_alloc_sort_buffer(unsigned size)
|
|
|
|
{
|
|
|
|
void *ptr = NULL;
|
|
|
|
|
|
|
|
if (size < KMALLOC_MAX_SIZE)
|
|
|
|
ptr = kmalloc(size, GFP_NOFS | __GFP_NOWARN);
|
|
|
|
if (!ptr)
|
|
|
|
ptr = __vmalloc(size, GFP_NOFS, PAGE_KERNEL);
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
|
|
|
|
static int gfs2_set_cookies(struct gfs2_sbd *sdp, struct buffer_head *bh,
|
|
|
|
unsigned leaf_nr, struct gfs2_dirent **darr,
|
|
|
|
unsigned entries)
|
|
|
|
{
|
|
|
|
int sort_id = -1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < entries; i++) {
|
|
|
|
unsigned offset;
|
|
|
|
|
|
|
|
darr[i]->de_cookie = be32_to_cpu(darr[i]->de_hash);
|
|
|
|
darr[i]->de_cookie = gfs2_disk_hash2offset(darr[i]->de_cookie);
|
|
|
|
|
|
|
|
if (!sdp->sd_args.ar_loccookie)
|
|
|
|
continue;
|
|
|
|
offset = (char *)(darr[i]) -
|
2018-10-03 20:47:36 +07:00
|
|
|
(bh->b_data + gfs2_dirent_offset(sdp, bh->b_data));
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
offset /= GFS2_MIN_DIRENT_SIZE;
|
|
|
|
offset += leaf_nr * sdp->sd_max_dents_per_leaf;
|
|
|
|
if (offset >= GFS2_USE_HASH_FLAG ||
|
|
|
|
leaf_nr >= GFS2_USE_HASH_FLAG) {
|
|
|
|
darr[i]->de_cookie |= GFS2_USE_HASH_FLAG;
|
|
|
|
if (sort_id < 0)
|
|
|
|
sort_id = i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
darr[i]->de_cookie &= GFS2_HASH_INDEX_MASK;
|
|
|
|
darr[i]->de_cookie |= offset;
|
|
|
|
}
|
|
|
|
return sort_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
|
|
|
|
int *copied, unsigned *depth,
|
2007-01-17 22:09:20 +07:00
|
|
|
u64 leaf_no)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2007-04-18 15:38:42 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
2006-03-29 02:14:04 +07:00
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_leaf *lf;
|
2007-04-18 15:38:42 +07:00
|
|
|
unsigned entries = 0, entries2 = 0;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
unsigned leaves = 0, leaf = 0, offset, sort_offset;
|
|
|
|
struct gfs2_dirent **darr, *dent;
|
2006-03-29 02:14:04 +07:00
|
|
|
struct dirent_gather g;
|
|
|
|
struct buffer_head **larr;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
int error, i, need_sort = 0, sort_id;
|
2006-03-29 02:14:04 +07:00
|
|
|
u64 lfn = leaf_no;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
do {
|
2006-03-29 02:14:04 +07:00
|
|
|
error = get_leaf(ip, lfn, &bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error)
|
2006-03-29 02:14:04 +07:00
|
|
|
goto out;
|
|
|
|
lf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
if (leaves == 0)
|
|
|
|
*depth = be16_to_cpu(lf->lf_depth);
|
|
|
|
entries += be16_to_cpu(lf->lf_entries);
|
|
|
|
leaves++;
|
|
|
|
lfn = be64_to_cpu(lf->lf_next);
|
|
|
|
brelse(bh);
|
|
|
|
} while(lfn);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
if (*depth < GFS2_DIR_MAX_DEPTH || !sdp->sd_args.ar_loccookie) {
|
|
|
|
need_sort = 1;
|
|
|
|
sort_offset = 0;
|
|
|
|
}
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
if (!entries)
|
|
|
|
return 0;
|
|
|
|
|
2006-03-29 02:14:04 +07:00
|
|
|
error = -ENOMEM;
|
2007-04-18 15:38:42 +07:00
|
|
|
/*
|
|
|
|
* The extra 99 entries are not normally used, but are a buffer
|
|
|
|
* zone in case the number of entries in the leaf is corrupt.
|
|
|
|
* 99 is the maximum number of entries that can fit in a single
|
|
|
|
* leaf block.
|
|
|
|
*/
|
2010-07-28 23:56:23 +07:00
|
|
|
larr = gfs2_alloc_sort_buffer((leaves + entries + 99) * sizeof(void *));
|
2006-03-29 02:14:04 +07:00
|
|
|
if (!larr)
|
|
|
|
goto out;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
darr = (struct gfs2_dirent **)(larr + leaves);
|
|
|
|
g.pdent = (const struct gfs2_dirent **)darr;
|
2006-03-29 02:14:04 +07:00
|
|
|
g.offset = 0;
|
|
|
|
lfn = leaf_no;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-29 02:14:04 +07:00
|
|
|
do {
|
|
|
|
error = get_leaf(ip, lfn, &bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error)
|
2010-07-28 23:56:23 +07:00
|
|
|
goto out_free;
|
2006-03-29 02:14:04 +07:00
|
|
|
lf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
lfn = be64_to_cpu(lf->lf_next);
|
|
|
|
if (lf->lf_entries) {
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
offset = g.offset;
|
2007-04-18 15:38:42 +07:00
|
|
|
entries2 += be16_to_cpu(lf->lf_entries);
|
2006-03-29 02:14:04 +07:00
|
|
|
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
|
|
|
|
gfs2_dirent_gather, NULL, &g);
|
|
|
|
error = PTR_ERR(dent);
|
2007-04-18 15:38:42 +07:00
|
|
|
if (IS_ERR(dent))
|
2010-07-28 23:56:23 +07:00
|
|
|
goto out_free;
|
2007-04-18 15:38:42 +07:00
|
|
|
if (entries2 != g.offset) {
|
2007-04-26 11:08:02 +07:00
|
|
|
fs_warn(sdp, "Number of entries corrupt in dir "
|
|
|
|
"leaf %llu, entries2 (%u) != "
|
|
|
|
"g.offset (%u)\n",
|
|
|
|
(unsigned long long)bh->b_blocknr,
|
|
|
|
entries2, g.offset);
|
2017-05-26 20:28:56 +07:00
|
|
|
gfs2_consist_inode(ip);
|
2007-04-18 15:38:42 +07:00
|
|
|
error = -EIO;
|
2010-07-28 23:56:23 +07:00
|
|
|
goto out_free;
|
2006-03-29 02:14:04 +07:00
|
|
|
}
|
|
|
|
error = 0;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
sort_id = gfs2_set_cookies(sdp, bh, leaf, &darr[offset],
|
|
|
|
be16_to_cpu(lf->lf_entries));
|
|
|
|
if (!need_sort && sort_id >= 0) {
|
|
|
|
need_sort = 1;
|
|
|
|
sort_offset = offset + sort_id;
|
|
|
|
}
|
2006-03-29 02:14:04 +07:00
|
|
|
larr[leaf++] = bh;
|
2006-01-16 23:50:04 +07:00
|
|
|
} else {
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
larr[leaf++] = NULL;
|
2006-03-29 02:14:04 +07:00
|
|
|
brelse(bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
2006-03-29 02:14:04 +07:00
|
|
|
} while(lfn);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2007-04-18 15:38:42 +07:00
|
|
|
BUG_ON(entries2 != entries);
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
error = do_filldir_main(ip, ctx, darr, entries, need_sort ?
|
|
|
|
sort_offset : entries, copied);
|
2010-07-28 23:56:23 +07:00
|
|
|
out_free:
|
2006-03-29 02:14:04 +07:00
|
|
|
for(i = 0; i < leaf; i++)
|
2019-09-03 20:10:05 +07:00
|
|
|
brelse(larr[i]);
|
2014-11-20 12:18:38 +07:00
|
|
|
kvfree(larr);
|
2006-03-29 02:14:04 +07:00
|
|
|
out:
|
2006-01-16 23:50:04 +07:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2011-11-09 20:46:06 +07:00
|
|
|
/**
|
|
|
|
* gfs2_dir_readahead - Issue read-ahead requests for leaf blocks.
|
2011-10-27 23:16:06 +07:00
|
|
|
*
|
|
|
|
* Note: we can't calculate each index like dir_e_read can because we don't
|
|
|
|
* have the leaf, and therefore we don't have the depth, and therefore we
|
|
|
|
* don't have the length. So we have to just read enough ahead to make up
|
2011-11-09 20:46:06 +07:00
|
|
|
* for the loss of information.
|
|
|
|
*/
|
2011-10-27 23:16:06 +07:00
|
|
|
static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index,
|
|
|
|
struct file_ra_state *f_ra)
|
|
|
|
{
|
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
|
|
|
struct gfs2_glock *gl = ip->i_gl;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
u64 blocknr = 0, last;
|
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
/* First check if we've already read-ahead for the whole range. */
|
2011-11-09 20:46:06 +07:00
|
|
|
if (index + MAX_RA_BLOCKS < f_ra->start)
|
2011-10-27 23:16:06 +07:00
|
|
|
return;
|
|
|
|
|
|
|
|
f_ra->start = max((pgoff_t)index, f_ra->start);
|
|
|
|
for (count = 0; count < MAX_RA_BLOCKS; count++) {
|
|
|
|
if (f_ra->start >= hsize) /* if exceeded the hash table */
|
|
|
|
break;
|
|
|
|
|
|
|
|
last = blocknr;
|
|
|
|
blocknr = be64_to_cpu(ip->i_hash_cache[f_ra->start]);
|
|
|
|
f_ra->start++;
|
|
|
|
if (blocknr == last)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bh = gfs2_getbuf(gl, blocknr, 1);
|
|
|
|
if (trylock_buffer(bh)) {
|
|
|
|
if (buffer_uptodate(bh)) {
|
|
|
|
unlock_buffer(bh);
|
|
|
|
brelse(bh);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh->b_end_io = end_buffer_read_sync;
|
gfs2: add flag REQ_PRIO for metadata I/O
When gfs2 does metadata I/O, only REQ_META is used as a metadata hint of
the bio. But flag REQ_META is just a hint for block trace, not for block
layer code to handle a bio as metadata request.
For some of metadata I/Os of gfs2, A REQ_PRIO flag on the metadata bio
would be very informative to block layer code. For example, if bcache is
used as a I/O cache for gfs2, it will be possible for bcache code to get
the hint and cache the pre-fetched metadata blocks on cache device. This
behavior may be helpful to improve metadata I/O performance if the
following requests hit the cache.
Here are the locations in gfs2 code where a REQ_PRIO flag should be added,
- All places where REQ_READAHEAD is used, gfs2 code uses this flag for
metadata read ahead.
- In gfs2_meta_rq() where the first metadata block is read in.
- In gfs2_write_buf_to_page(), read in quota metadata blocks to have them
up to date.
These metadata blocks are probably to be accessed again in future, adding
a REQ_PRIO flag may have bcache to keep such metadata in fast cache
device. For system without a cache layer, REQ_PRIO can still provide hint
to block layer to handle metadata requests more properly.
Signed-off-by: Coly Li <colyli@suse.de>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2017-07-21 19:48:22 +07:00
|
|
|
submit_bh(REQ_OP_READ,
|
|
|
|
REQ_RAHEAD | REQ_META | REQ_PRIO,
|
|
|
|
bh);
|
2011-10-27 23:16:06 +07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
brelse(bh);
|
|
|
|
}
|
|
|
|
}
|
2011-06-15 16:29:37 +07:00
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/**
|
2006-03-21 00:30:04 +07:00
|
|
|
* dir_e_read - Reads the entries from a directory into a filldir buffer
|
|
|
|
* @dip: dinode pointer
|
2013-05-17 01:14:48 +07:00
|
|
|
* @ctx: actor to feed the entries to
|
2006-01-16 23:50:04 +07:00
|
|
|
*
|
2006-03-21 00:30:04 +07:00
|
|
|
* Returns: errno
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
static int dir_e_read(struct inode *inode, struct dir_context *ctx,
|
|
|
|
struct file_ra_state *f_ra)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *dip = GFS2_I(inode);
|
2006-09-04 23:49:07 +07:00
|
|
|
u32 hsize, len = 0;
|
|
|
|
u32 hash, index;
|
2006-10-14 21:46:30 +07:00
|
|
|
__be64 *lp;
|
2006-03-21 00:30:04 +07:00
|
|
|
int copied = 0;
|
|
|
|
int error = 0;
|
2006-07-12 00:19:13 +07:00
|
|
|
unsigned depth = 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
hsize = BIT(dip->i_depth);
|
2013-05-17 01:14:48 +07:00
|
|
|
hash = gfs2_dir_offset2hash(ctx->pos);
|
2008-02-01 16:23:44 +07:00
|
|
|
index = hash >> (32 - dip->i_depth);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-11-09 20:46:06 +07:00
|
|
|
if (dip->i_hash_cache == NULL)
|
2011-10-27 23:16:06 +07:00
|
|
|
f_ra->start = 0;
|
2011-06-15 16:29:37 +07:00
|
|
|
lp = gfs2_dir_get_hash_table(dip);
|
|
|
|
if (IS_ERR(lp))
|
|
|
|
return PTR_ERR(lp);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-10-27 23:16:06 +07:00
|
|
|
gfs2_dir_readahead(inode, hsize, index, f_ra);
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
while (index < hsize) {
|
2013-05-17 01:14:48 +07:00
|
|
|
error = gfs2_dir_read_leaf(inode, ctx,
|
2006-03-29 02:14:04 +07:00
|
|
|
&copied, &depth,
|
2011-06-15 16:29:37 +07:00
|
|
|
be64_to_cpu(lp[index]));
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error)
|
2006-03-29 02:14:04 +07:00
|
|
|
break;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
len = BIT(dip->i_depth - depth);
|
2006-01-16 23:50:04 +07:00
|
|
|
index = (index & ~(len - 1)) + len;
|
|
|
|
}
|
|
|
|
|
2006-03-29 02:14:04 +07:00
|
|
|
if (error > 0)
|
|
|
|
error = 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2013-05-17 01:14:48 +07:00
|
|
|
int gfs2_dir_read(struct inode *inode, struct dir_context *ctx,
|
|
|
|
struct file_ra_state *f_ra)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *dip = GFS2_I(inode);
|
2007-04-18 15:38:42 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
2006-03-29 02:14:04 +07:00
|
|
|
struct dirent_gather g;
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
struct gfs2_dirent **darr, *dent;
|
2006-01-16 23:50:04 +07:00
|
|
|
struct buffer_head *dibh;
|
|
|
|
int copied = 0;
|
|
|
|
int error;
|
|
|
|
|
2008-11-03 20:59:19 +07:00
|
|
|
if (!dip->i_entries)
|
2006-03-29 02:14:04 +07:00
|
|
|
return 0;
|
|
|
|
|
2008-11-04 17:05:22 +07:00
|
|
|
if (dip->i_diskflags & GFS2_DIF_EXHASH)
|
2013-05-17 01:14:48 +07:00
|
|
|
return dir_e_read(inode, ctx, f_ra);
|
2006-03-29 02:14:04 +07:00
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
if (!gfs2_is_stuffed(dip)) {
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(dip, &dibh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2006-03-29 02:14:04 +07:00
|
|
|
error = -ENOMEM;
|
2007-04-18 15:38:42 +07:00
|
|
|
/* 96 is max number of dirents which can be stuffed into an inode */
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 03:55:00 +07:00
|
|
|
darr = kmalloc_array(96, sizeof(struct gfs2_dirent *), GFP_NOFS);
|
2006-03-29 02:14:04 +07:00
|
|
|
if (darr) {
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
g.pdent = (const struct gfs2_dirent **)darr;
|
2006-03-29 02:14:04 +07:00
|
|
|
g.offset = 0;
|
|
|
|
dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
|
|
|
|
gfs2_dirent_gather, NULL, &g);
|
|
|
|
if (IS_ERR(dent)) {
|
|
|
|
error = PTR_ERR(dent);
|
|
|
|
goto out;
|
|
|
|
}
|
2008-11-03 20:59:19 +07:00
|
|
|
if (dip->i_entries != g.offset) {
|
2007-04-18 15:38:42 +07:00
|
|
|
fs_warn(sdp, "Number of entries corrupt in dir %llu, "
|
2008-11-03 20:59:19 +07:00
|
|
|
"ip->i_entries (%u) != g.offset (%u)\n",
|
2007-05-15 21:37:50 +07:00
|
|
|
(unsigned long long)dip->i_no_addr,
|
2008-11-03 20:59:19 +07:00
|
|
|
dip->i_entries,
|
2007-04-18 15:38:42 +07:00
|
|
|
g.offset);
|
2017-05-26 20:28:56 +07:00
|
|
|
gfs2_consist_inode(dip);
|
2007-04-18 15:38:42 +07:00
|
|
|
error = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
gfs2_set_cookies(sdp, dibh, 0, darr, dip->i_entries);
|
2013-05-17 01:14:48 +07:00
|
|
|
error = do_filldir_main(dip, ctx, darr,
|
gfs2: change gfs2 readdir cookie
gfs2 currently returns 31 bits of filename hash as a cookie that readdir
uses for an offset into the directory. When there are a large number of
directory entries, the likelihood of a collision goes up way too
quickly. GFS2 will now return cookies that are guaranteed unique for a
while, and then fail back to using 30 bits of filename hash.
Specifically, the directory leaf blocks are divided up into chunks based
on the minimum size of a gfs2 directory entry (48 bytes). Each entry's
cookie is based off the chunk where it starts, in the linked list of
leaf blocks that it hashes to (there are 131072 hash buckets). Directory
entries will have unique names until they take reach chunk 8192.
Assuming the largest filenames possible, and the least efficient spacing
possible, this new method will still be able to return unique names when
the previous method has statistically more than a 99% chance of a
collision. The non-unique names it fails back to are guaranteed to not
collide with the unique names.
unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "0"
- 13 bits for the offset
non-unique cookies will be in this format:
- 1 bit "0" to make sure the the returned cookie is positive
- 17 bits for the hash table index
- 1 bit for the mode "1"
- 13 more bits of the name hash
Another benefit of location based cookies, is that once a directory's
exhash table is fully extended (so that multiple hash table indexs do
not use the same leaf blocks), gfs2 can skip sorting the directory
entries until it reaches the non-unique ones, and then it only needs to
sort these. This provides a significant speed up for directory reads of
very large directories.
The only issue is that for these cookies to continue to point to the
correct entry as files are added and removed from the directory, gfs2
must keep the entries at the same offset in the leaf block when they are
split (see my previous patch). This means that until all the nodes in a
cluster are running with code that will split the directory leaf blocks
this way, none of the nodes can use the new cookie code. To deal with
this, gfs2 now has the mount option loccookie, which, if set, will make
it return these new location based cookies. This option must not be set
until all nodes in the cluster are at least running this version of the
kernel code, and you have guaranteed that there are no outstanding
cookies required by other software, such as NFS.
gfs2 uses some of the extra space at the end of the gfs2_dirent
structure to store the calculated readdir cookies. This keeps us from
needing to allocate a seperate array to hold these values. gfs2
recomputes the cookie stored in de_cookie for every readdir call. The
time it takes to do so is small, and if gfs2 expected this value to be
saved on disk, the new code wouldn't work correctly on filesystems
created with an earlier version of gfs2.
One issue with adding de_cookie to the union in the gfs2_dirent
structure is that it caused the union to align itself to a 4 byte
boundary, instead of its previous 2 byte boundary. This changed the
offset of de_rahead. To solve that, I pulled de_rahead out of the union,
since it does not need to be there.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2015-12-01 21:46:55 +07:00
|
|
|
dip->i_entries, 0, &copied);
|
2006-03-29 02:14:04 +07:00
|
|
|
out:
|
|
|
|
kfree(darr);
|
|
|
|
}
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error > 0)
|
|
|
|
error = 0;
|
|
|
|
|
|
|
|
brelse(dibh);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_search - Search a directory
|
2013-06-11 19:45:29 +07:00
|
|
|
* @dip: The GFS2 dir inode
|
|
|
|
* @name: The name we are looking up
|
|
|
|
* @fail_on_exist: Fail if the name exists rather than looking it up
|
2006-01-16 23:50:04 +07:00
|
|
|
*
|
|
|
|
* This routine searches a directory for a file or another directory.
|
|
|
|
* Assumes a glock is held on dip.
|
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
2013-06-11 19:45:29 +07:00
|
|
|
struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name,
|
|
|
|
bool fail_on_exist)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-03-21 00:30:04 +07:00
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_dirent *dent;
|
2013-06-11 19:45:29 +07:00
|
|
|
u64 addr, formal_ino;
|
|
|
|
u16 dtype;
|
2007-05-15 21:37:50 +07:00
|
|
|
|
|
|
|
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
|
|
|
|
if (dent) {
|
2015-11-12 04:00:35 +07:00
|
|
|
struct inode *inode;
|
|
|
|
u16 rahead;
|
|
|
|
|
2007-05-15 21:37:50 +07:00
|
|
|
if (IS_ERR(dent))
|
2008-02-07 15:15:26 +07:00
|
|
|
return ERR_CAST(dent);
|
2013-06-11 19:45:29 +07:00
|
|
|
dtype = be16_to_cpu(dent->de_type);
|
2015-11-12 04:00:35 +07:00
|
|
|
rahead = be16_to_cpu(dent->de_rahead);
|
2013-06-11 19:45:29 +07:00
|
|
|
addr = be64_to_cpu(dent->de_inum.no_addr);
|
|
|
|
formal_ino = be64_to_cpu(dent->de_inum.no_formal_ino);
|
2007-05-15 21:37:50 +07:00
|
|
|
brelse(bh);
|
2013-06-11 19:45:29 +07:00
|
|
|
if (fail_on_exist)
|
|
|
|
return ERR_PTR(-EEXIST);
|
gfs2: Fix gfs2_lookup_by_inum lock inversion
The current gfs2_lookup_by_inum takes the glock of a presumed inode
identified by block number, verifies that the block is indeed an inode,
and then instantiates and reads the new inode via gfs2_inode_lookup.
However, instantiating a new inode may block on freeing a previous
instance of that inode (__wait_on_freeing_inode), and freeing an inode
requires to take the glock already held, leading to lock inversion and
deadlock.
Fix this by first instantiating the new inode, then verifying that the
block is an inode (if required), and then reading in the new inode, all
in gfs2_inode_lookup.
If the block we are looking for is not an inode, we discard the new
inode via iget_failed, which marks inodes as bad and unhashes them.
Other tasks waiting on that inode will get back a bad inode back from
ilookup or iget_locked; in that case, retry the lookup.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2016-06-15 00:22:27 +07:00
|
|
|
inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino,
|
|
|
|
GFS2_BLKST_FREE /* ignore */);
|
2015-11-12 04:00:35 +07:00
|
|
|
if (!IS_ERR(inode))
|
|
|
|
GFS2_I(inode)->i_rahead = rahead;
|
|
|
|
return inode;
|
2007-05-15 21:37:50 +07:00
|
|
|
}
|
|
|
|
return ERR_PTR(-ENOENT);
|
|
|
|
}
|
|
|
|
|
|
|
|
int gfs2_dir_check(struct inode *dir, const struct qstr *name,
|
|
|
|
const struct gfs2_inode *ip)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_dirent *dent;
|
|
|
|
int ret = -ENOENT;
|
2006-03-21 00:30:04 +07:00
|
|
|
|
|
|
|
dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
|
|
|
|
if (dent) {
|
|
|
|
if (IS_ERR(dent))
|
|
|
|
return PTR_ERR(dent);
|
2007-05-15 21:37:50 +07:00
|
|
|
if (ip) {
|
|
|
|
if (be64_to_cpu(dent->de_inum.no_addr) != ip->i_no_addr)
|
|
|
|
goto out;
|
|
|
|
if (be64_to_cpu(dent->de_inum.no_formal_ino) !=
|
|
|
|
ip->i_no_formal_ino)
|
|
|
|
goto out;
|
|
|
|
if (unlikely(IF2DT(ip->i_inode.i_mode) !=
|
|
|
|
be16_to_cpu(dent->de_type))) {
|
|
|
|
gfs2_consist_inode(GFS2_I(dir));
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
out:
|
2006-03-21 00:30:04 +07:00
|
|
|
brelse(bh);
|
|
|
|
}
|
2007-05-15 21:37:50 +07:00
|
|
|
return ret;
|
2006-03-21 00:30:04 +07:00
|
|
|
}
|
|
|
|
|
2014-01-08 19:14:57 +07:00
|
|
|
/**
|
|
|
|
* dir_new_leaf - Add a new leaf onto hash chain
|
|
|
|
* @inode: The directory
|
|
|
|
* @name: The name we are adding
|
|
|
|
*
|
|
|
|
* This adds a new dir leaf onto an existing leaf when there is not
|
|
|
|
* enough space to add a new dir entry. This is a last resort after
|
|
|
|
* we've expanded the hash table to max size and also split existing
|
|
|
|
* leaf blocks, so it will only occur for very large directories.
|
|
|
|
*
|
|
|
|
* The dist parameter is set to 1 for leaf blocks directly attached
|
|
|
|
* to the hash table, 2 for one layer of indirection, 3 for two layers
|
|
|
|
* etc. We are thus able to tell the difference between an old leaf
|
|
|
|
* with dist set to zero (i.e. "don't know") and a new one where we
|
|
|
|
* set this information for debug/fsck purposes.
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, or -ve on error
|
|
|
|
*/
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
static int dir_new_leaf(struct inode *inode, const struct qstr *name)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh, *obh;
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *leaf, *oleaf;
|
2014-01-08 19:14:57 +07:00
|
|
|
u32 dist = 1;
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
2006-03-21 00:30:04 +07:00
|
|
|
u32 index;
|
|
|
|
u64 bn;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2008-02-01 16:23:44 +07:00
|
|
|
index = name->hash >> (32 - ip->i_depth);
|
2006-03-21 00:30:04 +07:00
|
|
|
error = get_first_leaf(ip, index, &obh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
do {
|
2014-01-08 19:14:57 +07:00
|
|
|
dist++;
|
2006-03-21 00:30:04 +07:00
|
|
|
oleaf = (struct gfs2_leaf *)obh->b_data;
|
|
|
|
bn = be64_to_cpu(oleaf->lf_next);
|
|
|
|
if (!bn)
|
|
|
|
break;
|
|
|
|
brelse(obh);
|
|
|
|
error = get_leaf(ip, bn, &obh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
} while(1);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, obh);
|
2006-03-21 00:30:04 +07:00
|
|
|
|
|
|
|
leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth));
|
|
|
|
if (!leaf) {
|
|
|
|
brelse(obh);
|
|
|
|
return -ENOSPC;
|
|
|
|
}
|
2014-01-08 19:14:57 +07:00
|
|
|
leaf->lf_dist = cpu_to_be32(dist);
|
2006-04-13 04:39:45 +07:00
|
|
|
oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
|
2006-03-21 00:30:04 +07:00
|
|
|
brelse(bh);
|
|
|
|
brelse(obh);
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(ip, &bh);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(ip->i_gl, bh);
|
2008-02-12 21:17:27 +07:00
|
|
|
gfs2_add_inode_blocks(&ip->i_inode, 1);
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(ip, bh->b_data);
|
2006-03-21 00:30:04 +07:00
|
|
|
brelse(bh);
|
|
|
|
return 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
GFS2: Add meta readahead field in directory entries
The intent of this new field in the directory entry is to
allow a subsequent lookup to know how many blocks, which
are contiguous with the inode, contain metadata which relates
to the inode. This will then allow the issuing of a single
read to read these blocks, rather than reading the inode
first, and then issuing a second read for the metadata.
This only works under some fairly strict conditions, since
we do not have back pointers from inodes to directory entries
we must ensure that the blocks referenced in this way will
always belong to the inode.
This rules out being able to use this system for indirect
blocks, as these can change as a result of truncate/rewrite.
So the idea here is to restrict this to xattr blocks only
for the time being. For most inodes, that means only a
single block. Also, when using ACLs and/or SELinux or
other LSMs, these will be added at inode creation time
so that they will be contiguous with the inode on disk and
also will almost always be needed when we read the inode in
for permissions checks.
Once an xattr block for an inode is allocated, it will never
change until the inode is deallocated.
This patch adds the new field, a further patch will add the
readahead in due course.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-02-07 18:23:22 +07:00
|
|
|
static u16 gfs2_inode_ra_len(const struct gfs2_inode *ip)
|
|
|
|
{
|
|
|
|
u64 where = ip->i_no_addr + 1;
|
|
|
|
if (ip->i_eattr == where)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/**
|
|
|
|
* gfs2_dir_add - Add new filename into directory
|
2014-01-06 19:49:43 +07:00
|
|
|
* @inode: The directory inode
|
|
|
|
* @name: The new name
|
|
|
|
* @nip: The GFS2 inode to be linked in to the directory
|
|
|
|
* @da: The directory addition info
|
|
|
|
*
|
|
|
|
* If the call to gfs2_diradd_alloc_required resulted in there being
|
|
|
|
* no need to allocate any new directory blocks, then it will contain
|
|
|
|
* a pointer to the directory entry and the bh in which it resides. We
|
|
|
|
* can use that without having to repeat the search. If there was no
|
|
|
|
* free space, then we must now create more space.
|
2006-01-16 23:50:04 +07:00
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code on failure
|
|
|
|
*/
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
int gfs2_dir_add(struct inode *inode, const struct qstr *name,
|
2014-01-06 19:49:43 +07:00
|
|
|
const struct gfs2_inode *nip, struct gfs2_diradd *da)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2014-01-06 19:49:43 +07:00
|
|
|
struct buffer_head *bh = da->bh;
|
|
|
|
struct gfs2_dirent *dent = da->dent;
|
vfs: change inode times to use struct timespec64
struct timespec is not y2038 safe. Transition vfs to use
y2038 safe struct timespec64 instead.
The change was made with the help of the following cocinelle
script. This catches about 80% of the changes.
All the header file and logic changes are included in the
first 5 rules. The rest are trivial substitutions.
I avoid changing any of the function signatures or any other
filesystem specific data structures to keep the patch simple
for review.
The script can be a little shorter by combining different cases.
But, this version was sufficient for my usecase.
virtual patch
@ depends on patch @
identifier now;
@@
- struct timespec
+ struct timespec64
current_time ( ... )
{
- struct timespec now = current_kernel_time();
+ struct timespec64 now = current_kernel_time64();
...
- return timespec_trunc(
+ return timespec64_trunc(
... );
}
@ depends on patch @
identifier xtime;
@@
struct \( iattr \| inode \| kstat \) {
...
- struct timespec xtime;
+ struct timespec64 xtime;
...
}
@ depends on patch @
identifier t;
@@
struct inode_operations {
...
int (*update_time) (...,
- struct timespec t,
+ struct timespec64 t,
...);
...
}
@ depends on patch @
identifier t;
identifier fn_update_time =~ "update_time$";
@@
fn_update_time (...,
- struct timespec *t,
+ struct timespec64 *t,
...) { ... }
@ depends on patch @
identifier t;
@@
lease_get_mtime( ... ,
- struct timespec *t
+ struct timespec64 *t
) { ... }
@te depends on patch forall@
identifier ts;
local idexpression struct inode *inode_node;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn_update_time =~ "update_time$";
identifier fn;
expression e, E3;
local idexpression struct inode *node1;
local idexpression struct inode *node2;
local idexpression struct iattr *attr1;
local idexpression struct iattr *attr2;
local idexpression struct iattr attr;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
@@
(
(
- struct timespec ts;
+ struct timespec64 ts;
|
- struct timespec ts = current_time(inode_node);
+ struct timespec64 ts = current_time(inode_node);
)
<+... when != ts
(
- timespec_equal(&inode_node->i_xtime, &ts)
+ timespec64_equal(&inode_node->i_xtime, &ts)
|
- timespec_equal(&ts, &inode_node->i_xtime)
+ timespec64_equal(&ts, &inode_node->i_xtime)
|
- timespec_compare(&inode_node->i_xtime, &ts)
+ timespec64_compare(&inode_node->i_xtime, &ts)
|
- timespec_compare(&ts, &inode_node->i_xtime)
+ timespec64_compare(&ts, &inode_node->i_xtime)
|
ts = current_time(e)
|
fn_update_time(..., &ts,...)
|
inode_node->i_xtime = ts
|
node1->i_xtime = ts
|
ts = inode_node->i_xtime
|
<+... attr1->ia_xtime ...+> = ts
|
ts = attr1->ia_xtime
|
ts.tv_sec
|
ts.tv_nsec
|
btrfs_set_stack_timespec_sec(..., ts.tv_sec)
|
btrfs_set_stack_timespec_nsec(..., ts.tv_nsec)
|
- ts = timespec64_to_timespec(
+ ts =
...
-)
|
- ts = ktime_to_timespec(
+ ts = ktime_to_timespec64(
...)
|
- ts = E3
+ ts = timespec_to_timespec64(E3)
|
- ktime_get_real_ts(&ts)
+ ktime_get_real_ts64(&ts)
|
fn(...,
- ts
+ timespec64_to_timespec(ts)
,...)
)
...+>
(
<... when != ts
- return ts;
+ return timespec64_to_timespec(ts);
...>
)
|
- timespec_equal(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_equal(&node1->i_xtime2, &node2->i_xtime2)
|
- timespec_equal(&node1->i_xtime1, &attr2->ia_xtime2)
+ timespec64_equal(&node1->i_xtime2, &attr2->ia_xtime2)
|
- timespec_compare(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_compare(&node1->i_xtime1, &node2->i_xtime2)
|
node1->i_xtime1 =
- timespec_trunc(attr1->ia_xtime1,
+ timespec64_trunc(attr1->ia_xtime1,
...)
|
- attr1->ia_xtime1 = timespec_trunc(attr2->ia_xtime2,
+ attr1->ia_xtime1 = timespec64_trunc(attr2->ia_xtime2,
...)
|
- ktime_get_real_ts(&attr1->ia_xtime1)
+ ktime_get_real_ts64(&attr1->ia_xtime1)
|
- ktime_get_real_ts(&attr.ia_xtime1)
+ ktime_get_real_ts64(&attr.ia_xtime1)
)
@ depends on patch @
struct inode *node;
struct iattr *attr;
identifier fn;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
expression e;
@@
(
- fn(node->i_xtime);
+ fn(timespec64_to_timespec(node->i_xtime));
|
fn(...,
- node->i_xtime);
+ timespec64_to_timespec(node->i_xtime));
|
- e = fn(attr->ia_xtime);
+ e = fn(timespec64_to_timespec(attr->ia_xtime));
)
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
fn (...,
- &attr->ia_xtime,
+ &ts,
...);
)
...+>
}
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
struct kstat *stat;
identifier ia_xtime =~ "^ia_[acm]time$";
identifier i_xtime =~ "^i_[acm]time$";
identifier xtime =~ "^[acm]time$";
identifier fn, ret;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(stat->xtime);
ret = fn (...,
- &stat->xtime);
+ &ts);
)
...+>
}
@ depends on patch @
struct inode *node;
struct inode *node2;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier i_xtime3 =~ "^i_[acm]time$";
struct iattr *attrp;
struct iattr *attrp2;
struct iattr attr ;
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
struct kstat *stat;
struct kstat stat1;
struct timespec64 ts;
identifier xtime =~ "^[acmb]time$";
expression e;
@@
(
( node->i_xtime2 \| attrp->ia_xtime2 \| attr.ia_xtime2 \) = node->i_xtime1 ;
|
node->i_xtime2 = \( node2->i_xtime1 \| timespec64_trunc(...) \);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
stat->xtime = node2->i_xtime1;
|
stat1.xtime = node2->i_xtime1;
|
( node->i_xtime2 \| attrp->ia_xtime2 \) = attrp->ia_xtime1 ;
|
( attrp->ia_xtime1 \| attr.ia_xtime1 \) = attrp2->ia_xtime2;
|
- e = node->i_xtime1;
+ e = timespec64_to_timespec( node->i_xtime1 );
|
- e = attrp->ia_xtime1;
+ e = timespec64_to_timespec( attrp->ia_xtime1 );
|
node->i_xtime1 = current_time(...);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
- node->i_xtime1 = e;
+ node->i_xtime1 = timespec_to_timespec64(e);
)
Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Cc: <anton@tuxera.com>
Cc: <balbi@kernel.org>
Cc: <bfields@fieldses.org>
Cc: <darrick.wong@oracle.com>
Cc: <dhowells@redhat.com>
Cc: <dsterba@suse.com>
Cc: <dwmw2@infradead.org>
Cc: <hch@lst.de>
Cc: <hirofumi@mail.parknet.co.jp>
Cc: <hubcap@omnibond.com>
Cc: <jack@suse.com>
Cc: <jaegeuk@kernel.org>
Cc: <jaharkes@cs.cmu.edu>
Cc: <jslaby@suse.com>
Cc: <keescook@chromium.org>
Cc: <mark@fasheh.com>
Cc: <miklos@szeredi.hu>
Cc: <nico@linaro.org>
Cc: <reiserfs-devel@vger.kernel.org>
Cc: <richard@nod.at>
Cc: <sage@redhat.com>
Cc: <sfrench@samba.org>
Cc: <swhiteho@redhat.com>
Cc: <tj@kernel.org>
Cc: <trond.myklebust@primarydata.com>
Cc: <tytso@mit.edu>
Cc: <viro@zeniv.linux.org.uk>
2018-05-09 09:36:02 +07:00
|
|
|
struct timespec64 tv;
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *leaf;
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
while(1) {
|
2014-01-06 19:49:43 +07:00
|
|
|
if (da->bh == NULL) {
|
|
|
|
dent = gfs2_dirent_search(inode, name,
|
|
|
|
gfs2_dirent_find_space, &bh);
|
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
if (dent) {
|
|
|
|
if (IS_ERR(dent))
|
|
|
|
return PTR_ERR(dent);
|
|
|
|
dent = gfs2_init_dirent(inode, dent, name, bh);
|
2007-05-15 21:37:50 +07:00
|
|
|
gfs2_inum_out(nip, dent);
|
2011-05-09 19:30:08 +07:00
|
|
|
dent->de_type = cpu_to_be16(IF2DT(nip->i_inode.i_mode));
|
GFS2: Add meta readahead field in directory entries
The intent of this new field in the directory entry is to
allow a subsequent lookup to know how many blocks, which
are contiguous with the inode, contain metadata which relates
to the inode. This will then allow the issuing of a single
read to read these blocks, rather than reading the inode
first, and then issuing a second read for the metadata.
This only works under some fairly strict conditions, since
we do not have back pointers from inodes to directory entries
we must ensure that the blocks referenced in this way will
always belong to the inode.
This rules out being able to use this system for indirect
blocks, as these can change as a result of truncate/rewrite.
So the idea here is to restrict this to xattr blocks only
for the time being. For most inodes, that means only a
single block. Also, when using ACLs and/or SELinux or
other LSMs, these will be added at inode creation time
so that they will be contiguous with the inode on disk and
also will almost always be needed when we read the inode in
for permissions checks.
Once an xattr block for an inode is allocated, it will never
change until the inode is deallocated.
This patch adds the new field, a further patch will add the
readahead in due course.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-02-07 18:23:22 +07:00
|
|
|
dent->de_rahead = cpu_to_be16(gfs2_inode_ra_len(nip));
|
2016-09-14 21:48:04 +07:00
|
|
|
tv = current_time(&ip->i_inode);
|
2008-11-04 17:05:22 +07:00
|
|
|
if (ip->i_diskflags & GFS2_DIF_EXHASH) {
|
2006-03-21 00:30:04 +07:00
|
|
|
leaf = (struct gfs2_leaf *)bh->b_data;
|
2008-02-13 06:06:10 +07:00
|
|
|
be16_add_cpu(&leaf->lf_entries, 1);
|
2014-01-08 19:14:57 +07:00
|
|
|
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
|
|
|
|
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
|
2006-03-21 00:30:04 +07:00
|
|
|
}
|
2014-01-06 19:49:43 +07:00
|
|
|
da->dent = NULL;
|
|
|
|
da->bh = NULL;
|
2006-03-21 00:30:04 +07:00
|
|
|
brelse(bh);
|
2008-11-03 20:59:19 +07:00
|
|
|
ip->i_entries++;
|
2014-01-08 19:14:57 +07:00
|
|
|
ip->i_inode.i_mtime = ip->i_inode.i_ctime = tv;
|
2011-05-09 19:30:08 +07:00
|
|
|
if (S_ISDIR(nip->i_inode.i_mode))
|
|
|
|
inc_nlink(&ip->i_inode);
|
2012-11-13 01:04:54 +07:00
|
|
|
mark_inode_dirty(inode);
|
2006-03-21 00:30:04 +07:00
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
}
|
2008-11-04 17:05:22 +07:00
|
|
|
if (!(ip->i_diskflags & GFS2_DIF_EXHASH)) {
|
2006-03-21 00:30:04 +07:00
|
|
|
error = dir_make_exhash(inode);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
error = dir_split_leaf(inode, name);
|
|
|
|
if (error == 0)
|
|
|
|
continue;
|
2006-03-30 07:02:15 +07:00
|
|
|
if (error < 0)
|
2006-03-21 00:30:04 +07:00
|
|
|
break;
|
2008-02-01 16:23:44 +07:00
|
|
|
if (ip->i_depth < GFS2_DIR_MAX_DEPTH) {
|
2006-03-21 00:30:04 +07:00
|
|
|
error = dir_double_exhash(ip);
|
|
|
|
if (error)
|
|
|
|
break;
|
|
|
|
error = dir_split_leaf(inode, name);
|
2006-03-30 07:02:15 +07:00
|
|
|
if (error < 0)
|
2006-03-21 00:30:04 +07:00
|
|
|
break;
|
2006-03-30 07:02:15 +07:00
|
|
|
if (error == 0)
|
|
|
|
continue;
|
2006-03-21 00:30:04 +07:00
|
|
|
}
|
|
|
|
error = dir_new_leaf(inode, name);
|
|
|
|
if (!error)
|
|
|
|
continue;
|
|
|
|
error = -ENOSPC;
|
|
|
|
break;
|
|
|
|
}
|
2006-01-16 23:50:04 +07:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
/**
|
|
|
|
* gfs2_dir_del - Delete a directory entry
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
* @filename: The filename
|
|
|
|
*
|
|
|
|
* Returns: 0 on success, error code on failure
|
|
|
|
*/
|
|
|
|
|
2011-05-09 22:42:37 +07:00
|
|
|
int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2011-05-09 22:42:37 +07:00
|
|
|
const struct qstr *name = &dentry->d_name;
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_dirent *dent, *prev = NULL;
|
|
|
|
struct buffer_head *bh;
|
vfs: change inode times to use struct timespec64
struct timespec is not y2038 safe. Transition vfs to use
y2038 safe struct timespec64 instead.
The change was made with the help of the following cocinelle
script. This catches about 80% of the changes.
All the header file and logic changes are included in the
first 5 rules. The rest are trivial substitutions.
I avoid changing any of the function signatures or any other
filesystem specific data structures to keep the patch simple
for review.
The script can be a little shorter by combining different cases.
But, this version was sufficient for my usecase.
virtual patch
@ depends on patch @
identifier now;
@@
- struct timespec
+ struct timespec64
current_time ( ... )
{
- struct timespec now = current_kernel_time();
+ struct timespec64 now = current_kernel_time64();
...
- return timespec_trunc(
+ return timespec64_trunc(
... );
}
@ depends on patch @
identifier xtime;
@@
struct \( iattr \| inode \| kstat \) {
...
- struct timespec xtime;
+ struct timespec64 xtime;
...
}
@ depends on patch @
identifier t;
@@
struct inode_operations {
...
int (*update_time) (...,
- struct timespec t,
+ struct timespec64 t,
...);
...
}
@ depends on patch @
identifier t;
identifier fn_update_time =~ "update_time$";
@@
fn_update_time (...,
- struct timespec *t,
+ struct timespec64 *t,
...) { ... }
@ depends on patch @
identifier t;
@@
lease_get_mtime( ... ,
- struct timespec *t
+ struct timespec64 *t
) { ... }
@te depends on patch forall@
identifier ts;
local idexpression struct inode *inode_node;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn_update_time =~ "update_time$";
identifier fn;
expression e, E3;
local idexpression struct inode *node1;
local idexpression struct inode *node2;
local idexpression struct iattr *attr1;
local idexpression struct iattr *attr2;
local idexpression struct iattr attr;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
@@
(
(
- struct timespec ts;
+ struct timespec64 ts;
|
- struct timespec ts = current_time(inode_node);
+ struct timespec64 ts = current_time(inode_node);
)
<+... when != ts
(
- timespec_equal(&inode_node->i_xtime, &ts)
+ timespec64_equal(&inode_node->i_xtime, &ts)
|
- timespec_equal(&ts, &inode_node->i_xtime)
+ timespec64_equal(&ts, &inode_node->i_xtime)
|
- timespec_compare(&inode_node->i_xtime, &ts)
+ timespec64_compare(&inode_node->i_xtime, &ts)
|
- timespec_compare(&ts, &inode_node->i_xtime)
+ timespec64_compare(&ts, &inode_node->i_xtime)
|
ts = current_time(e)
|
fn_update_time(..., &ts,...)
|
inode_node->i_xtime = ts
|
node1->i_xtime = ts
|
ts = inode_node->i_xtime
|
<+... attr1->ia_xtime ...+> = ts
|
ts = attr1->ia_xtime
|
ts.tv_sec
|
ts.tv_nsec
|
btrfs_set_stack_timespec_sec(..., ts.tv_sec)
|
btrfs_set_stack_timespec_nsec(..., ts.tv_nsec)
|
- ts = timespec64_to_timespec(
+ ts =
...
-)
|
- ts = ktime_to_timespec(
+ ts = ktime_to_timespec64(
...)
|
- ts = E3
+ ts = timespec_to_timespec64(E3)
|
- ktime_get_real_ts(&ts)
+ ktime_get_real_ts64(&ts)
|
fn(...,
- ts
+ timespec64_to_timespec(ts)
,...)
)
...+>
(
<... when != ts
- return ts;
+ return timespec64_to_timespec(ts);
...>
)
|
- timespec_equal(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_equal(&node1->i_xtime2, &node2->i_xtime2)
|
- timespec_equal(&node1->i_xtime1, &attr2->ia_xtime2)
+ timespec64_equal(&node1->i_xtime2, &attr2->ia_xtime2)
|
- timespec_compare(&node1->i_xtime1, &node2->i_xtime2)
+ timespec64_compare(&node1->i_xtime1, &node2->i_xtime2)
|
node1->i_xtime1 =
- timespec_trunc(attr1->ia_xtime1,
+ timespec64_trunc(attr1->ia_xtime1,
...)
|
- attr1->ia_xtime1 = timespec_trunc(attr2->ia_xtime2,
+ attr1->ia_xtime1 = timespec64_trunc(attr2->ia_xtime2,
...)
|
- ktime_get_real_ts(&attr1->ia_xtime1)
+ ktime_get_real_ts64(&attr1->ia_xtime1)
|
- ktime_get_real_ts(&attr.ia_xtime1)
+ ktime_get_real_ts64(&attr.ia_xtime1)
)
@ depends on patch @
struct inode *node;
struct iattr *attr;
identifier fn;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
expression e;
@@
(
- fn(node->i_xtime);
+ fn(timespec64_to_timespec(node->i_xtime));
|
fn(...,
- node->i_xtime);
+ timespec64_to_timespec(node->i_xtime));
|
- e = fn(attr->ia_xtime);
+ e = fn(timespec64_to_timespec(attr->ia_xtime));
)
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
identifier i_xtime =~ "^i_[acm]time$";
identifier ia_xtime =~ "^ia_[acm]time$";
identifier fn;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
fn (...,
- &attr->ia_xtime,
+ &ts,
...);
)
...+>
}
@ depends on patch forall @
struct inode *node;
struct iattr *attr;
struct kstat *stat;
identifier ia_xtime =~ "^ia_[acm]time$";
identifier i_xtime =~ "^i_[acm]time$";
identifier xtime =~ "^[acm]time$";
identifier fn, ret;
@@
{
+ struct timespec ts;
<+...
(
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(node->i_xtime);
ret = fn (...,
- &node->i_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime,
+ &ts,
...);
|
+ ts = timespec64_to_timespec(attr->ia_xtime);
ret = fn (...,
- &attr->ia_xtime);
+ &ts);
|
+ ts = timespec64_to_timespec(stat->xtime);
ret = fn (...,
- &stat->xtime);
+ &ts);
)
...+>
}
@ depends on patch @
struct inode *node;
struct inode *node2;
identifier i_xtime1 =~ "^i_[acm]time$";
identifier i_xtime2 =~ "^i_[acm]time$";
identifier i_xtime3 =~ "^i_[acm]time$";
struct iattr *attrp;
struct iattr *attrp2;
struct iattr attr ;
identifier ia_xtime1 =~ "^ia_[acm]time$";
identifier ia_xtime2 =~ "^ia_[acm]time$";
struct kstat *stat;
struct kstat stat1;
struct timespec64 ts;
identifier xtime =~ "^[acmb]time$";
expression e;
@@
(
( node->i_xtime2 \| attrp->ia_xtime2 \| attr.ia_xtime2 \) = node->i_xtime1 ;
|
node->i_xtime2 = \( node2->i_xtime1 \| timespec64_trunc(...) \);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
|
stat->xtime = node2->i_xtime1;
|
stat1.xtime = node2->i_xtime1;
|
( node->i_xtime2 \| attrp->ia_xtime2 \) = attrp->ia_xtime1 ;
|
( attrp->ia_xtime1 \| attr.ia_xtime1 \) = attrp2->ia_xtime2;
|
- e = node->i_xtime1;
+ e = timespec64_to_timespec( node->i_xtime1 );
|
- e = attrp->ia_xtime1;
+ e = timespec64_to_timespec( attrp->ia_xtime1 );
|
node->i_xtime1 = current_time(...);
|
node->i_xtime2 = node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
node->i_xtime1 = node->i_xtime3 =
- e;
+ timespec_to_timespec64(e);
|
- node->i_xtime1 = e;
+ node->i_xtime1 = timespec_to_timespec64(e);
)
Signed-off-by: Deepa Dinamani <deepa.kernel@gmail.com>
Cc: <anton@tuxera.com>
Cc: <balbi@kernel.org>
Cc: <bfields@fieldses.org>
Cc: <darrick.wong@oracle.com>
Cc: <dhowells@redhat.com>
Cc: <dsterba@suse.com>
Cc: <dwmw2@infradead.org>
Cc: <hch@lst.de>
Cc: <hirofumi@mail.parknet.co.jp>
Cc: <hubcap@omnibond.com>
Cc: <jack@suse.com>
Cc: <jaegeuk@kernel.org>
Cc: <jaharkes@cs.cmu.edu>
Cc: <jslaby@suse.com>
Cc: <keescook@chromium.org>
Cc: <mark@fasheh.com>
Cc: <miklos@szeredi.hu>
Cc: <nico@linaro.org>
Cc: <reiserfs-devel@vger.kernel.org>
Cc: <richard@nod.at>
Cc: <sage@redhat.com>
Cc: <sfrench@samba.org>
Cc: <swhiteho@redhat.com>
Cc: <tj@kernel.org>
Cc: <trond.myklebust@primarydata.com>
Cc: <tytso@mit.edu>
Cc: <viro@zeniv.linux.org.uk>
2018-05-09 09:36:02 +07:00
|
|
|
struct timespec64 tv = current_time(&dip->i_inode);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
/* Returns _either_ the entry (if its first in block) or the
|
|
|
|
previous entry otherwise */
|
2006-06-15 02:32:57 +07:00
|
|
|
dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (!dent) {
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
if (IS_ERR(dent)) {
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return PTR_ERR(dent);
|
|
|
|
}
|
|
|
|
/* If not first in block, adjust pointers accordingly */
|
2006-03-29 02:14:04 +07:00
|
|
|
if (gfs2_dirent_find(dent, name, NULL) == 0) {
|
2006-03-21 00:30:04 +07:00
|
|
|
prev = dent;
|
|
|
|
dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));
|
|
|
|
}
|
|
|
|
|
|
|
|
dirent_del(dip, bh, prev, dent);
|
2008-11-04 17:05:22 +07:00
|
|
|
if (dip->i_diskflags & GFS2_DIF_EXHASH) {
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
u16 entries = be16_to_cpu(leaf->lf_entries);
|
|
|
|
if (!entries)
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
leaf->lf_entries = cpu_to_be16(--entries);
|
2014-01-08 19:14:57 +07:00
|
|
|
leaf->lf_nsec = cpu_to_be32(tv.tv_nsec);
|
|
|
|
leaf->lf_sec = cpu_to_be64(tv.tv_sec);
|
2006-03-21 00:30:04 +07:00
|
|
|
}
|
2006-04-08 03:28:07 +07:00
|
|
|
brelse(bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
|
2008-11-03 20:59:19 +07:00
|
|
|
if (!dip->i_entries)
|
2006-03-21 00:30:04 +07:00
|
|
|
gfs2_consist_inode(dip);
|
2008-11-03 20:59:19 +07:00
|
|
|
dip->i_entries--;
|
2014-01-08 19:14:57 +07:00
|
|
|
dip->i_inode.i_mtime = dip->i_inode.i_ctime = tv;
|
VFS: (Scripted) Convert S_ISLNK/DIR/REG(dentry->d_inode) to d_is_*(dentry)
Convert the following where appropriate:
(1) S_ISLNK(dentry->d_inode) to d_is_symlink(dentry).
(2) S_ISREG(dentry->d_inode) to d_is_reg(dentry).
(3) S_ISDIR(dentry->d_inode) to d_is_dir(dentry). This is actually more
complicated than it appears as some calls should be converted to
d_can_lookup() instead. The difference is whether the directory in
question is a real dir with a ->lookup op or whether it's a fake dir with
a ->d_automount op.
In some circumstances, we can subsume checks for dentry->d_inode not being
NULL into this, provided we the code isn't in a filesystem that expects
d_inode to be NULL if the dirent really *is* negative (ie. if we're going to
use d_inode() rather than d_backing_inode() to get the inode pointer).
Note that the dentry type field may be set to something other than
DCACHE_MISS_TYPE when d_inode is NULL in the case of unionmount, where the VFS
manages the fall-through from a negative dentry to a lower layer. In such a
case, the dentry type of the negative union dentry is set to the same as the
type of the lower dentry.
However, if you know d_inode is not NULL at the call site, then you can use
the d_is_xxx() functions even in a filesystem.
There is one further complication: a 0,0 chardev dentry may be labelled
DCACHE_WHITEOUT_TYPE rather than DCACHE_SPECIAL_TYPE. Strictly, this was
intended for special directory entry types that don't have attached inodes.
The following perl+coccinelle script was used:
use strict;
my @callers;
open($fd, 'git grep -l \'S_IS[A-Z].*->d_inode\' |') ||
die "Can't grep for S_ISDIR and co. callers";
@callers = <$fd>;
close($fd);
unless (@callers) {
print "No matches\n";
exit(0);
}
my @cocci = (
'@@',
'expression E;',
'@@',
'',
'- S_ISLNK(E->d_inode->i_mode)',
'+ d_is_symlink(E)',
'',
'@@',
'expression E;',
'@@',
'',
'- S_ISDIR(E->d_inode->i_mode)',
'+ d_is_dir(E)',
'',
'@@',
'expression E;',
'@@',
'',
'- S_ISREG(E->d_inode->i_mode)',
'+ d_is_reg(E)' );
my $coccifile = "tmp.sp.cocci";
open($fd, ">$coccifile") || die $coccifile;
print($fd "$_\n") || die $coccifile foreach (@cocci);
close($fd);
foreach my $file (@callers) {
chomp $file;
print "Processing ", $file, "\n";
system("spatch", "--sp-file", $coccifile, $file, "--in-place", "--no-show-diff") == 0 ||
die "spatch failed";
}
[AV: overlayfs parts skipped]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2015-01-29 19:02:35 +07:00
|
|
|
if (d_is_dir(dentry))
|
2011-05-09 22:42:37 +07:00
|
|
|
drop_nlink(&dip->i_inode);
|
2006-06-15 02:32:57 +07:00
|
|
|
mark_inode_dirty(&dip->i_inode);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-08-15 20:20:36 +07:00
|
|
|
return 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_mvino - Change inode number of directory entry
|
|
|
|
* @dip: The GFS2 inode
|
|
|
|
* @filename:
|
|
|
|
* @new_inode:
|
|
|
|
*
|
|
|
|
* This routine changes the inode number of a directory entry. It's used
|
|
|
|
* by rename to change ".." when a directory is moved.
|
|
|
|
* Assumes a glock is held on dvp.
|
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
|
2007-05-15 21:37:50 +07:00
|
|
|
const struct gfs2_inode *nip, unsigned int new_type)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-03-21 00:30:04 +07:00
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_dirent *dent;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-06-15 02:32:57 +07:00
|
|
|
dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
if (!dent) {
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
if (IS_ERR(dent))
|
|
|
|
return PTR_ERR(dent);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, bh);
|
2007-05-15 21:37:50 +07:00
|
|
|
gfs2_inum_out(nip, dent);
|
2006-03-21 00:30:04 +07:00
|
|
|
dent->de_type = cpu_to_be16(new_type);
|
2018-03-01 02:48:53 +07:00
|
|
|
brelse(bh);
|
2006-03-21 00:30:04 +07:00
|
|
|
|
2016-09-14 21:48:04 +07:00
|
|
|
dip->i_inode.i_mtime = dip->i_inode.i_ctime = current_time(&dip->i_inode);
|
2018-03-01 02:48:53 +07:00
|
|
|
mark_inode_dirty_sync(&dip->i_inode);
|
2006-03-21 00:30:04 +07:00
|
|
|
return 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* leaf_dealloc - Deallocate a directory leaf
|
|
|
|
* @dip: the directory
|
|
|
|
* @index: the hash table offset in the directory
|
|
|
|
* @len: the number of pointers to this leaf
|
|
|
|
* @leaf_no: the leaf number
|
2011-03-23 00:55:23 +07:00
|
|
|
* @leaf_bh: buffer_head for the starting leaf
|
2011-03-23 00:54:03 +07:00
|
|
|
* last_dealloc: 1 if this is the final dealloc for the leaf, else 0
|
2006-01-16 23:50:04 +07:00
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
|
2011-03-23 00:55:23 +07:00
|
|
|
u64 leaf_no, struct buffer_head *leaf_bh,
|
|
|
|
int last_dealloc)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2006-06-15 02:32:57 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_leaf *tmp_leaf;
|
2006-01-16 23:50:04 +07:00
|
|
|
struct gfs2_rgrp_list rlist;
|
|
|
|
struct buffer_head *bh, *dibh;
|
2006-09-04 23:49:07 +07:00
|
|
|
u64 blk, nblk;
|
2006-01-16 23:50:04 +07:00
|
|
|
unsigned int rg_blocks = 0, l_blocks = 0;
|
|
|
|
char *ht;
|
2006-09-04 23:49:07 +07:00
|
|
|
unsigned int x, size = len * sizeof(u64);
|
2006-01-16 23:50:04 +07:00
|
|
|
int error;
|
|
|
|
|
2012-04-05 09:11:16 +07:00
|
|
|
error = gfs2_rindex_update(sdp);
|
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2006-01-16 23:50:04 +07:00
|
|
|
memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
|
|
|
|
|
2013-06-20 02:15:53 +07:00
|
|
|
ht = kzalloc(size, GFP_NOFS | __GFP_NOWARN);
|
2013-05-30 20:48:56 +07:00
|
|
|
if (ht == NULL)
|
2015-02-02 10:59:54 +07:00
|
|
|
ht = __vmalloc(size, GFP_NOFS | __GFP_NOWARN | __GFP_ZERO,
|
|
|
|
PAGE_KERNEL);
|
2006-01-16 23:50:04 +07:00
|
|
|
if (!ht)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-02-01 08:49:26 +07:00
|
|
|
error = gfs2_quota_hold(dip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error)
|
2012-05-18 20:28:23 +07:00
|
|
|
goto out;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
/* Count the number of leaves */
|
2011-03-23 00:55:23 +07:00
|
|
|
bh = leaf_bh;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
for (blk = leaf_no; blk; blk = nblk) {
|
2011-03-23 00:55:23 +07:00
|
|
|
if (blk != leaf_no) {
|
|
|
|
error = get_leaf(dip, blk, &bh);
|
|
|
|
if (error)
|
|
|
|
goto out_rlist;
|
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
tmp_leaf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
nblk = be64_to_cpu(tmp_leaf->lf_next);
|
2011-03-23 00:55:23 +07:00
|
|
|
if (blk != leaf_no)
|
|
|
|
brelse(bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2011-09-02 22:08:09 +07:00
|
|
|
gfs2_rlist_add(dip, &rlist, blk);
|
2006-01-16 23:50:04 +07:00
|
|
|
l_blocks++;
|
|
|
|
}
|
|
|
|
|
2018-10-04 06:06:23 +07:00
|
|
|
gfs2_rlist_alloc(&rlist);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
|
|
|
for (x = 0; x < rlist.rl_rgrps; x++) {
|
2017-06-30 19:55:08 +07:00
|
|
|
struct gfs2_rgrpd *rgd = gfs2_glock2rgrp(rlist.rl_ghs[x].gh_gl);
|
|
|
|
|
2007-06-01 20:11:58 +07:00
|
|
|
rg_blocks += rgd->rd_length;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
|
|
|
|
if (error)
|
|
|
|
goto out_rlist;
|
|
|
|
|
|
|
|
error = gfs2_trans_begin(sdp,
|
2006-02-28 05:23:27 +07:00
|
|
|
rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) +
|
2006-01-16 23:50:04 +07:00
|
|
|
RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks);
|
|
|
|
if (error)
|
|
|
|
goto out_rg_gunlock;
|
|
|
|
|
2011-03-23 00:55:23 +07:00
|
|
|
bh = leaf_bh;
|
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
for (blk = leaf_no; blk; blk = nblk) {
|
2018-10-04 21:36:02 +07:00
|
|
|
struct gfs2_rgrpd *rgd;
|
|
|
|
|
2011-03-23 00:55:23 +07:00
|
|
|
if (blk != leaf_no) {
|
|
|
|
error = get_leaf(dip, blk, &bh);
|
|
|
|
if (error)
|
|
|
|
goto out_end_trans;
|
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
tmp_leaf = (struct gfs2_leaf *)bh->b_data;
|
|
|
|
nblk = be64_to_cpu(tmp_leaf->lf_next);
|
2011-03-23 00:55:23 +07:00
|
|
|
if (blk != leaf_no)
|
|
|
|
brelse(bh);
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2018-10-04 21:36:02 +07:00
|
|
|
rgd = gfs2_blk2rgrpd(sdp, blk, true);
|
|
|
|
gfs2_free_meta(dip, rgd, blk, 1);
|
2008-02-12 21:17:27 +07:00
|
|
|
gfs2_add_inode_blocks(&dip->i_inode, -1);
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
2006-09-04 23:49:07 +07:00
|
|
|
error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);
|
2006-01-16 23:50:04 +07:00
|
|
|
if (error != size) {
|
|
|
|
if (error >= 0)
|
|
|
|
error = -EIO;
|
|
|
|
goto out_end_trans;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = gfs2_meta_inode_buffer(dip, &dibh);
|
|
|
|
if (error)
|
|
|
|
goto out_end_trans;
|
|
|
|
|
2012-12-14 19:36:02 +07:00
|
|
|
gfs2_trans_add_meta(dip->i_gl, dibh);
|
2011-03-23 00:54:03 +07:00
|
|
|
/* On the last dealloc, make this a regular file in case we crash.
|
|
|
|
(We don't want to free these blocks a second time.) */
|
|
|
|
if (last_dealloc)
|
|
|
|
dip->i_inode.i_mode = S_IFREG;
|
2006-11-01 03:07:05 +07:00
|
|
|
gfs2_dinode_out(dip, dibh->b_data);
|
2006-01-16 23:50:04 +07:00
|
|
|
brelse(dibh);
|
|
|
|
|
2006-09-04 23:04:26 +07:00
|
|
|
out_end_trans:
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_trans_end(sdp);
|
2006-09-04 23:04:26 +07:00
|
|
|
out_rg_gunlock:
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
|
2006-09-04 23:04:26 +07:00
|
|
|
out_rlist:
|
2006-01-16 23:50:04 +07:00
|
|
|
gfs2_rlist_free(&rlist);
|
|
|
|
gfs2_quota_unhold(dip);
|
2008-03-04 01:54:21 +07:00
|
|
|
out:
|
2014-11-20 12:18:38 +07:00
|
|
|
kvfree(ht);
|
2006-01-16 23:50:04 +07:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory
|
|
|
|
* @dip: the directory
|
|
|
|
*
|
|
|
|
* Dealloc all on-disk directory leaves to FREEMETA state
|
|
|
|
* Change on-disk inode type to "regular file"
|
|
|
|
*
|
|
|
|
* Returns: errno
|
|
|
|
*/
|
|
|
|
|
|
|
|
int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip)
|
|
|
|
{
|
2011-03-23 00:56:37 +07:00
|
|
|
struct buffer_head *bh;
|
|
|
|
struct gfs2_leaf *leaf;
|
|
|
|
u32 hsize, len;
|
|
|
|
u32 index = 0, next_index;
|
|
|
|
__be64 *lp;
|
|
|
|
u64 leaf_no;
|
|
|
|
int error = 0, last;
|
|
|
|
|
2016-08-03 00:05:27 +07:00
|
|
|
hsize = BIT(dip->i_depth);
|
2011-03-23 00:56:37 +07:00
|
|
|
|
2011-06-15 16:29:37 +07:00
|
|
|
lp = gfs2_dir_get_hash_table(dip);
|
|
|
|
if (IS_ERR(lp))
|
|
|
|
return PTR_ERR(lp);
|
2011-03-23 00:56:37 +07:00
|
|
|
|
|
|
|
while (index < hsize) {
|
2011-06-15 16:29:37 +07:00
|
|
|
leaf_no = be64_to_cpu(lp[index]);
|
2011-03-23 00:56:37 +07:00
|
|
|
if (leaf_no) {
|
|
|
|
error = get_leaf(dip, leaf_no, &bh);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
leaf = (struct gfs2_leaf *)bh->b_data;
|
2016-08-03 00:05:27 +07:00
|
|
|
len = BIT(dip->i_depth - be16_to_cpu(leaf->lf_depth));
|
2011-03-23 00:56:37 +07:00
|
|
|
|
|
|
|
next_index = (index & ~(len - 1)) + len;
|
|
|
|
last = ((next_index >= hsize) ? 1 : 0);
|
|
|
|
error = leaf_dealloc(dip, index, len, leaf_no, bh,
|
|
|
|
last);
|
|
|
|
brelse(bh);
|
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
index = next_index;
|
|
|
|
} else
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index != hsize) {
|
|
|
|
gfs2_consist_inode(dip);
|
|
|
|
error = -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
|
|
|
return error;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gfs2_diradd_alloc_required - find if adding entry will require an allocation
|
|
|
|
* @ip: the file being written to
|
|
|
|
* @filname: the filename that's going to be added
|
2014-01-06 18:28:41 +07:00
|
|
|
* @da: The structure to return dir alloc info
|
2006-01-16 23:50:04 +07:00
|
|
|
*
|
2014-01-06 18:28:41 +07:00
|
|
|
* Returns: 0 if ok, -ve on error
|
2006-01-16 23:50:04 +07:00
|
|
|
*/
|
|
|
|
|
2014-01-06 18:28:41 +07:00
|
|
|
int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name,
|
|
|
|
struct gfs2_diradd *da)
|
2006-01-16 23:50:04 +07:00
|
|
|
{
|
2014-01-08 18:05:29 +07:00
|
|
|
struct gfs2_inode *ip = GFS2_I(inode);
|
2014-01-06 18:28:41 +07:00
|
|
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
2014-01-08 18:05:29 +07:00
|
|
|
const unsigned int extra = sizeof(struct gfs2_dinode) - sizeof(struct gfs2_leaf);
|
2006-03-21 00:30:04 +07:00
|
|
|
struct gfs2_dirent *dent;
|
|
|
|
struct buffer_head *bh;
|
2006-01-16 23:50:04 +07:00
|
|
|
|
2014-01-06 18:28:41 +07:00
|
|
|
da->nr_blocks = 0;
|
2014-01-06 19:49:43 +07:00
|
|
|
da->bh = NULL;
|
|
|
|
da->dent = NULL;
|
2014-01-06 18:28:41 +07:00
|
|
|
|
2006-03-21 00:30:04 +07:00
|
|
|
dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);
|
2006-04-08 03:28:07 +07:00
|
|
|
if (!dent) {
|
2014-01-06 18:28:41 +07:00
|
|
|
da->nr_blocks = sdp->sd_max_dirres;
|
2014-01-08 18:05:29 +07:00
|
|
|
if (!(ip->i_diskflags & GFS2_DIF_EXHASH) &&
|
|
|
|
(GFS2_DIRENT_SIZE(name->len) < extra))
|
|
|
|
da->nr_blocks = 1;
|
2014-01-06 18:28:41 +07:00
|
|
|
return 0;
|
2006-04-08 03:28:07 +07:00
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
if (IS_ERR(dent))
|
|
|
|
return PTR_ERR(dent);
|
2014-09-29 19:52:04 +07:00
|
|
|
|
|
|
|
if (da->save_loc) {
|
|
|
|
da->bh = bh;
|
|
|
|
da->dent = dent;
|
|
|
|
} else {
|
|
|
|
brelse(bh);
|
|
|
|
}
|
2006-03-21 00:30:04 +07:00
|
|
|
return 0;
|
2006-01-16 23:50:04 +07:00
|
|
|
}
|
|
|
|
|