From a0a9cfb6911bfbb1721eb4350b22405f841ece6d Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 23 Apr 2009 20:10:43 +0200 Subject: [PATCH] --- yaml --- r: 149578 b: refs/heads/master c: 55f4fa4e33e90c6b25b4c8ed038392a73b654fef h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/filesystems/nilfs2.txt | 5 +- trunk/drivers/regulator/Kconfig | 9 + trunk/drivers/regulator/Makefile | 1 + trunk/drivers/regulator/max1586.c | 249 ++++++++++++++ trunk/fs/nilfs2/bmap.c | 272 +++++++++++---- trunk/fs/nilfs2/bmap.h | 135 +++----- trunk/fs/nilfs2/btnode.c | 9 +- trunk/fs/nilfs2/btnode.h | 2 +- trunk/fs/nilfs2/btree.c | 366 +++++++++------------ trunk/fs/nilfs2/btree.h | 31 +- trunk/fs/nilfs2/cpfile.c | 47 +-- trunk/fs/nilfs2/cpfile.h | 4 +- trunk/fs/nilfs2/dat.c | 36 +- trunk/fs/nilfs2/dat.h | 2 +- trunk/fs/nilfs2/direct.c | 139 ++++---- trunk/fs/nilfs2/direct.h | 20 +- trunk/fs/nilfs2/gcinode.c | 5 +- trunk/fs/nilfs2/inode.c | 18 +- trunk/fs/nilfs2/ioctl.c | 35 +- trunk/fs/nilfs2/mdt.c | 3 +- trunk/fs/nilfs2/nilfs.h | 1 - trunk/fs/nilfs2/recovery.c | 37 +-- trunk/fs/nilfs2/segbuf.c | 3 +- trunk/fs/nilfs2/seglist.h | 85 +++++ trunk/fs/nilfs2/segment.c | 130 ++++++-- trunk/fs/nilfs2/segment.h | 12 +- trunk/fs/nilfs2/sufile.c | 119 +------ trunk/fs/nilfs2/sufile.h | 62 ++-- trunk/fs/nilfs2/super.c | 9 +- trunk/fs/nilfs2/the_nilfs.c | 1 + trunk/fs/ramfs/inode.c | 9 +- trunk/include/linux/regulator/max1586.h | 52 +++ 33 files changed, 1176 insertions(+), 734 deletions(-) create mode 100644 trunk/drivers/regulator/max1586.c create mode 100644 trunk/fs/nilfs2/seglist.h create mode 100644 trunk/include/linux/regulator/max1586.h diff --git a/[refs] b/[refs] index a7e7079569bb..69780ae48ee7 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9c7cb99a8202452d3e0440a5505c5c6d262771d9 +refs/heads/master: 55f4fa4e33e90c6b25b4c8ed038392a73b654fef diff --git a/trunk/Documentation/filesystems/nilfs2.txt b/trunk/Documentation/filesystems/nilfs2.txt index 01539f410676..55c4300abfcb 100644 --- a/trunk/Documentation/filesystems/nilfs2.txt +++ b/trunk/Documentation/filesystems/nilfs2.txt @@ -39,8 +39,9 @@ Features which NILFS2 does not support yet: - extended attributes - POSIX ACLs - quotas - - fsck - - resize + - writable snapshots + - remote backup (CDP) + - data integrity - defragmentation Mount options diff --git a/trunk/drivers/regulator/Kconfig b/trunk/drivers/regulator/Kconfig index e58c0ce65aa6..707da4d23537 100644 --- a/trunk/drivers/regulator/Kconfig +++ b/trunk/drivers/regulator/Kconfig @@ -56,6 +56,15 @@ config REGULATOR_BQ24022 charging select between 100 mA and 500 mA charging current limit. +config REGULATOR_MAX1586 + tristate "Maxim 1586/1587 voltage regulator" + depends on I2C + default n + help + This driver controls a Maxim 1586 or 1587 voltage output + regulator via I2C bus. The provided regulator is suitable + for PXA27x chips to control VCC_CORE and VCC_USIM voltages. + config REGULATOR_TWL4030 bool "TI TWL4030/TWL5030/TPS695x0 PMIC" depends on TWL4030_CORE diff --git a/trunk/drivers/regulator/Makefile b/trunk/drivers/regulator/Makefile index bac133afc061..1d7de87a8e1e 100644 --- a/trunk/drivers/regulator/Makefile +++ b/trunk/drivers/regulator/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o +obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o diff --git a/trunk/drivers/regulator/max1586.c b/trunk/drivers/regulator/max1586.c new file mode 100644 index 000000000000..bbbb55fcfe8c --- /dev/null +++ b/trunk/drivers/regulator/max1586.c @@ -0,0 +1,249 @@ +/* + * max1586.c -- Voltage and current regulation for the Maxim 1586 + * + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#define MAX1586_V3_MAX_VSEL 31 +#define MAX1586_V6_MAX_VSEL 3 + +#define MAX1586_V3_MIN_UV 700000 +#define MAX1586_V3_MAX_UV 1475000 +#define MAX1586_V3_STEP_UV 25000 + +#define MAX1586_V6_MIN_UV 0 +#define MAX1586_V6_MAX_UV 3000000 + +#define I2C_V3_SELECT (0 << 5) +#define I2C_V6_SELECT (1 << 5) + +/* + * V3 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V3 to 0.700V + (x & 0x1f) * 0.025V + */ +static int max1586_v3_calc_voltage(unsigned selector) +{ + return MAX1586_V3_MIN_UV + (MAX1586_V3_STEP_UV * selector); +} + +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct i2c_client *client = rdev_get_drvdata(rdev); + unsigned selector; + u8 v3_prog; + + if (min_uV < MAX1586_V3_MIN_UV || min_uV > MAX1586_V3_MAX_UV) + return -EINVAL; + if (max_uV < MAX1586_V3_MIN_UV || max_uV > MAX1586_V3_MAX_UV) + return -EINVAL; + + selector = (min_uV - MAX1586_V3_MIN_UV) / MAX1586_V3_STEP_UV; + if (max1586_v3_calc_voltage(selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", + max1586_v3_calc_voltage(selector) / 1000); + + v3_prog = I2C_V3_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v3_prog); +} + +static int max1586_v3_list(struct regulator_dev *rdev, unsigned selector) +{ + if (selector > MAX1586_V3_MAX_VSEL) + return -EINVAL; + return max1586_v3_calc_voltage(selector); +} + +/* + * V6 voltage + * On I2C bus, sending a "x" byte to the max1586 means : + * set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3) + * As regulator framework doesn't accept voltages to be 0V, we use 1uV. + */ +static int max1586_v6_calc_voltage(unsigned selector) +{ + static int voltages_uv[] = { 1, 1800000, 2500000, 3000000 }; + + return voltages_uv[selector]; +} + +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +{ + struct i2c_client *client = rdev_get_drvdata(rdev); + unsigned selector; + u8 v6_prog; + + if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + if (max_uV < MAX1586_V6_MIN_UV || max_uV > MAX1586_V6_MAX_UV) + return -EINVAL; + + if (min_uV >= 3000000) + selector = 3; + if (min_uV < 3000000) + selector = 2; + if (min_uV < 2500000) + selector = 1; + if (min_uV < 1800000) + selector = 0; + + if (max1586_v6_calc_voltage(selector) > max_uV) + return -EINVAL; + + dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", + max1586_v6_calc_voltage(selector) / 1000); + + v6_prog = I2C_V6_SELECT | (u8) selector; + return i2c_smbus_write_byte(client, v6_prog); +} + +static int max1586_v6_list(struct regulator_dev *rdev, unsigned selector) +{ + if (selector > MAX1586_V6_MAX_VSEL) + return -EINVAL; + return max1586_v6_calc_voltage(selector); +} + +/* + * The Maxim 1586 controls V3 and V6 voltages, but offers no way of reading back + * the set up value. + */ +static struct regulator_ops max1586_v3_ops = { + .set_voltage = max1586_v3_set, + .list_voltage = max1586_v3_list, +}; + +static struct regulator_ops max1586_v6_ops = { + .set_voltage = max1586_v6_set, + .list_voltage = max1586_v6_list, +}; + +static struct regulator_desc max1586_reg[] = { + { + .name = "Output_V3", + .id = MAX1586_V3, + .ops = &max1586_v3_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V3_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, + { + .name = "Output_V6", + .id = MAX1586_V6, + .ops = &max1586_v6_ops, + .type = REGULATOR_VOLTAGE, + .n_voltages = MAX1586_V6_MAX_VSEL + 1, + .owner = THIS_MODULE, + }, +}; + +static int max1586_pmic_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct regulator_dev **rdev; + struct max1586_platform_data *pdata = client->dev.platform_data; + int i, id, ret = 0; + + rdev = kzalloc(sizeof(struct regulator_dev *) * (MAX1586_V6 + 1), + GFP_KERNEL); + if (!rdev) + return -ENOMEM; + + ret = -EINVAL; + for (i = 0; i < pdata->num_subdevs && i <= MAX1586_V6; i++) { + id = pdata->subdevs[i].id; + if (!pdata->subdevs[i].platform_data) + continue; + if (id < MAX1586_V3 || id > MAX1586_V6) { + dev_err(&client->dev, "invalid regulator id %d\n", id); + goto err; + } + rdev[i] = regulator_register(&max1586_reg[id], &client->dev, + pdata->subdevs[i].platform_data, + client); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(&client->dev, "failed to register %s\n", + max1586_reg[id].name); + goto err; + } + } + + i2c_set_clientdata(client, rdev); + dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n"); + return 0; + +err: + while (--i >= 0) + regulator_unregister(rdev[i]); + kfree(rdev); + return ret; +} + +static int max1586_pmic_remove(struct i2c_client *client) +{ + struct regulator_dev **rdev = i2c_get_clientdata(client); + int i; + + for (i = 0; i <= MAX1586_V6; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + kfree(rdev); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id max1586_id[] = { + { "max1586", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max1586_id); + +static struct i2c_driver max1586_pmic_driver = { + .probe = max1586_pmic_probe, + .remove = max1586_pmic_remove, + .driver = { + .name = "max1586", + }, + .id_table = max1586_id, +}; + +static int __init max1586_pmic_init(void) +{ + return i2c_add_driver(&max1586_pmic_driver); +} +subsys_initcall(max1586_pmic_init); + +static void __exit max1586_pmic_exit(void) +{ + i2c_del_driver(&max1586_pmic_driver); +} +module_exit(max1586_pmic_exit); + +/* Module information */ +MODULE_DESCRIPTION("MAXIM 1586 voltage regulator driver"); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff --git a/trunk/fs/nilfs2/bmap.c b/trunk/fs/nilfs2/bmap.c index 36df60b6d8a4..064279e33bbb 100644 --- a/trunk/fs/nilfs2/bmap.c +++ b/trunk/fs/nilfs2/bmap.c @@ -31,26 +31,21 @@ #include "dat.h" #include "alloc.h" -struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) -{ - return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); -} - int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, __u64 *ptrp) { - sector_t blocknr; + __u64 ptr; int ret; down_read(&bmap->b_sem); ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); if (ret < 0) goto out; - if (NILFS_BMAP_USE_VBN(bmap)) { - ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp, - &blocknr); - if (!ret) - *ptrp = blocknr; + if (bmap->b_pops->bpop_translate != NULL) { + ret = bmap->b_pops->bpop_translate(bmap, *ptrp, &ptr); + if (ret < 0) + goto out; + *ptrp = ptr; } out: @@ -58,16 +53,6 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, return ret; } -int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp, - unsigned maxblocks) -{ - int ret; - - down_read(&bmap->b_sem); - ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks); - up_read(&bmap->b_sem); - return ret; -} /** * nilfs_bmap_lookup - find a record @@ -116,7 +101,8 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) if (n < 0) return n; ret = nilfs_btree_convert_and_insert( - bmap, key, ptr, keys, ptrs, n); + bmap, key, ptr, keys, ptrs, n, + NILFS_BMAP_LARGE_LOW, NILFS_BMAP_LARGE_HIGH); if (ret == 0) bmap->b_u.u_flags |= NILFS_BMAP_LARGE; @@ -172,7 +158,8 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) if (n < 0) return n; ret = nilfs_direct_delete_and_convert( - bmap, key, keys, ptrs, n); + bmap, key, keys, ptrs, n, + NILFS_BMAP_SMALL_LOW, NILFS_BMAP_SMALL_HIGH); if (ret == 0) bmap->b_u.u_flags &= ~NILFS_BMAP_LARGE; @@ -430,6 +417,38 @@ void nilfs_bmap_sub_blocks(const struct nilfs_bmap *bmap, int n) mark_inode_dirty(bmap->b_inode); } +int nilfs_bmap_get_block(const struct nilfs_bmap *bmap, __u64 ptr, + struct buffer_head **bhp) +{ + return nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, + ptr, 0, bhp, 0); +} + +void nilfs_bmap_put_block(const struct nilfs_bmap *bmap, + struct buffer_head *bh) +{ + brelse(bh); +} + +int nilfs_bmap_get_new_block(const struct nilfs_bmap *bmap, __u64 ptr, + struct buffer_head **bhp) +{ + int ret; + + ret = nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, + ptr, 0, bhp, 1); + if (ret < 0) + return ret; + set_buffer_nilfs_volatile(*bhp); + return 0; +} + +void nilfs_bmap_delete_block(const struct nilfs_bmap *bmap, + struct buffer_head *bh) +{ + nilfs_btnode_delete(bh); +} + __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap, const struct buffer_head *bh) { @@ -457,6 +476,11 @@ __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *bmap, __u64 key) return NILFS_BMAP_INVALID_PTR; } +static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) +{ + return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); +} + #define NILFS_BMAP_GROUP_DIV 8 __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) { @@ -469,51 +493,64 @@ __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) (entries_per_group / NILFS_BMAP_GROUP_DIV); } -int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { return nilfs_dat_prepare_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_commit_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -int nilfs_bmap_start_v(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *req, - sector_t blocknr) +static int nilfs_bmap_prepare_start_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { - struct inode *dat = nilfs_bmap_get_dat(bmap); - int ret; + return nilfs_dat_prepare_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); +} - ret = nilfs_dat_prepare_start(dat, &req->bpr_req); - if (likely(!ret)) - nilfs_dat_commit_start(dat, &req->bpr_req, blocknr); - return ret; +static void nilfs_bmap_commit_start_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req, + sector_t blocknr) +{ + nilfs_dat_commit_start(nilfs_bmap_get_dat(bmap), &req->bpr_req, + blocknr); +} + +static void nilfs_bmap_abort_start_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + nilfs_dat_abort_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { return nilfs_dat_prepare_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); } -void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 0); +} + +static void nilfs_bmap_commit_end_vmdt(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { - nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, - bmap->b_ptr_type == NILFS_BMAP_PTR_VS); + nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 1); } -void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) +static void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) { nilfs_dat_abort_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); } @@ -529,44 +566,128 @@ int nilfs_bmap_mark_dirty(const struct nilfs_bmap *bmap, __u64 vblocknr) return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), vblocknr); } -int nilfs_bmap_prepare_update_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) +int nilfs_bmap_prepare_update(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) { - struct inode *dat = nilfs_bmap_get_dat(bmap); int ret; - ret = nilfs_dat_prepare_end(dat, &oldreq->bpr_req); + ret = bmap->b_pops->bpop_prepare_end_ptr(bmap, oldreq); if (ret < 0) return ret; - ret = nilfs_dat_prepare_alloc(dat, &newreq->bpr_req); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, newreq); if (ret < 0) - nilfs_dat_abort_end(dat, &oldreq->bpr_req); + bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); return ret; } -void nilfs_bmap_commit_update_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) +void nilfs_bmap_commit_update(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) { - struct inode *dat = nilfs_bmap_get_dat(bmap); + bmap->b_pops->bpop_commit_end_ptr(bmap, oldreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, newreq); +} - nilfs_dat_commit_end(dat, &oldreq->bpr_req, - bmap->b_ptr_type == NILFS_BMAP_PTR_VS); - nilfs_dat_commit_alloc(dat, &newreq->bpr_req); +void nilfs_bmap_abort_update(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *oldreq, + union nilfs_bmap_ptr_req *newreq) +{ + bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, newreq); } -void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *oldreq, - union nilfs_bmap_ptr_req *newreq) +static int nilfs_bmap_translate_v(const struct nilfs_bmap *bmap, __u64 ptr, + __u64 *ptrp) { - struct inode *dat = nilfs_bmap_get_dat(bmap); + sector_t blocknr; + int ret; - nilfs_dat_abort_end(dat, &oldreq->bpr_req); - nilfs_dat_abort_alloc(dat, &newreq->bpr_req); + ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), ptr, &blocknr); + if (ret < 0) + return ret; + if (ptrp != NULL) + *ptrp = blocknr; + return 0; } +static int nilfs_bmap_prepare_alloc_p(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + /* ignore target ptr */ + req->bpr_ptr = bmap->b_last_allocated_ptr++; + return 0; +} + +static void nilfs_bmap_commit_alloc_p(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + /* do nothing */ +} + +static void nilfs_bmap_abort_alloc_p(struct nilfs_bmap *bmap, + union nilfs_bmap_ptr_req *req) +{ + bmap->b_last_allocated_ptr--; +} + +static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_v = { + .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, + .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, + .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, + .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, + .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, + .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, + .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, + .bpop_commit_end_ptr = nilfs_bmap_commit_end_v, + .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, + + .bpop_translate = nilfs_bmap_translate_v, +}; + +static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_vmdt = { + .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, + .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, + .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, + .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, + .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, + .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, + .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, + .bpop_commit_end_ptr = nilfs_bmap_commit_end_vmdt, + .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, + + .bpop_translate = nilfs_bmap_translate_v, +}; + +static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_p = { + .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_p, + .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_p, + .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_p, + .bpop_prepare_start_ptr = NULL, + .bpop_commit_start_ptr = NULL, + .bpop_abort_start_ptr = NULL, + .bpop_prepare_end_ptr = NULL, + .bpop_commit_end_ptr = NULL, + .bpop_abort_end_ptr = NULL, + + .bpop_translate = NULL, +}; + +static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_gc = { + .bpop_prepare_alloc_ptr = NULL, + .bpop_commit_alloc_ptr = NULL, + .bpop_abort_alloc_ptr = NULL, + .bpop_prepare_start_ptr = NULL, + .bpop_commit_start_ptr = NULL, + .bpop_abort_start_ptr = NULL, + .bpop_prepare_end_ptr = NULL, + .bpop_commit_end_ptr = NULL, + .bpop_abort_end_ptr = NULL, + + .bpop_translate = NULL, +}; + static struct lock_class_key nilfs_bmap_dat_lock_key; /** @@ -593,26 +714,31 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; switch (bmap->b_inode->i_ino) { case NILFS_DAT_INO: - bmap->b_ptr_type = NILFS_BMAP_PTR_P; - bmap->b_last_allocated_key = 0; + bmap->b_pops = &nilfs_bmap_ptr_ops_p; + bmap->b_last_allocated_key = 0; /* XXX: use macro */ bmap->b_last_allocated_ptr = NILFS_BMAP_NEW_PTR_INIT; lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); break; case NILFS_CPFILE_INO: case NILFS_SUFILE_INO: - bmap->b_ptr_type = NILFS_BMAP_PTR_VS; - bmap->b_last_allocated_key = 0; + bmap->b_pops = &nilfs_bmap_ptr_ops_vmdt; + bmap->b_last_allocated_key = 0; /* XXX: use macro */ bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; break; default: - bmap->b_ptr_type = NILFS_BMAP_PTR_VM; - bmap->b_last_allocated_key = 0; + bmap->b_pops = &nilfs_bmap_ptr_ops_v; + bmap->b_last_allocated_key = 0; /* XXX: use macro */ bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; break; } return (bmap->b_u.u_flags & NILFS_BMAP_LARGE) ? - nilfs_btree_init(bmap) : nilfs_direct_init(bmap); + nilfs_btree_init(bmap, + NILFS_BMAP_LARGE_LOW, + NILFS_BMAP_LARGE_HIGH) : + nilfs_direct_init(bmap, + NILFS_BMAP_SMALL_LOW, + NILFS_BMAP_SMALL_HIGH); } /** @@ -638,7 +764,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) memset(&bmap->b_u, 0, NILFS_BMAP_SIZE); init_rwsem(&bmap->b_sem); bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; - bmap->b_ptr_type = NILFS_BMAP_PTR_U; + bmap->b_pops = &nilfs_bmap_ptr_ops_gc; bmap->b_last_allocated_key = 0; bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; bmap->b_state = 0; diff --git a/trunk/fs/nilfs2/bmap.h b/trunk/fs/nilfs2/bmap.h index b2890cdcef12..4f2708abb1ba 100644 --- a/trunk/fs/nilfs2/bmap.h +++ b/trunk/fs/nilfs2/bmap.h @@ -64,8 +64,6 @@ struct nilfs_bmap_stats { */ struct nilfs_bmap_operations { int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *); - int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *, - unsigned); int (*bop_insert)(struct nilfs_bmap *, __u64, __u64); int (*bop_delete)(struct nilfs_bmap *, __u64); void (*bop_clear)(struct nilfs_bmap *); @@ -88,6 +86,34 @@ struct nilfs_bmap_operations { }; +/** + * struct nilfs_bmap_ptr_operations - bmap ptr operation table + */ +struct nilfs_bmap_ptr_operations { + int (*bpop_prepare_alloc_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + void (*bpop_commit_alloc_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + void (*bpop_abort_alloc_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + int (*bpop_prepare_start_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + void (*bpop_commit_start_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + sector_t); + void (*bpop_abort_start_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + int (*bpop_prepare_end_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + void (*bpop_commit_end_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + void (*bpop_abort_end_ptr)(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *); + + int (*bpop_translate)(const struct nilfs_bmap *, __u64, __u64 *); +}; + + #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64)) #define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */) #define NILFS_BMAP_NEW_PTR_INIT \ @@ -105,9 +131,11 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) * @b_sem: semaphore * @b_inode: owner of bmap * @b_ops: bmap operation table + * @b_pops: bmap ptr operation table + * @b_low: low watermark of conversion + * @b_high: high watermark of conversion * @b_last_allocated_key: last allocated key for data block * @b_last_allocated_ptr: last allocated ptr for data block - * @b_ptr_type: pointer type * @b_state: state */ struct nilfs_bmap { @@ -118,22 +146,14 @@ struct nilfs_bmap { struct rw_semaphore b_sem; struct inode *b_inode; const struct nilfs_bmap_operations *b_ops; + const struct nilfs_bmap_ptr_operations *b_pops; + __u64 b_low; + __u64 b_high; __u64 b_last_allocated_key; __u64 b_last_allocated_ptr; - int b_ptr_type; int b_state; }; -/* pointer type */ -#define NILFS_BMAP_PTR_P 0 /* physical block number (i.e. LBN) */ -#define NILFS_BMAP_PTR_VS 1 /* virtual block number (single - version) */ -#define NILFS_BMAP_PTR_VM 2 /* virtual block number (has multiple - versions) */ -#define NILFS_BMAP_PTR_U (-1) /* never perform pointer operations */ - -#define NILFS_BMAP_USE_VBN(bmap) ((bmap)->b_ptr_type > 0) - /* state */ #define NILFS_BMAP_DIRTY 0x00000001 @@ -142,7 +162,6 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); -int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); @@ -163,67 +182,7 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); /* * Internal use only */ -struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *); -int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *); -static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - if (NILFS_BMAP_USE_VBN(bmap)) - return nilfs_bmap_prepare_alloc_v(bmap, req); - /* ignore target ptr */ - req->bpr_ptr = bmap->b_last_allocated_ptr++; - return 0; -} - -static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - if (NILFS_BMAP_USE_VBN(bmap)) - nilfs_bmap_commit_alloc_v(bmap, req); -} - -static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - if (NILFS_BMAP_USE_VBN(bmap)) - nilfs_bmap_abort_alloc_v(bmap, req); - else - bmap->b_last_allocated_ptr--; -} - -int nilfs_bmap_prepare_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); -void nilfs_bmap_commit_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); -void nilfs_bmap_abort_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); - -static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - return NILFS_BMAP_USE_VBN(bmap) ? - nilfs_bmap_prepare_end_v(bmap, req) : 0; -} - -static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - if (NILFS_BMAP_USE_VBN(bmap)) - nilfs_bmap_commit_end_v(bmap, req); -} - -static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, - union nilfs_bmap_ptr_req *req) -{ - if (NILFS_BMAP_USE_VBN(bmap)) - nilfs_bmap_abort_end_v(bmap, req); -} - -int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *, - sector_t); int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); @@ -234,20 +193,28 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); -int nilfs_bmap_prepare_update_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_commit_update_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); -void nilfs_bmap_abort_update_v(struct nilfs_bmap *, - union nilfs_bmap_ptr_req *, - union nilfs_bmap_ptr_req *); +int nilfs_bmap_prepare_update(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_commit_update(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); +void nilfs_bmap_abort_update(struct nilfs_bmap *, + union nilfs_bmap_ptr_req *, + union nilfs_bmap_ptr_req *); void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); +int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64, + struct buffer_head **); +void nilfs_bmap_put_block(const struct nilfs_bmap *, struct buffer_head *); +int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64, + struct buffer_head **); +void nilfs_bmap_delete_block(const struct nilfs_bmap *, struct buffer_head *); + + /* Assume that bmap semaphore is locked. */ static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap) { diff --git a/trunk/fs/nilfs2/btnode.c b/trunk/fs/nilfs2/btnode.c index 7e0b61be212e..4cc07b2c30e0 100644 --- a/trunk/fs/nilfs2/btnode.c +++ b/trunk/fs/nilfs2/btnode.c @@ -46,18 +46,15 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); } -static struct address_space_operations def_btnode_aops = { - .sync_page = block_sync_page, -}; +static struct address_space_operations def_btnode_aops; -void nilfs_btnode_cache_init(struct address_space *btnc, - struct backing_dev_info *bdi) +void nilfs_btnode_cache_init(struct address_space *btnc) { btnc->host = NULL; /* can safely set to host inode ? */ btnc->flags = 0; mapping_set_gfp_mask(btnc, GFP_NOFS); btnc->assoc_mapping = NULL; - btnc->backing_dev_info = bdi; + btnc->backing_dev_info = &default_backing_dev_info; btnc->a_ops = &def_btnode_aops; } diff --git a/trunk/fs/nilfs2/btnode.h b/trunk/fs/nilfs2/btnode.h index 3e2275172ed6..35faa86444a7 100644 --- a/trunk/fs/nilfs2/btnode.h +++ b/trunk/fs/nilfs2/btnode.h @@ -38,7 +38,7 @@ struct nilfs_btnode_chkey_ctxt { }; void nilfs_btnode_cache_init_once(struct address_space *); -void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *); +void nilfs_btnode_cache_init(struct address_space *); void nilfs_btnode_cache_clear(struct address_space *); int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, struct buffer_head **, int); diff --git a/trunk/fs/nilfs2/btree.c b/trunk/fs/nilfs2/btree.c index aa412724b64e..6b37a2767293 100644 --- a/trunk/fs/nilfs2/btree.c +++ b/trunk/fs/nilfs2/btree.c @@ -29,7 +29,6 @@ #include "btnode.h" #include "btree.h" #include "alloc.h" -#include "dat.h" /** * struct nilfs_btree_path - A path on which B-tree operations are executed @@ -110,7 +109,8 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, level < NILFS_BTREE_LEVEL_MAX; level++) { if (path[level].bp_bh != NULL) { - brelse(path[level].bp_bh); + nilfs_bmap_put_block(&btree->bt_bmap, + path[level].bp_bh); path[level].bp_bh = NULL; } /* sib_bh is released or deleted by prepare or commit @@ -123,29 +123,10 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, } } + /* * B-tree node operations */ -static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr, - struct buffer_head **bhp) -{ - struct address_space *btnc = - &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; - return nilfs_btnode_get(btnc, ptr, 0, bhp, 0); -} - -static int nilfs_btree_get_new_block(const struct nilfs_btree *btree, - __u64 ptr, struct buffer_head **bhp) -{ - struct address_space *btnc = - &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; - int ret; - - ret = nilfs_btnode_get(btnc, ptr, 0, bhp, 1); - if (!ret) - set_buffer_nilfs_volatile(*bhp); - return ret; -} static inline int nilfs_btree_node_get_flags(const struct nilfs_btree *btree, @@ -507,7 +488,8 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, path[level].bp_index = index; for (level--; level >= minlevel; level--) { - ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, + &path[level].bp_bh); if (ret < 0) return ret; node = nilfs_btree_get_nonroot_node(btree, path, level); @@ -553,7 +535,8 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree, path[level].bp_index = index; for (level--; level > 0; level--) { - ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, + &path[level].bp_bh); if (ret < 0) return ret; node = nilfs_btree_get_nonroot_node(btree, path, level); @@ -596,87 +579,6 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap, return ret; } -static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, - __u64 key, __u64 *ptrp, unsigned maxblocks) -{ - struct nilfs_btree *btree = (struct nilfs_btree *)bmap; - struct nilfs_btree_path *path; - struct nilfs_btree_node *node; - struct inode *dat = NULL; - __u64 ptr, ptr2; - sector_t blocknr; - int level = NILFS_BTREE_LEVEL_NODE_MIN; - int ret, cnt, index, maxlevel; - - path = nilfs_btree_alloc_path(btree); - if (path == NULL) - return -ENOMEM; - nilfs_btree_init_path(btree, path); - ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); - if (ret < 0) - goto out; - - if (NILFS_BMAP_USE_VBN(bmap)) { - dat = nilfs_bmap_get_dat(bmap); - ret = nilfs_dat_translate(dat, ptr, &blocknr); - if (ret < 0) - goto out; - ptr = blocknr; - } - cnt = 1; - if (cnt == maxblocks) - goto end; - - maxlevel = nilfs_btree_height(btree) - 1; - node = nilfs_btree_get_node(btree, path, level); - index = path[level].bp_index + 1; - for (;;) { - while (index < nilfs_btree_node_get_nchildren(btree, node)) { - if (nilfs_btree_node_get_key(btree, node, index) != - key + cnt) - goto end; - ptr2 = nilfs_btree_node_get_ptr(btree, node, index); - if (dat) { - ret = nilfs_dat_translate(dat, ptr2, &blocknr); - if (ret < 0) - goto out; - ptr2 = blocknr; - } - if (ptr2 != ptr + cnt || ++cnt == maxblocks) - goto end; - index++; - continue; - } - if (level == maxlevel) - break; - - /* look-up right sibling node */ - node = nilfs_btree_get_node(btree, path, level + 1); - index = path[level + 1].bp_index + 1; - if (index >= nilfs_btree_node_get_nchildren(btree, node) || - nilfs_btree_node_get_key(btree, node, index) != key + cnt) - break; - ptr2 = nilfs_btree_node_get_ptr(btree, node, index); - path[level + 1].bp_index = index; - - brelse(path[level].bp_bh); - path[level].bp_bh = NULL; - ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh); - if (ret < 0) - goto out; - node = nilfs_btree_get_nonroot_node(btree, path, level); - index = 0; - path[level].bp_index = index; - } - end: - *ptrp = ptr; - ret = cnt; - out: - nilfs_btree_clear_path(btree, path); - nilfs_btree_free_path(btree, path); - return ret; -} - static void nilfs_btree_promote_key(struct nilfs_btree *btree, struct nilfs_btree_path *path, int level, __u64 key) @@ -767,13 +669,13 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree, nilfs_btree_node_get_key(btree, node, 0)); if (move) { - brelse(path[level].bp_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index += lnchildren; path[level + 1].bp_index--; } else { - brelse(path[level].bp_sib_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level].bp_index -= n; } @@ -820,14 +722,14 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree, path[level + 1].bp_index--; if (move) { - brelse(path[level].bp_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index -= nilfs_btree_node_get_nchildren(btree, node); path[level + 1].bp_index++; } else { - brelse(path[level].bp_sib_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -879,7 +781,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, *keyp = nilfs_btree_node_get_key(btree, right, 0); *ptrp = path[level].bp_newreq.bpr_ptr; - brelse(path[level].bp_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; } else { @@ -888,7 +790,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, *keyp = nilfs_btree_node_get_key(btree, right, 0); *ptrp = path[level].bp_newreq.bpr_ptr; - brelse(path[level].bp_sib_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -995,12 +897,12 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, level = NILFS_BTREE_LEVEL_DATA; /* allocate a new ptr for data block */ - if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) + if (btree->bt_ops->btop_find_target != NULL) path[level].bp_newreq.bpr_ptr = - nilfs_btree_find_target_v(btree, path, key); + btree->bt_ops->btop_find_target(btree, path, key); - ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( + &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_data; @@ -1022,7 +924,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, if (pindex > 0) { sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex - 1); - ret = nilfs_btree_get_block(btree, sibptr, &bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, + &bh); if (ret < 0) goto err_out_child_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1033,7 +936,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, stats->bs_nblocks++; goto out; } else - brelse(bh); + nilfs_bmap_put_block(&btree->bt_bmap, bh); } /* right sibling */ @@ -1041,7 +944,8 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, nilfs_btree_node_get_nchildren(btree, parent) - 1) { sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex + 1); - ret = nilfs_btree_get_block(btree, sibptr, &bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, + &bh); if (ret < 0) goto err_out_child_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1052,19 +956,19 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, stats->bs_nblocks++; goto out; } else - brelse(bh); + nilfs_bmap_put_block(&btree->bt_bmap, bh); } /* split */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( + &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; - ret = nilfs_btree_get_new_block(btree, - path[level].bp_newreq.bpr_ptr, - &bh); + ret = nilfs_bmap_get_new_block(&btree->bt_bmap, + path[level].bp_newreq.bpr_ptr, + &bh); if (ret < 0) goto err_out_curr_node; @@ -1090,12 +994,12 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* grow */ path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; - ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( + &btree->bt_bmap, &path[level].bp_newreq); if (ret < 0) goto err_out_child_node; - ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, - &bh); + ret = nilfs_bmap_get_new_block(&btree->bt_bmap, + path[level].bp_newreq.bpr_ptr, &bh); if (ret < 0) goto err_out_curr_node; @@ -1119,16 +1023,18 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, /* error */ err_out_curr_node: - nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); err_out_child_node: for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { - nilfs_btnode_delete(path[level].bp_sib_bh); - nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, - &path[level].bp_newreq); + nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr( + &btree->bt_bmap, &path[level].bp_newreq); } - nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); + btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, + &path[level].bp_newreq); err_out_data: *levelp = level; stats->bs_nblocks = 0; @@ -1143,12 +1049,14 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; - if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) - nilfs_btree_set_target_v(btree, key, ptr); + if (btree->bt_ops->btop_set_target != NULL) + btree->bt_ops->btop_set_target(btree, key, ptr); for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { - nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, - &path[level - 1].bp_newreq); + if (btree->bt_bmap.b_pops->bpop_commit_alloc_ptr != NULL) { + btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( + &btree->bt_bmap, &path[level - 1].bp_newreq); + } path[level].bp_op(btree, path, level, &key, &ptr); } @@ -1245,7 +1153,7 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree, nilfs_btree_promote_key(btree, path, level + 1, nilfs_btree_node_get_key(btree, node, 0)); - brelse(path[level].bp_sib_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level].bp_index += n; } @@ -1284,7 +1192,7 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree, nilfs_btree_node_get_key(btree, right, 0)); path[level + 1].bp_index--; - brelse(path[level].bp_sib_bh); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; } @@ -1313,7 +1221,7 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree, unlock_buffer(path[level].bp_bh); unlock_buffer(path[level].bp_sib_bh); - nilfs_btnode_delete(path[level].bp_bh); + nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); path[level].bp_bh = path[level].bp_sib_bh; path[level].bp_sib_bh = NULL; path[level].bp_index += nilfs_btree_node_get_nchildren(btree, left); @@ -1344,7 +1252,7 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree, unlock_buffer(path[level].bp_bh); unlock_buffer(path[level].bp_sib_bh); - nilfs_btnode_delete(path[level].bp_sib_bh); + nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); path[level].bp_sib_bh = NULL; path[level + 1].bp_index++; } @@ -1368,7 +1276,7 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree, nilfs_btree_node_move_left(btree, root, child, n); unlock_buffer(path[level].bp_bh); - nilfs_btnode_delete(path[level].bp_bh); + nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); path[level].bp_bh = NULL; } @@ -1392,10 +1300,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, path[level].bp_oldreq.bpr_ptr = nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); - ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, - &path[level].bp_oldreq); - if (ret < 0) - goto err_out_child_node; + if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { + ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( + &btree->bt_bmap, &path[level].bp_oldreq); + if (ret < 0) + goto err_out_child_node; + } if (nilfs_btree_node_get_nchildren(btree, node) > nilfs_btree_node_nchildren_min(btree, node)) { @@ -1411,7 +1321,8 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* left sibling */ sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex - 1); - ret = nilfs_btree_get_block(btree, sibptr, &bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, + &bh); if (ret < 0) goto err_out_curr_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1432,7 +1343,8 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* right sibling */ sibptr = nilfs_btree_node_get_ptr(btree, parent, pindex + 1); - ret = nilfs_btree_get_block(btree, sibptr, &bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, + &bh); if (ret < 0) goto err_out_curr_node; sib = (struct nilfs_btree_node *)bh->b_data; @@ -1469,12 +1381,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, node = nilfs_btree_get_root(btree); path[level].bp_oldreq.bpr_ptr = nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); - - ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, - &path[level].bp_oldreq); - if (ret < 0) - goto err_out_child_node; - + if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { + ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( + &btree->bt_bmap, &path[level].bp_oldreq); + if (ret < 0) + goto err_out_child_node; + } /* child of the root node is deleted */ path[level].bp_op = nilfs_btree_do_delete; stats->bs_nblocks++; @@ -1486,12 +1398,15 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, /* error */ err_out_curr_node: - nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq); + if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) + btree->bt_bmap.b_pops->bpop_abort_end_ptr( + &btree->bt_bmap, &path[level].bp_oldreq); err_out_child_node: for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { - brelse(path[level].bp_sib_bh); - nilfs_bmap_abort_end_ptr(&btree->bt_bmap, - &path[level].bp_oldreq); + nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); + if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) + btree->bt_bmap.b_pops->bpop_abort_end_ptr( + &btree->bt_bmap, &path[level].bp_oldreq); } *levelp = level; stats->bs_nblocks = 0; @@ -1505,8 +1420,9 @@ static void nilfs_btree_commit_delete(struct nilfs_btree *btree, int level; for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { - nilfs_bmap_commit_end_ptr(&btree->bt_bmap, - &path[level].bp_oldreq); + if (btree->bt_bmap.b_pops->bpop_commit_end_ptr != NULL) + btree->bt_bmap.b_pops->bpop_commit_end_ptr( + &btree->bt_bmap, &path[level].bp_oldreq); path[level].bp_op(btree, path, level, NULL, NULL); } @@ -1585,7 +1501,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) if (nchildren > 1) return 0; ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); - ret = nilfs_btree_get_block(btree, ptr, &bh); + ret = nilfs_bmap_get_block(bmap, ptr, &bh); if (ret < 0) return ret; node = (struct nilfs_btree_node *)bh->b_data; @@ -1599,9 +1515,9 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) nextmaxkey = (nchildren > 1) ? nilfs_btree_node_get_key(btree, node, nchildren - 2) : 0; if (bh != NULL) - brelse(bh); + nilfs_bmap_put_block(bmap, bh); - return (maxkey == key) && (nextmaxkey < NILFS_BMAP_LARGE_LOW); + return (maxkey == key) && (nextmaxkey < bmap->b_low); } static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, @@ -1626,7 +1542,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, nchildren = nilfs_btree_node_get_nchildren(btree, root); WARN_ON(nchildren > 1); ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); - ret = nilfs_btree_get_block(btree, ptr, &bh); + ret = nilfs_bmap_get_block(bmap, ptr, &bh); if (ret < 0) return ret; node = (struct nilfs_btree_node *)bh->b_data; @@ -1647,7 +1563,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, } if (bh != NULL) - brelse(bh); + nilfs_bmap_put_block(bmap, bh); return nitems; } @@ -1668,10 +1584,10 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* for data */ /* cannot find near ptr */ - if (NILFS_BMAP_USE_VBN(bmap)) - dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key); - - ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq); + if (btree->bt_ops->btop_find_target != NULL) + dreq->bpr_ptr + = btree->bt_ops->btop_find_target(btree, NULL, key); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, dreq); if (ret < 0) return ret; @@ -1679,11 +1595,11 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, stats->bs_nblocks++; if (nreq != NULL) { nreq->bpr_ptr = dreq->bpr_ptr + 1; - ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq); + ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, nreq); if (ret < 0) goto err_out_dreq; - ret = nilfs_btree_get_new_block(btree, nreq->bpr_ptr, &bh); + ret = nilfs_bmap_get_new_block(bmap, nreq->bpr_ptr, &bh); if (ret < 0) goto err_out_nreq; @@ -1696,9 +1612,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, /* error */ err_out_nreq: - nilfs_bmap_abort_alloc_ptr(bmap, nreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, nreq); err_out_dreq: - nilfs_bmap_abort_alloc_ptr(bmap, dreq); + bmap->b_pops->bpop_abort_alloc_ptr(bmap, dreq); stats->bs_nblocks = 0; return ret; @@ -1708,7 +1624,7 @@ static void nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr, const __u64 *keys, const __u64 *ptrs, - int n, + int n, __u64 low, __u64 high, union nilfs_bmap_ptr_req *dreq, union nilfs_bmap_ptr_req *nreq, struct buffer_head *bh) @@ -1726,10 +1642,12 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, /* convert and insert */ btree = (struct nilfs_btree *)bmap; - nilfs_btree_init(bmap); + nilfs_btree_init(bmap, low, high); if (nreq != NULL) { - nilfs_bmap_commit_alloc_ptr(bmap, dreq); - nilfs_bmap_commit_alloc_ptr(bmap, nreq); + if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) { + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); + bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); + } /* create child node at level 1 */ lock_buffer(bh); @@ -1743,7 +1661,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_bmap_set_dirty(bmap); unlock_buffer(bh); - brelse(bh); + nilfs_bmap_put_block(bmap, bh); /* create root node at level 2 */ node = nilfs_btree_get_root(btree); @@ -1751,7 +1669,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, 2, 1, &keys[0], &tmpptr); } else { - nilfs_bmap_commit_alloc_ptr(bmap, dreq); + if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) + bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); /* create root node at level 1 */ node = nilfs_btree_get_root(btree); @@ -1763,8 +1682,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, nilfs_bmap_set_dirty(bmap); } - if (NILFS_BMAP_USE_VBN(bmap)) - nilfs_btree_set_target_v(btree, key, dreq->bpr_ptr); + if (btree->bt_ops->btop_set_target != NULL) + btree->bt_ops->btop_set_target(btree, key, dreq->bpr_ptr); } /** @@ -1775,10 +1694,13 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, * @keys: * @ptrs: * @n: + * @low: + * @high: */ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr, - const __u64 *keys, const __u64 *ptrs, int n) + const __u64 *keys, const __u64 *ptrs, + int n, __u64 low, __u64 high) { struct buffer_head *bh; union nilfs_bmap_ptr_req dreq, nreq, *di, *ni; @@ -1803,7 +1725,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, if (ret < 0) return ret; nilfs_btree_commit_convert_and_insert(bmap, key, ptr, keys, ptrs, n, - di, ni, bh); + low, high, di, ni, bh); nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); return 0; } @@ -1832,9 +1754,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, nilfs_btree_node_get_ptr(btree, parent, path[level + 1].bp_index); path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; - ret = nilfs_bmap_prepare_update_v(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + ret = nilfs_bmap_prepare_update(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (ret < 0) return ret; @@ -1846,9 +1768,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, &path[level].bp_ctxt); if (ret < 0) { - nilfs_bmap_abort_update_v(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_abort_update(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); return ret; } } @@ -1862,9 +1784,9 @@ static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, { struct nilfs_btree_node *parent; - nilfs_bmap_commit_update_v(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_commit_update(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (buffer_nilfs_node(path[level].bp_bh)) { nilfs_btnode_commit_change_key( @@ -1883,9 +1805,9 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, struct nilfs_btree_path *path, int level) { - nilfs_bmap_abort_update_v(&btree->bt_bmap, - &path[level].bp_oldreq, - &path[level].bp_newreq); + nilfs_bmap_abort_update(&btree->bt_bmap, + &path[level].bp_oldreq, + &path[level].bp_newreq); if (buffer_nilfs_node(path[level].bp_bh)) nilfs_btnode_abort_change_key( &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, @@ -2008,9 +1930,7 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, goto out; } - ret = NILFS_BMAP_USE_VBN(bmap) ? - nilfs_btree_propagate_v(btree, path, level, bh) : - nilfs_btree_propagate_p(btree, path, level, bh); + ret = btree->bt_ops->btop_propagate(btree, path, level, bh); out: nilfs_btree_clear_path(btree, path); @@ -2146,9 +2066,12 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, ptr = nilfs_btree_node_get_ptr(btree, parent, path[level + 1].bp_index); req.bpr_ptr = ptr; - ret = nilfs_bmap_start_v(&btree->bt_bmap, &req, blocknr); - if (unlikely(ret < 0)) + ret = btree->bt_bmap.b_pops->bpop_prepare_start_ptr(&btree->bt_bmap, + &req); + if (ret < 0) return ret; + btree->bt_bmap.b_pops->bpop_commit_start_ptr(&btree->bt_bmap, + &req, blocknr); key = nilfs_btree_node_get_key(btree, parent, path[level + 1].bp_index); @@ -2191,9 +2114,8 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, goto out; } - ret = NILFS_BMAP_USE_VBN(bmap) ? - nilfs_btree_assign_v(btree, path, level, bh, blocknr, binfo) : - nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo); + ret = btree->bt_ops->btop_assign(btree, path, level, bh, + blocknr, binfo); out: nilfs_btree_clear_path(btree, path); @@ -2249,7 +2171,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) WARN_ON(ret == -ENOENT); goto out; } - ret = nilfs_btree_get_block(btree, ptr, &bh); + ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, &bh); if (ret < 0) { WARN_ON(ret == -ENOENT); goto out; @@ -2257,7 +2179,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) if (!buffer_dirty(bh)) nilfs_btnode_mark_dirty(bh); - brelse(bh); + nilfs_bmap_put_block(&btree->bt_bmap, bh); if (!nilfs_bmap_dirty(&btree->bt_bmap)) nilfs_bmap_set_dirty(&btree->bt_bmap); @@ -2269,7 +2191,6 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) static const struct nilfs_bmap_operations nilfs_btree_ops = { .bop_lookup = nilfs_btree_lookup, - .bop_lookup_contig = nilfs_btree_lookup_contig, .bop_insert = nilfs_btree_insert, .bop_delete = nilfs_btree_delete, .bop_clear = NULL, @@ -2289,7 +2210,6 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = { static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_lookup = NULL, - .bop_lookup_contig = NULL, .bop_insert = NULL, .bop_delete = NULL, .bop_clear = NULL, @@ -2307,13 +2227,43 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { .bop_gather_data = NULL, }; -int nilfs_btree_init(struct nilfs_bmap *bmap) +static const struct nilfs_btree_operations nilfs_btree_ops_v = { + .btop_find_target = nilfs_btree_find_target_v, + .btop_set_target = nilfs_btree_set_target_v, + .btop_propagate = nilfs_btree_propagate_v, + .btop_assign = nilfs_btree_assign_v, +}; + +static const struct nilfs_btree_operations nilfs_btree_ops_p = { + .btop_find_target = NULL, + .btop_set_target = NULL, + .btop_propagate = nilfs_btree_propagate_p, + .btop_assign = nilfs_btree_assign_p, +}; + +int nilfs_btree_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) { + struct nilfs_btree *btree; + + btree = (struct nilfs_btree *)bmap; bmap->b_ops = &nilfs_btree_ops; + bmap->b_low = low; + bmap->b_high = high; + switch (bmap->b_inode->i_ino) { + case NILFS_DAT_INO: + btree->bt_ops = &nilfs_btree_ops_p; + break; + default: + btree->bt_ops = &nilfs_btree_ops_v; + break; + } + return 0; } void nilfs_btree_init_gc(struct nilfs_bmap *bmap) { + bmap->b_low = NILFS_BMAP_LARGE_LOW; + bmap->b_high = NILFS_BMAP_LARGE_HIGH; bmap->b_ops = &nilfs_btree_ops_gc; } diff --git a/trunk/fs/nilfs2/btree.h b/trunk/fs/nilfs2/btree.h index 0e72bbbc6b64..4766deb52fb1 100644 --- a/trunk/fs/nilfs2/btree.h +++ b/trunk/fs/nilfs2/btree.h @@ -33,6 +33,28 @@ struct nilfs_btree; struct nilfs_btree_path; +/** + * struct nilfs_btree_operations - B-tree operation table + */ +struct nilfs_btree_operations { + __u64 (*btop_find_target)(const struct nilfs_btree *, + const struct nilfs_btree_path *, __u64); + void (*btop_set_target)(struct nilfs_btree *, __u64, __u64); + + struct the_nilfs *(*btop_get_nilfs)(struct nilfs_btree *); + + int (*btop_propagate)(struct nilfs_btree *, + struct nilfs_btree_path *, + int, + struct buffer_head *); + int (*btop_assign)(struct nilfs_btree *, + struct nilfs_btree_path *, + int, + struct buffer_head **, + sector_t, + union nilfs_binfo *); +}; + /** * struct nilfs_btree_node - B-tree node * @bn_flags: flags @@ -58,9 +80,13 @@ struct nilfs_btree_node { /** * struct nilfs_btree - B-tree structure * @bt_bmap: bmap base structure + * @bt_ops: B-tree operation table */ struct nilfs_btree { struct nilfs_bmap bt_bmap; + + /* B-tree-specific members */ + const struct nilfs_btree_operations *bt_ops; }; @@ -82,9 +108,10 @@ struct nilfs_btree { int nilfs_btree_path_cache_init(void); void nilfs_btree_path_cache_destroy(void); -int nilfs_btree_init(struct nilfs_bmap *); +int nilfs_btree_init(struct nilfs_bmap *, __u64, __u64); int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, - const __u64 *, const __u64 *, int); + const __u64 *, const __u64 *, + int, __u64, __u64); void nilfs_btree_init_gc(struct nilfs_bmap *); #endif /* _NILFS_BTREE_H */ diff --git a/trunk/fs/nilfs2/cpfile.c b/trunk/fs/nilfs2/cpfile.c index 7d49813f66d6..cadd36b14d07 100644 --- a/trunk/fs/nilfs2/cpfile.c +++ b/trunk/fs/nilfs2/cpfile.c @@ -295,6 +295,10 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, return -EINVAL; } + /* cannot delete the latest checkpoint */ + if (start == nilfs_mdt_cno(cpfile) - 1) + return -EPERM; + down_write(&NILFS_MDT(cpfile)->mi_sem); ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); @@ -380,10 +384,9 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, } static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, - void *buf, unsigned cisz, size_t nci) + struct nilfs_cpinfo *ci, size_t nci) { struct nilfs_checkpoint *cp; - struct nilfs_cpinfo *ci = buf; struct buffer_head *bh; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; @@ -407,22 +410,17 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, kaddr = kmap_atomic(bh->b_page, KM_USER0); cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { - if (!nilfs_checkpoint_invalid(cp)) { - nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, - ci); - ci = (void *)ci + cisz; - n++; - } + if (!nilfs_checkpoint_invalid(cp)) + nilfs_cpfile_checkpoint_to_cpinfo( + cpfile, cp, &ci[n++]); } kunmap_atomic(kaddr, KM_USER0); brelse(bh); } ret = n; - if (n > 0) { - ci = (void *)ci - cisz; - *cnop = ci->ci_cno + 1; - } + if (n > 0) + *cnop = ci[n - 1].ci_cno + 1; out: up_read(&NILFS_MDT(cpfile)->mi_sem); @@ -430,12 +428,11 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, } static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, - void *buf, unsigned cisz, size_t nci) + struct nilfs_cpinfo *ci, size_t nci) { struct buffer_head *bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp; - struct nilfs_cpinfo *ci = buf; __u64 curr = *cnop, next; unsigned long curr_blkoff, next_blkoff; void *kaddr; @@ -475,9 +472,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, if (unlikely(nilfs_checkpoint_invalid(cp) || !nilfs_checkpoint_snapshot(cp))) break; - nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); - ci = (void *)ci + cisz; - n++; + nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); if (next == 0) break; /* reach end of the snapshot list */ @@ -516,13 +511,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, */ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, - void *buf, unsigned cisz, size_t nci) + struct nilfs_cpinfo *ci, size_t nci) { switch (mode) { case NILFS_CHECKPOINT: - return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); + return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); case NILFS_SNAPSHOT: - return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); + return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); default: return -EINVAL; } @@ -538,14 +533,20 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) struct nilfs_cpinfo ci; __u64 tcno = cno; ssize_t nci; + int ret; - nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); + nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); if (nci < 0) return nci; else if (nci == 0 || ci.ci_cno != cno) return -ENOENT; - else if (nilfs_cpinfo_snapshot(&ci)) - return -EBUSY; + + /* cannot delete the latest checkpoint nor snapshots */ + ret = nilfs_cpinfo_snapshot(&ci); + if (ret < 0) + return ret; + else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1) + return -EPERM; return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); } diff --git a/trunk/fs/nilfs2/cpfile.h b/trunk/fs/nilfs2/cpfile.h index 788a45950197..1a8a1008c342 100644 --- a/trunk/fs/nilfs2/cpfile.h +++ b/trunk/fs/nilfs2/cpfile.h @@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64); int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); int nilfs_cpfile_is_snapshot(struct inode *, __u64); int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); -ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, void *, unsigned, - size_t); +ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, + struct nilfs_cpinfo *, size_t); #endif /* _NILFS_CPFILE_H */ diff --git a/trunk/fs/nilfs2/dat.c b/trunk/fs/nilfs2/dat.c index 0b2710e2d565..bb8a5818e7f1 100644 --- a/trunk/fs/nilfs2/dat.c +++ b/trunk/fs/nilfs2/dat.c @@ -92,6 +92,21 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) nilfs_palloc_abort_alloc_entry(dat, req); } +int nilfs_dat_prepare_free(struct inode *dat, struct nilfs_palloc_req *req) +{ + int ret; + + ret = nilfs_palloc_prepare_free_entry(dat, req); + if (ret < 0) + return ret; + ret = nilfs_dat_prepare_entry(dat, req, 0); + if (ret < 0) { + nilfs_palloc_abort_free_entry(dat, req); + return ret; + } + return 0; +} + void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; @@ -376,37 +391,36 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) return ret; } -ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, +ssize_t nilfs_dat_get_vinfo(struct inode *dat, struct nilfs_vinfo *vinfo, size_t nvi) { struct buffer_head *entry_bh; struct nilfs_dat_entry *entry; - struct nilfs_vinfo *vinfo = buf; __u64 first, last; void *kaddr; unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; int i, j, n, ret; for (i = 0; i < nvi; i += n) { - ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr, + ret = nilfs_palloc_get_entry_block(dat, vinfo[i].vi_vblocknr, 0, &entry_bh); if (ret < 0) return ret; kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); /* last virtual block number in this block */ - first = vinfo->vi_vblocknr; + first = vinfo[i].vi_vblocknr; do_div(first, entries_per_block); first *= entries_per_block; last = first + entries_per_block - 1; for (j = i, n = 0; - j < nvi && vinfo->vi_vblocknr >= first && - vinfo->vi_vblocknr <= last; - j++, n++, vinfo = (void *)vinfo + visz) { + j < nvi && vinfo[j].vi_vblocknr >= first && + vinfo[j].vi_vblocknr <= last; + j++, n++) { entry = nilfs_palloc_block_get_entry( - dat, vinfo->vi_vblocknr, entry_bh, kaddr); - vinfo->vi_start = le64_to_cpu(entry->de_start); - vinfo->vi_end = le64_to_cpu(entry->de_end); - vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr); + dat, vinfo[j].vi_vblocknr, entry_bh, kaddr); + vinfo[j].vi_start = le64_to_cpu(entry->de_start); + vinfo[j].vi_end = le64_to_cpu(entry->de_end); + vinfo[j].vi_blocknr = le64_to_cpu(entry->de_blocknr); } kunmap_atomic(kaddr, KM_USER0); brelse(entry_bh); diff --git a/trunk/fs/nilfs2/dat.h b/trunk/fs/nilfs2/dat.h index d328b81eead4..d9560654a4b7 100644 --- a/trunk/fs/nilfs2/dat.h +++ b/trunk/fs/nilfs2/dat.h @@ -47,6 +47,6 @@ void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); int nilfs_dat_mark_dirty(struct inode *, __u64); int nilfs_dat_freev(struct inode *, __u64 *, size_t); int nilfs_dat_move(struct inode *, __u64, sector_t); -ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t); +ssize_t nilfs_dat_get_vinfo(struct inode *, struct nilfs_vinfo *, size_t); #endif /* _NILFS_DAT_H */ diff --git a/trunk/fs/nilfs2/direct.c b/trunk/fs/nilfs2/direct.c index 342d9765df8d..c6379e482781 100644 --- a/trunk/fs/nilfs2/direct.c +++ b/trunk/fs/nilfs2/direct.c @@ -25,7 +25,6 @@ #include "page.h" #include "direct.h" #include "alloc.h" -#include "dat.h" static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) { @@ -63,47 +62,6 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap, return 0; } -static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap, - __u64 key, __u64 *ptrp, - unsigned maxblocks) -{ - struct nilfs_direct *direct = (struct nilfs_direct *)bmap; - struct inode *dat = NULL; - __u64 ptr, ptr2; - sector_t blocknr; - int ret, cnt; - - if (key > NILFS_DIRECT_KEY_MAX || - (ptr = nilfs_direct_get_ptr(direct, key)) == - NILFS_BMAP_INVALID_PTR) - return -ENOENT; - - if (NILFS_BMAP_USE_VBN(bmap)) { - dat = nilfs_bmap_get_dat(bmap); - ret = nilfs_dat_translate(dat, ptr, &blocknr); - if (ret < 0) - return ret; - ptr = blocknr; - } - - maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1); - for (cnt = 1; cnt < maxblocks && - (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) != - NILFS_BMAP_INVALID_PTR; - cnt++) { - if (dat) { - ret = nilfs_dat_translate(dat, ptr2, &blocknr); - if (ret < 0) - return ret; - ptr2 = blocknr; - } - if (ptr2 != ptr + cnt) - break; - } - *ptrp = ptr; - return cnt; -} - static __u64 nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) { @@ -132,9 +90,10 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, { int ret; - if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) - req->bpr_ptr = nilfs_direct_find_target_v(direct, key); - ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req); + if (direct->d_ops->dop_find_target != NULL) + req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); + ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, + req); if (ret < 0) return ret; @@ -152,14 +111,16 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, bh = (struct buffer_head *)((unsigned long)ptr); set_buffer_nilfs_volatile(bh); - nilfs_bmap_commit_alloc_ptr(&direct->d_bmap, req); + if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) + direct->d_bmap.b_pops->bpop_commit_alloc_ptr( + &direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, req->bpr_ptr); if (!nilfs_bmap_dirty(&direct->d_bmap)) nilfs_bmap_set_dirty(&direct->d_bmap); - if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) - nilfs_direct_set_target_v(direct, key, req->bpr_ptr); + if (direct->d_ops->dop_set_target != NULL) + direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); } static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) @@ -191,18 +152,25 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, { int ret; - req->bpr_ptr = nilfs_direct_get_ptr(direct, key); - ret = nilfs_bmap_prepare_end_ptr(&direct->d_bmap, req); - if (!ret) - stats->bs_nblocks = 1; - return ret; + if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { + req->bpr_ptr = nilfs_direct_get_ptr(direct, key); + ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( + &direct->d_bmap, req); + if (ret < 0) + return ret; + } + + stats->bs_nblocks = 1; + return 0; } static void nilfs_direct_commit_delete(struct nilfs_direct *direct, union nilfs_bmap_ptr_req *req, __u64 key) { - nilfs_bmap_commit_end_ptr(&direct->d_bmap, req); + if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) + direct->d_bmap.b_pops->bpop_commit_end_ptr( + &direct->d_bmap, req); nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); } @@ -276,7 +244,8 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap, } int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, - __u64 key, __u64 *keys, __u64 *ptrs, int n) + __u64 key, __u64 *keys, __u64 *ptrs, + int n, __u64 low, __u64 high) { struct nilfs_direct *direct; __le64 *dptrs; @@ -306,7 +275,8 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, dptrs[i] = NILFS_BMAP_INVALID_PTR; } - nilfs_direct_init(bmap); + nilfs_direct_init(bmap, low, high); + return 0; } @@ -323,11 +293,11 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, if (!buffer_nilfs_volatile(bh)) { oldreq.bpr_ptr = ptr; newreq.bpr_ptr = ptr; - ret = nilfs_bmap_prepare_update_v(&direct->d_bmap, &oldreq, - &newreq); + ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq, + &newreq); if (ret < 0) return ret; - nilfs_bmap_commit_update_v(&direct->d_bmap, &oldreq, &newreq); + nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq); set_buffer_nilfs_volatile(bh); nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); } else @@ -339,10 +309,12 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, struct buffer_head *bh) { - struct nilfs_direct *direct = (struct nilfs_direct *)bmap; + struct nilfs_direct *direct; - return NILFS_BMAP_USE_VBN(bmap) ? - nilfs_direct_propagate_v(direct, bh) : 0; + direct = (struct nilfs_direct *)bmap; + return (direct->d_ops->dop_propagate != NULL) ? + direct->d_ops->dop_propagate(direct, bh) : + 0; } static int nilfs_direct_assign_v(struct nilfs_direct *direct, @@ -355,9 +327,12 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct, int ret; req.bpr_ptr = ptr; - ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr); - if (unlikely(ret < 0)) + ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( + &direct->d_bmap, &req); + if (ret < 0) return ret; + direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap, + &req, blocknr); binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); @@ -402,14 +377,12 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, return -EINVAL; } - return NILFS_BMAP_USE_VBN(bmap) ? - nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) : - nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo); + return direct->d_ops->dop_assign(direct, key, ptr, bh, + blocknr, binfo); } static const struct nilfs_bmap_operations nilfs_direct_ops = { .bop_lookup = nilfs_direct_lookup, - .bop_lookup_contig = nilfs_direct_lookup_contig, .bop_insert = nilfs_direct_insert, .bop_delete = nilfs_direct_delete, .bop_clear = NULL, @@ -428,8 +401,36 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { }; -int nilfs_direct_init(struct nilfs_bmap *bmap) +static const struct nilfs_direct_operations nilfs_direct_ops_v = { + .dop_find_target = nilfs_direct_find_target_v, + .dop_set_target = nilfs_direct_set_target_v, + .dop_propagate = nilfs_direct_propagate_v, + .dop_assign = nilfs_direct_assign_v, +}; + +static const struct nilfs_direct_operations nilfs_direct_ops_p = { + .dop_find_target = NULL, + .dop_set_target = NULL, + .dop_propagate = NULL, + .dop_assign = nilfs_direct_assign_p, +}; + +int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) { + struct nilfs_direct *direct; + + direct = (struct nilfs_direct *)bmap; bmap->b_ops = &nilfs_direct_ops; + bmap->b_low = low; + bmap->b_high = high; + switch (bmap->b_inode->i_ino) { + case NILFS_DAT_INO: + direct->d_ops = &nilfs_direct_ops_p; + break; + default: + direct->d_ops = &nilfs_direct_ops_v; + break; + } + return 0; } diff --git a/trunk/fs/nilfs2/direct.h b/trunk/fs/nilfs2/direct.h index a5ffd66e25d0..45d2c5cda812 100644 --- a/trunk/fs/nilfs2/direct.h +++ b/trunk/fs/nilfs2/direct.h @@ -30,6 +30,18 @@ struct nilfs_direct; +/** + * struct nilfs_direct_operations - direct mapping operation table + */ +struct nilfs_direct_operations { + __u64 (*dop_find_target)(const struct nilfs_direct *, __u64); + void (*dop_set_target)(struct nilfs_direct *, __u64, __u64); + int (*dop_propagate)(struct nilfs_direct *, struct buffer_head *); + int (*dop_assign)(struct nilfs_direct *, __u64, __u64, + struct buffer_head **, sector_t, + union nilfs_binfo *); +}; + /** * struct nilfs_direct_node - direct node * @dn_flags: flags @@ -43,9 +55,13 @@ struct nilfs_direct_node { /** * struct nilfs_direct - direct mapping * @d_bmap: bmap structure + * @d_ops: direct mapping operation table */ struct nilfs_direct { struct nilfs_bmap d_bmap; + + /* direct-mapping-specific members */ + const struct nilfs_direct_operations *d_ops; }; @@ -54,9 +70,9 @@ struct nilfs_direct { #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) -int nilfs_direct_init(struct nilfs_bmap *); +int nilfs_direct_init(struct nilfs_bmap *, __u64, __u64); int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *, - __u64 *, int); + __u64 *, int, __u64, __u64); #endif /* _NILFS_DIRECT_H */ diff --git a/trunk/fs/nilfs2/gcinode.c b/trunk/fs/nilfs2/gcinode.c index 1b3c2bb20da9..19d2102b6a69 100644 --- a/trunk/fs/nilfs2/gcinode.c +++ b/trunk/fs/nilfs2/gcinode.c @@ -52,9 +52,8 @@ #include "dat.h" #include "ifile.h" -static struct address_space_operations def_gcinode_aops = { - .sync_page = block_sync_page, -}; +static struct address_space_operations def_gcinode_aops = {}; +/* XXX need def_gcinode_iops/fops? */ /* * nilfs_gccache_submit_read_data() - add data buffer and submit read request diff --git a/trunk/fs/nilfs2/inode.c b/trunk/fs/nilfs2/inode.c index 2696d6b513b7..49ab4a49bb4f 100644 --- a/trunk/fs/nilfs2/inode.c +++ b/trunk/fs/nilfs2/inode.c @@ -43,23 +43,22 @@ * * This function does not issue actual read request of the specified data * block. It is done by VFS. + * Bulk read for direct-io is not supported yet. (should be supported) */ int nilfs_get_block(struct inode *inode, sector_t blkoff, struct buffer_head *bh_result, int create) { struct nilfs_inode_info *ii = NILFS_I(inode); - __u64 blknum = 0; + unsigned long blknum = 0; int err = 0, ret; struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); - unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; - down_read(&NILFS_MDT(dat)->mi_sem); - ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); - up_read(&NILFS_MDT(dat)->mi_sem); - if (ret >= 0) { /* found */ + /* This exclusion control is a workaround; should be revised */ + down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ + ret = nilfs_bmap_lookup(ii->i_bmap, (unsigned long)blkoff, &blknum); + up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ + if (ret == 0) { /* found */ map_bh(bh_result, inode->i_sb, blknum); - if (ret > 0) - bh_result->b_size = (ret << inode->i_blkbits); goto out; } /* data block was not found */ @@ -241,7 +240,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, struct address_space_operations nilfs_aops = { .writepage = nilfs_writepage, .readpage = nilfs_readpage, - .sync_page = block_sync_page, + /* .sync_page = nilfs_sync_page, */ .writepages = nilfs_writepages, .set_page_dirty = nilfs_set_page_dirty, .readpages = nilfs_readpages, @@ -250,7 +249,6 @@ struct address_space_operations nilfs_aops = { /* .releasepage = nilfs_releasepage, */ .invalidatepage = block_invalidatepage, .direct_IO = nilfs_direct_IO, - .is_partially_uptodate = block_is_partially_uptodate, }; struct inode *nilfs_new_inode(struct inode *dir, int mode) diff --git a/trunk/fs/nilfs2/ioctl.c b/trunk/fs/nilfs2/ioctl.c index 6ea5f872e2de..d6759b92006f 100644 --- a/trunk/fs/nilfs2/ioctl.c +++ b/trunk/fs/nilfs2/ioctl.c @@ -152,7 +152,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, down_read(&nilfs->ns_segctor_sem); ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, - size, nmembs); + nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -182,8 +182,7 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, int ret; down_read(&nilfs->ns_segctor_sem); - ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, - nmembs); + ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -213,7 +212,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, int ret; down_read(&nilfs->ns_segctor_sem); - ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs); + ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); up_read(&nilfs->ns_segctor_sem); return ret; } @@ -436,6 +435,24 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, return nmembs; } +static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, + struct nilfs_argv *argv, void *buf) +{ + size_t nmembs = argv->v_nmembs; + struct nilfs_sb_info *sbi = nilfs->ns_writer; + int ret; + + if (unlikely(!sbi)) { + /* never happens because called for a writable mount */ + WARN_ON(1); + return -EROFS; + } + ret = nilfs_segctor_add_segments_to_be_freed( + NILFS_SC(sbi), buf, nmembs); + + return (ret < 0) ? ret : nmembs; +} + int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, struct nilfs_argv *argv, void **kbufs) { @@ -474,6 +491,14 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, msg = "cannot mark copying blocks dirty"; goto failed; } + ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]); + if (ret < 0) { + /* + * can safely abort because this operation is atomic. + */ + msg = "cannot set segments to be freed"; + goto failed; + } return 0; failed: @@ -590,7 +615,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, if (copy_from_user(&argv, argp, sizeof(argv))) return -EFAULT; - if (argv.v_size < membsz) + if (argv.v_size != membsz) return -EINVAL; ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); diff --git a/trunk/fs/nilfs2/mdt.c b/trunk/fs/nilfs2/mdt.c index 3d3ddb3f5177..bb78745a0e30 100644 --- a/trunk/fs/nilfs2/mdt.c +++ b/trunk/fs/nilfs2/mdt.c @@ -430,7 +430,6 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) static struct address_space_operations def_mdt_aops = { .writepage = nilfs_mdt_write_page, - .sync_page = block_sync_page, }; static struct inode_operations def_mdt_iops; @@ -450,7 +449,7 @@ struct inode * nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, ino_t ino, gfp_t gfp_mask) { - struct inode *inode = nilfs_alloc_inode_common(nilfs); + struct inode *inode = nilfs_alloc_inode(sb); if (!inode) return NULL; diff --git a/trunk/fs/nilfs2/nilfs.h b/trunk/fs/nilfs2/nilfs.h index edf6a59d9f2a..da6fc0bba2e5 100644 --- a/trunk/fs/nilfs2/nilfs.h +++ b/trunk/fs/nilfs2/nilfs.h @@ -263,7 +263,6 @@ extern void nilfs_dirty_inode(struct inode *); extern struct dentry *nilfs_get_parent(struct dentry *); /* super.c */ -extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); extern struct inode *nilfs_alloc_inode(struct super_block *); extern void nilfs_destroy_inode(struct inode *); extern void nilfs_error(struct super_block *, const char *, const char *, ...) diff --git a/trunk/fs/nilfs2/recovery.c b/trunk/fs/nilfs2/recovery.c index d80cc71be749..57afa9d24061 100644 --- a/trunk/fs/nilfs2/recovery.c +++ b/trunk/fs/nilfs2/recovery.c @@ -28,6 +28,7 @@ #include "segment.h" #include "sufile.h" #include "page.h" +#include "seglist.h" #include "segbuf.h" /* @@ -394,24 +395,6 @@ static void dispose_recovery_list(struct list_head *head) } } -struct nilfs_segment_entry { - struct list_head list; - __u64 segnum; -}; - -static int nilfs_segment_list_add(struct list_head *head, __u64 segnum) -{ - struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); - - if (unlikely(!ent)) - return -ENOMEM; - - ent->segnum = segnum; - INIT_LIST_HEAD(&ent->list); - list_add_tail(&ent->list, head); - return 0; -} - void nilfs_dispose_segment_list(struct list_head *head) { while (!list_empty(head)) { @@ -419,7 +402,7 @@ void nilfs_dispose_segment_list(struct list_head *head) = list_entry(head->next, struct nilfs_segment_entry, list); list_del(&ent->list); - kfree(ent); + nilfs_free_segment_entry(ent); } } @@ -448,10 +431,12 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, if (unlikely(err)) goto failed; + err = -ENOMEM; for (i = 1; i < 4; i++) { - err = nilfs_segment_list_add(head, segnum[i]); - if (unlikely(err)) + ent = nilfs_alloc_segment_entry(segnum[i]); + if (unlikely(!ent)) goto failed; + list_add_tail(&ent->list, head); } /* @@ -465,7 +450,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, goto failed; } list_del(&ent->list); - kfree(ent); + nilfs_free_segment_entry(ent); } /* Allocate new segments for recovery */ @@ -806,6 +791,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, u64 seg_seq; __u64 segnum, nextnum = 0; __u64 cno; + struct nilfs_segment_entry *ent; LIST_HEAD(segments); int empty_seg = 0, scan_newer = 0; int ret; @@ -906,9 +892,12 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, if (empty_seg++) goto super_root_found; /* found a valid super root */ - ret = nilfs_segment_list_add(&segments, segnum); - if (unlikely(ret)) + ent = nilfs_alloc_segment_entry(segnum); + if (unlikely(!ent)) { + ret = -ENOMEM; goto failed; + } + list_add_tail(&ent->list, &segments); seg_seq++; segnum = nextnum; diff --git a/trunk/fs/nilfs2/segbuf.c b/trunk/fs/nilfs2/segbuf.c index 9e3fe17bb96b..1e68821b4a9b 100644 --- a/trunk/fs/nilfs2/segbuf.c +++ b/trunk/fs/nilfs2/segbuf.c @@ -26,6 +26,7 @@ #include #include "page.h" #include "segbuf.h" +#include "seglist.h" static struct kmem_cache *nilfs_segbuf_cachep; @@ -393,7 +394,7 @@ int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, * Last BIO is always sent through the following * submission. */ - rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); + rw |= (1 << BIO_RW_SYNCIO); res = nilfs_submit_seg_bio(wi, rw); if (unlikely(res)) goto failed_bio; diff --git a/trunk/fs/nilfs2/seglist.h b/trunk/fs/nilfs2/seglist.h new file mode 100644 index 000000000000..d39df9144e99 --- /dev/null +++ b/trunk/fs/nilfs2/seglist.h @@ -0,0 +1,85 @@ +/* + * seglist.h - expediential structure and routines to handle list of segments + * (would be removed in a future release) + * + * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Written by Ryusuke Konishi + * + */ +#ifndef _NILFS_SEGLIST_H +#define _NILFS_SEGLIST_H + +#include +#include +#include +#include "sufile.h" + +struct nilfs_segment_entry { + __u64 segnum; + +#define NILFS_SLH_FREED 0x0001 /* The segment was freed provisonally. + It must be cancelled if + construction aborted */ + + unsigned flags; + struct list_head list; + struct buffer_head *bh_su; + struct nilfs_segment_usage *raw_su; +}; + + +void nilfs_dispose_segment_list(struct list_head *); + +static inline struct nilfs_segment_entry * +nilfs_alloc_segment_entry(__u64 segnum) +{ + struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); + + if (likely(ent)) { + ent->segnum = segnum; + ent->flags = 0; + ent->bh_su = NULL; + ent->raw_su = NULL; + INIT_LIST_HEAD(&ent->list); + } + return ent; +} + +static inline int nilfs_open_segment_entry(struct nilfs_segment_entry *ent, + struct inode *sufile) +{ + return nilfs_sufile_get_segment_usage(sufile, ent->segnum, + &ent->raw_su, &ent->bh_su); +} + +static inline void nilfs_close_segment_entry(struct nilfs_segment_entry *ent, + struct inode *sufile) +{ + if (!ent->bh_su) + return; + nilfs_sufile_put_segment_usage(sufile, ent->segnum, ent->bh_su); + ent->bh_su = NULL; + ent->raw_su = NULL; +} + +static inline void nilfs_free_segment_entry(struct nilfs_segment_entry *ent) +{ + kfree(ent); +} + +#endif /* _NILFS_SEGLIST_H */ diff --git a/trunk/fs/nilfs2/segment.c b/trunk/fs/nilfs2/segment.c index aa977549919e..22c7f65c2403 100644 --- a/trunk/fs/nilfs2/segment.c +++ b/trunk/fs/nilfs2/segment.c @@ -39,6 +39,7 @@ #include "sufile.h" #include "cpfile.h" #include "ifile.h" +#include "seglist.h" #include "segbuf.h" @@ -78,8 +79,7 @@ enum { /* State flags of collection */ #define NILFS_CF_NODE 0x0001 /* Collecting node blocks */ #define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */ -#define NILFS_CF_SUFREED 0x0004 /* segment usages has been freed */ -#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED | NILFS_CF_SUFREED) +#define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED) /* Operations depending on the construction mode and file type */ struct nilfs_sc_operations { @@ -810,7 +810,7 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci) { return list_empty(&sci->sc_dirty_files) && !test_bit(NILFS_SC_DIRTY, &sci->sc_flags) && - sci->sc_nfreesegs == 0 && + list_empty(&sci->sc_cleaning_segments) && (!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes)); } @@ -1005,6 +1005,44 @@ static void nilfs_drop_collected_inodes(struct list_head *head) } } +static void nilfs_segctor_cancel_free_segments(struct nilfs_sc_info *sci, + struct inode *sufile) + +{ + struct list_head *head = &sci->sc_cleaning_segments; + struct nilfs_segment_entry *ent; + int err; + + list_for_each_entry(ent, head, list) { + if (!(ent->flags & NILFS_SLH_FREED)) + break; + err = nilfs_sufile_cancel_free(sufile, ent->segnum); + WARN_ON(err); /* do not happen */ + ent->flags &= ~NILFS_SLH_FREED; + } +} + +static int nilfs_segctor_prepare_free_segments(struct nilfs_sc_info *sci, + struct inode *sufile) +{ + struct list_head *head = &sci->sc_cleaning_segments; + struct nilfs_segment_entry *ent; + int err; + + list_for_each_entry(ent, head, list) { + err = nilfs_sufile_free(sufile, ent->segnum); + if (unlikely(err)) + return err; + ent->flags |= NILFS_SLH_FREED; + } + return 0; +} + +static void nilfs_segctor_commit_free_segments(struct nilfs_sc_info *sci) +{ + nilfs_dispose_segment_list(&sci->sc_cleaning_segments); +} + static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci, struct inode *inode, struct list_head *listp, @@ -1123,7 +1161,6 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) struct the_nilfs *nilfs = sbi->s_nilfs; struct list_head *head; struct nilfs_inode_info *ii; - size_t ndone; int err = 0; switch (sci->sc_stage.scnt) { @@ -1213,16 +1250,10 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) break; sci->sc_stage.scnt++; /* Fall through */ case NILFS_ST_SUFILE: - err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs, - sci->sc_nfreesegs, &ndone); - if (unlikely(err)) { - nilfs_sufile_cancel_freev(nilfs->ns_sufile, - sci->sc_freesegs, ndone, - NULL); + err = nilfs_segctor_prepare_free_segments(sci, + nilfs->ns_sufile); + if (unlikely(err)) break; - } - sci->sc_stage.flags |= NILFS_CF_SUFREED; - err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile, &nilfs_sc_file_ops); if (unlikely(err)) @@ -1455,15 +1486,7 @@ static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci, { if (unlikely(err)) { nilfs_segctor_free_incomplete_segments(sci, nilfs); - if (sci->sc_stage.flags & NILFS_CF_SUFREED) { - int ret; - - ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, - sci->sc_freesegs, - sci->sc_nfreesegs, - NULL); - WARN_ON(ret); /* do not happen */ - } + nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); } nilfs_segctor_clear_segment_buffers(sci); } @@ -1562,13 +1585,7 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) break; - if (sci->sc_stage.flags & NILFS_CF_SUFREED) { - err = nilfs_sufile_cancel_freev(nilfs->ns_sufile, - sci->sc_freesegs, - sci->sc_nfreesegs, - NULL); - WARN_ON(err); /* do not happen */ - } + nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); nilfs_segctor_clear_segment_buffers(sci); err = nilfs_segctor_extend_segments(sci, nilfs, nadd); @@ -2207,8 +2224,10 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) nilfs_segctor_complete_write(sci); /* Commit segments */ - if (has_sr) + if (has_sr) { + nilfs_segctor_commit_free_segments(sci); nilfs_segctor_clear_metadata_dirty(sci); + } nilfs_segctor_end_construction(sci, nilfs, 0); @@ -2282,6 +2301,48 @@ void nilfs_flush_segment(struct super_block *sb, ino_t ino) /* assign bit 0 to data files */ } +int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci, + __u64 *segnum, size_t nsegs) +{ + struct nilfs_segment_entry *ent; + struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs; + struct inode *sufile = nilfs->ns_sufile; + LIST_HEAD(list); + __u64 *pnum; + size_t i; + int err; + + for (pnum = segnum, i = 0; i < nsegs; pnum++, i++) { + ent = nilfs_alloc_segment_entry(*pnum); + if (unlikely(!ent)) { + err = -ENOMEM; + goto failed; + } + list_add_tail(&ent->list, &list); + + err = nilfs_open_segment_entry(ent, sufile); + if (unlikely(err)) + goto failed; + + if (unlikely(!nilfs_segment_usage_dirty(ent->raw_su))) + printk(KERN_WARNING "NILFS: unused segment is " + "requested to be cleaned (segnum=%llu)\n", + (unsigned long long)ent->segnum); + nilfs_close_segment_entry(ent, sufile); + } + list_splice(&list, sci->sc_cleaning_segments.prev); + return 0; + + failed: + nilfs_dispose_segment_list(&list); + return err; +} + +void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *sci) +{ + nilfs_dispose_segment_list(&sci->sc_cleaning_segments); +} + struct nilfs_segctor_wait_request { wait_queue_t wq; __u32 seq; @@ -2546,13 +2607,10 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, err = nilfs_init_gcdat_inode(nilfs); if (unlikely(err)) goto out_unlock; - err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); if (unlikely(err)) goto out_unlock; - sci->sc_freesegs = kbufs[4]; - sci->sc_nfreesegs = argv[4].v_nmembs; list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev); for (;;) { @@ -2571,8 +2629,6 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, } out_unlock: - sci->sc_freesegs = NULL; - sci->sc_nfreesegs = 0; nilfs_clear_gcdat_inode(nilfs); nilfs_transaction_unlock(sbi); return err; @@ -2779,6 +2835,7 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) INIT_LIST_HEAD(&sci->sc_dirty_files); INIT_LIST_HEAD(&sci->sc_segbufs); INIT_LIST_HEAD(&sci->sc_gc_inodes); + INIT_LIST_HEAD(&sci->sc_cleaning_segments); INIT_LIST_HEAD(&sci->sc_copied_buffers); sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; @@ -2844,6 +2901,9 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1); } + if (!list_empty(&sci->sc_cleaning_segments)) + nilfs_dispose_segment_list(&sci->sc_cleaning_segments); + WARN_ON(!list_empty(&sci->sc_segbufs)); down_write(&sbi->s_nilfs->ns_segctor_sem); diff --git a/trunk/fs/nilfs2/segment.h b/trunk/fs/nilfs2/segment.h index 0d2a475a741b..476bdd5df5be 100644 --- a/trunk/fs/nilfs2/segment.h +++ b/trunk/fs/nilfs2/segment.h @@ -90,9 +90,8 @@ struct nilfs_segsum_pointer { * @sc_nblk_inc: Block count of current generation * @sc_dirty_files: List of files to be written * @sc_gc_inodes: List of GC inodes having blocks to be written + * @sc_cleaning_segments: List of segments to be freed through construction * @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data - * @sc_freesegs: array of segment numbers to be freed - * @sc_nfreesegs: number of segments on @sc_freesegs * @sc_dsync_inode: inode whose data pages are written for a sync operation * @sc_dsync_start: start byte offset of data pages * @sc_dsync_end: end byte offset of data pages (inclusive) @@ -132,11 +131,9 @@ struct nilfs_sc_info { struct list_head sc_dirty_files; struct list_head sc_gc_inodes; + struct list_head sc_cleaning_segments; struct list_head sc_copied_buffers; - __u64 *sc_freesegs; - size_t sc_nfreesegs; - struct nilfs_inode_info *sc_dsync_inode; loff_t sc_dsync_start; loff_t sc_dsync_end; @@ -228,6 +225,10 @@ extern void nilfs_flush_segment(struct super_block *, ino_t); extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, void **); +extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *, + __u64 *, size_t); +extern void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *); + extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); @@ -239,6 +240,5 @@ extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *, extern int nilfs_recover_logical_segments(struct the_nilfs *, struct nilfs_sb_info *, struct nilfs_recovery_info *); -extern void nilfs_dispose_segment_list(struct list_head *); #endif /* _NILFS_SEGMENT_H */ diff --git a/trunk/fs/nilfs2/sufile.c b/trunk/fs/nilfs2/sufile.c index 37994d4a59cc..98e68677f045 100644 --- a/trunk/fs/nilfs2/sufile.c +++ b/trunk/fs/nilfs2/sufile.c @@ -18,7 +18,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Written by Koji Sato . - * Rivised by Ryusuke Konishi . */ #include @@ -109,102 +108,6 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, nilfs_mdt_mark_buffer_dirty(header_bh); } -/** - * nilfs_sufile_updatev - modify multiple segment usages at a time - * @sufile: inode of segment usage file - * @segnumv: array of segment numbers - * @nsegs: size of @segnumv array - * @create: creation flag - * @ndone: place to store number of modified segments on @segnumv - * @dofunc: primitive operation for the update - * - * Description: nilfs_sufile_updatev() repeatedly calls @dofunc - * against the given array of segments. The @dofunc is called with - * buffers of a header block and the sufile block in which the target - * segment usage entry is contained. If @ndone is given, the number - * of successfully modified segments from the head is stored in the - * place @ndone points to. - * - * Return Value: On success, zero is returned. On error, one of the - * following negative error codes is returned. - * - * %-EIO - I/O error. - * - * %-ENOMEM - Insufficient amount of memory available. - * - * %-ENOENT - Given segment usage is in hole block (may be returned if - * @create is zero) - * - * %-EINVAL - Invalid segment usage number - */ -int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs, - int create, size_t *ndone, - void (*dofunc)(struct inode *, __u64, - struct buffer_head *, - struct buffer_head *)) -{ - struct buffer_head *header_bh, *bh; - unsigned long blkoff, prev_blkoff; - __u64 *seg; - size_t nerr = 0, n = 0; - int ret = 0; - - if (unlikely(nsegs == 0)) - goto out; - - down_write(&NILFS_MDT(sufile)->mi_sem); - for (seg = segnumv; seg < segnumv + nsegs; seg++) { - if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) { - printk(KERN_WARNING - "%s: invalid segment number: %llu\n", __func__, - (unsigned long long)*seg); - nerr++; - } - } - if (nerr > 0) { - ret = -EINVAL; - goto out_sem; - } - - ret = nilfs_sufile_get_header_block(sufile, &header_bh); - if (ret < 0) - goto out_sem; - - seg = segnumv; - blkoff = nilfs_sufile_get_blkoff(sufile, *seg); - ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); - if (ret < 0) - goto out_header; - - for (;;) { - dofunc(sufile, *seg, header_bh, bh); - - if (++seg >= segnumv + nsegs) - break; - prev_blkoff = blkoff; - blkoff = nilfs_sufile_get_blkoff(sufile, *seg); - if (blkoff == prev_blkoff) - continue; - - /* get different block */ - brelse(bh); - ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); - if (unlikely(ret < 0)) - goto out_header; - } - brelse(bh); - - out_header: - n = seg - segnumv; - brelse(header_bh); - out_sem: - up_write(&NILFS_MDT(sufile)->mi_sem); - out: - if (ndone) - *ndone = n; - return ret; -} - int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, void (*dofunc)(struct inode *, __u64, struct buffer_head *, @@ -587,8 +490,7 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, * nilfs_sufile_get_suinfo - * @sufile: inode of segment usage file * @segnum: segment number to start looking - * @buf: array of suinfo - * @sisz: byte size of suinfo + * @si: array of suinfo * @nsi: size of suinfo array * * Description: @@ -600,12 +502,11 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, * * %-ENOMEM - Insufficient amount of memory available. */ -ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, - unsigned sisz, size_t nsi) +ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, + struct nilfs_suinfo *si, size_t nsi) { struct buffer_head *su_bh; struct nilfs_segment_usage *su; - struct nilfs_suinfo *si = buf; size_t susz = NILFS_MDT(sufile)->mi_entry_size; struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; void *kaddr; @@ -630,22 +531,20 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, if (ret != -ENOENT) goto out; /* hole */ - memset(si, 0, sisz * n); - si = (void *)si + sisz * n; + memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n); continue; } kaddr = kmap_atomic(su_bh->b_page, KM_USER0); su = nilfs_sufile_block_get_segment_usage( sufile, segnum, su_bh, kaddr); - for (j = 0; j < n; - j++, su = (void *)su + susz, si = (void *)si + sisz) { - si->sui_lastmod = le64_to_cpu(su->su_lastmod); - si->sui_nblocks = le32_to_cpu(su->su_nblocks); - si->sui_flags = le32_to_cpu(su->su_flags) & + for (j = 0; j < n; j++, su = (void *)su + susz) { + si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod); + si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks); + si[i + j].sui_flags = le32_to_cpu(su->su_flags) & ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); if (nilfs_segment_is_active(nilfs, segnum + j)) - si->sui_flags |= + si[i + j].sui_flags |= (1UL << NILFS_SEGMENT_USAGE_ACTIVE); } kunmap_atomic(kaddr, KM_USER0); diff --git a/trunk/fs/nilfs2/sufile.h b/trunk/fs/nilfs2/sufile.h index a2c4d76c3366..a2e2efd4ade1 100644 --- a/trunk/fs/nilfs2/sufile.h +++ b/trunk/fs/nilfs2/sufile.h @@ -43,26 +43,42 @@ void nilfs_sufile_put_segment_usage(struct inode *, __u64, struct buffer_head *); int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *); int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); -ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned, +ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *, size_t); -int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *, - void (*dofunc)(struct inode *, __u64, - struct buffer_head *, - struct buffer_head *)); int nilfs_sufile_update(struct inode *, __u64, int, void (*dofunc)(struct inode *, __u64, struct buffer_head *, struct buffer_head *)); +void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, + struct buffer_head *); void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *, struct buffer_head *); void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, struct buffer_head *); -void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, - struct buffer_head *); void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, struct buffer_head *); +/** + * nilfs_sufile_cancel_free - + * @sufile: inode of segment usage file + * @segnum: segment number + * + * Description: + * + * Return Value: On success, 0 is returned. On error, one of the following + * negative error codes is returned. + * + * %-EIO - I/O error. + * + * %-ENOMEM - Insufficient amount of memory available. + */ +static inline int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum) +{ + return nilfs_sufile_update(sufile, segnum, 0, + nilfs_sufile_do_cancel_free); +} + /** * nilfs_sufile_scrap - make a segment garbage * @sufile: inode of segment usage file @@ -83,38 +99,6 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum) return nilfs_sufile_update(sufile, segnum, 0, nilfs_sufile_do_free); } -/** - * nilfs_sufile_freev - free segments - * @sufile: inode of segment usage file - * @segnumv: array of segment numbers - * @nsegs: size of @segnumv array - * @ndone: place to store the number of freed segments - */ -static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv, - size_t nsegs, size_t *ndone) -{ - return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, - nilfs_sufile_do_free); -} - -/** - * nilfs_sufile_cancel_freev - reallocate freeing segments - * @sufile: inode of segment usage file - * @segnumv: array of segment numbers - * @nsegs: size of @segnumv array - * @ndone: place to store the number of cancelled segments - * - * Return Value: On success, 0 is returned. On error, a negative error codes - * is returned. - */ -static inline int nilfs_sufile_cancel_freev(struct inode *sufile, - __u64 *segnumv, size_t nsegs, - size_t *ndone) -{ - return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, - nilfs_sufile_do_cancel_free); -} - /** * nilfs_sufile_set_error - mark a segment as erroneous * @sufile: inode of segment usage file diff --git a/trunk/fs/nilfs2/super.c b/trunk/fs/nilfs2/super.c index ab785f85aa50..1777a3467bd2 100644 --- a/trunk/fs/nilfs2/super.c +++ b/trunk/fs/nilfs2/super.c @@ -133,7 +133,7 @@ void nilfs_warning(struct super_block *sb, const char *function, static struct kmem_cache *nilfs_inode_cachep; -struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) +struct inode *nilfs_alloc_inode(struct super_block *sb) { struct nilfs_inode_info *ii; @@ -143,15 +143,10 @@ struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) ii->i_bh = NULL; ii->i_state = 0; ii->vfs_inode.i_version = 1; - nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); + nilfs_btnode_cache_init(&ii->i_btnode_cache); return &ii->vfs_inode; } -struct inode *nilfs_alloc_inode(struct super_block *sb) -{ - return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs); -} - void nilfs_destroy_inode(struct inode *inode) { kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); diff --git a/trunk/fs/nilfs2/the_nilfs.c b/trunk/fs/nilfs2/the_nilfs.c index 8b8889825716..e4e5c78bcc93 100644 --- a/trunk/fs/nilfs2/the_nilfs.c +++ b/trunk/fs/nilfs2/the_nilfs.c @@ -32,6 +32,7 @@ #include "cpfile.h" #include "sufile.h" #include "dat.h" +#include "seglist.h" #include "segbuf.h" diff --git a/trunk/fs/ramfs/inode.c b/trunk/fs/ramfs/inode.c index 0ff7566c767c..3a6b193d8444 100644 --- a/trunk/fs/ramfs/inode.c +++ b/trunk/fs/ramfs/inode.c @@ -202,12 +202,9 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) return -EINVAL; opts->mode = option & S_IALLUGO; break; - /* - * We might like to report bad mount options here; - * but traditionally ramfs has ignored all mount options, - * and as it is used as a !CONFIG_SHMEM simple substitute - * for tmpfs, better continue to ignore other mount options. - */ + default: + printk(KERN_ERR "ramfs: bad mount option: %s\n", p); + return -EINVAL; } } diff --git a/trunk/include/linux/regulator/max1586.h b/trunk/include/linux/regulator/max1586.h new file mode 100644 index 000000000000..2056973396b6 --- /dev/null +++ b/trunk/include/linux/regulator/max1586.h @@ -0,0 +1,52 @@ +/* + * max1586.h -- Voltage regulation for the Maxim 1586 + * + * Copyright (C) 2008 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef REGULATOR_MAX1586 +#define REGULATOR_MAX1586 + +#include + +#define MAX1586_V3 0 +#define MAX1586_V6 1 + +/** + * max1586_subdev_data - regulator data + * @id: regulator Id (either MAX1586_V3 or MAX1586_V6) + * @name: regulator cute name (example for V3: "vcc_core") + * @platform_data: regulator init data (contraints, supplies, ...) + */ +struct max1586_subdev_data { + int id; + char *name; + struct regulator_init_data *platform_data; +}; + +/** + * max1586_platform_data - platform data for max1586 + * @num_subdevs: number of regultors used (may be 1 or 2) + * @subdevs: regulator used + * At most, there will be a regulator for V3 and one for V6 voltages. + */ +struct max1586_platform_data { + int num_subdevs; + struct max1586_subdev_data *subdevs; +}; + +#endif