mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
Merge ccfff0a2bd ("Merge tag 'virtio-mem-for-5.16' of git://github.com/davidhildenbrand/linux") into android-mainline
Steps on the way to 5.16-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I4b799e0446bd05dc0bdbf470cc27264bbf242f07
This commit is contained in:
@@ -42,6 +42,9 @@ properties:
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -57,4 +60,5 @@ examples:
|
||||
reg = <0x10000000 0x1000>;
|
||||
clocks = <&hfclk>, <&rtcclk>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator.
|
||||
|
||||
Reference
|
||||
[1] Si5351A/B/C Data Sheet
|
||||
https://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
|
||||
https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf
|
||||
|
||||
The Si5351a/b/c are programmable i2c clock generators with up to 8 output
|
||||
clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
|
||||
|
||||
@@ -23,6 +23,7 @@ properties:
|
||||
- socionext,uniphier-ld11-clock
|
||||
- socionext,uniphier-ld20-clock
|
||||
- socionext,uniphier-pxs3-clock
|
||||
- socionext,uniphier-nx1-clock
|
||||
- description: Media I/O (MIO) clock, SD clock
|
||||
enum:
|
||||
- socionext,uniphier-ld4-mio-clock
|
||||
@@ -33,6 +34,7 @@ properties:
|
||||
- socionext,uniphier-ld11-mio-clock
|
||||
- socionext,uniphier-ld20-sd-clock
|
||||
- socionext,uniphier-pxs3-sd-clock
|
||||
- socionext,uniphier-nx1-sd-clock
|
||||
- description: Peripheral clock
|
||||
enum:
|
||||
- socionext,uniphier-ld4-peri-clock
|
||||
@@ -43,6 +45,10 @@ properties:
|
||||
- socionext,uniphier-ld11-peri-clock
|
||||
- socionext,uniphier-ld20-peri-clock
|
||||
- socionext,uniphier-pxs3-peri-clock
|
||||
- socionext,uniphier-nx1-peri-clock
|
||||
- description: SoC-glue clock
|
||||
enum:
|
||||
- socionext,uniphier-pro4-sg-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
@@ -809,10 +809,8 @@ noinline_for_stack bool submit_bio_checks(struct bio *bio)
|
||||
if (unlikely(!current->io_context))
|
||||
create_task_io_context(current, GFP_ATOMIC, q->node);
|
||||
|
||||
if (blk_throtl_bio(bio)) {
|
||||
blkcg_bio_issue_init(bio);
|
||||
if (blk_throtl_bio(bio))
|
||||
return false;
|
||||
}
|
||||
|
||||
blk_cgroup_bio_start(bio);
|
||||
blkcg_bio_issue_init(bio);
|
||||
|
||||
@@ -104,8 +104,8 @@ static struct kobj_type blk_ia_ranges_ktype = {
|
||||
};
|
||||
|
||||
/**
|
||||
* disk_register_ia_ranges - register with sysfs a set of independent
|
||||
* access ranges
|
||||
* disk_register_independent_access_ranges - register with sysfs a set of
|
||||
* independent access ranges
|
||||
* @disk: Target disk
|
||||
* @new_iars: New set of independent access ranges
|
||||
*
|
||||
|
||||
@@ -370,9 +370,6 @@ bool blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio,
|
||||
bool ret = false;
|
||||
enum hctx_type type;
|
||||
|
||||
if (bio_queue_enter(bio))
|
||||
return false;
|
||||
|
||||
if (e && e->type->ops.bio_merge) {
|
||||
ret = e->type->ops.bio_merge(q, bio, nr_segs);
|
||||
goto out_put;
|
||||
@@ -397,7 +394,6 @@ bool blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio,
|
||||
|
||||
spin_unlock(&ctx->lock);
|
||||
out_put:
|
||||
blk_queue_exit(q);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2495,8 +2495,9 @@ static inline unsigned short blk_plug_max_rq_count(struct blk_plug *plug)
|
||||
return BLK_MAX_REQUEST_COUNT;
|
||||
}
|
||||
|
||||
static bool blk_attempt_bio_merge(struct request_queue *q, struct bio *bio,
|
||||
unsigned int nr_segs, bool *same_queue_rq)
|
||||
static bool blk_mq_attempt_bio_merge(struct request_queue *q,
|
||||
struct bio *bio, unsigned int nr_segs,
|
||||
bool *same_queue_rq)
|
||||
{
|
||||
if (!blk_queue_nomerges(q) && bio_mergeable(bio)) {
|
||||
if (blk_attempt_plug_merge(q, bio, nr_segs, same_queue_rq))
|
||||
@@ -2520,12 +2521,8 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
|
||||
};
|
||||
struct request *rq;
|
||||
|
||||
if (unlikely(bio_queue_enter(bio)))
|
||||
if (blk_mq_attempt_bio_merge(q, bio, nsegs, same_queue_rq))
|
||||
return NULL;
|
||||
if (unlikely(!submit_bio_checks(bio)))
|
||||
goto put_exit;
|
||||
if (blk_attempt_bio_merge(q, bio, nsegs, same_queue_rq))
|
||||
goto put_exit;
|
||||
|
||||
rq_qos_throttle(q, bio);
|
||||
|
||||
@@ -2542,26 +2539,44 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q,
|
||||
rq_qos_cleanup(q, bio);
|
||||
if (bio->bi_opf & REQ_NOWAIT)
|
||||
bio_wouldblock_error(bio);
|
||||
put_exit:
|
||||
blk_queue_exit(q);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool blk_mq_can_use_cached_rq(struct request *rq,
|
||||
struct bio *bio)
|
||||
{
|
||||
if (blk_mq_get_hctx_type(bio->bi_opf) != rq->mq_hctx->type)
|
||||
return false;
|
||||
|
||||
if (op_is_flush(rq->cmd_flags) != op_is_flush(bio->bi_opf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline struct request *blk_mq_get_request(struct request_queue *q,
|
||||
struct blk_plug *plug,
|
||||
struct bio *bio,
|
||||
unsigned int nsegs,
|
||||
bool *same_queue_rq)
|
||||
{
|
||||
struct request *rq;
|
||||
bool checked = false;
|
||||
|
||||
if (plug) {
|
||||
struct request *rq;
|
||||
|
||||
rq = rq_list_peek(&plug->cached_rq);
|
||||
if (rq && rq->q == q) {
|
||||
if (unlikely(!submit_bio_checks(bio)))
|
||||
return NULL;
|
||||
if (blk_attempt_bio_merge(q, bio, nsegs, same_queue_rq))
|
||||
if (blk_mq_attempt_bio_merge(q, bio, nsegs,
|
||||
same_queue_rq))
|
||||
return NULL;
|
||||
checked = true;
|
||||
if (!blk_mq_can_use_cached_rq(rq, bio))
|
||||
goto fallback;
|
||||
rq->cmd_flags = bio->bi_opf;
|
||||
plug->cached_rq = rq_list_next(rq);
|
||||
INIT_LIST_HEAD(&rq->queuelist);
|
||||
rq_qos_throttle(q, bio);
|
||||
@@ -2569,7 +2584,15 @@ static inline struct request *blk_mq_get_request(struct request_queue *q,
|
||||
}
|
||||
}
|
||||
|
||||
return blk_mq_get_new_requests(q, plug, bio, nsegs, same_queue_rq);
|
||||
fallback:
|
||||
if (unlikely(bio_queue_enter(bio)))
|
||||
return NULL;
|
||||
if (!checked && !submit_bio_checks(bio))
|
||||
return NULL;
|
||||
rq = blk_mq_get_new_requests(q, plug, bio, nsegs, same_queue_rq);
|
||||
if (!rq)
|
||||
blk_queue_exit(q);
|
||||
return rq;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,15 +89,7 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue_type(struct request_queue *
|
||||
return q->queue_hw_ctx[q->tag_set->map[type].mq_map[cpu]];
|
||||
}
|
||||
|
||||
/*
|
||||
* blk_mq_map_queue() - map (cmd_flags,type) to hardware queue
|
||||
* @q: request queue
|
||||
* @flags: request command flags
|
||||
* @ctx: software queue cpu ctx
|
||||
*/
|
||||
static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
|
||||
unsigned int flags,
|
||||
struct blk_mq_ctx *ctx)
|
||||
static inline enum hctx_type blk_mq_get_hctx_type(unsigned int flags)
|
||||
{
|
||||
enum hctx_type type = HCTX_TYPE_DEFAULT;
|
||||
|
||||
@@ -108,8 +100,20 @@ static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
|
||||
type = HCTX_TYPE_POLL;
|
||||
else if ((flags & REQ_OP_MASK) == REQ_OP_READ)
|
||||
type = HCTX_TYPE_READ;
|
||||
|
||||
return ctx->hctxs[type];
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* blk_mq_map_queue() - map (cmd_flags,type) to hardware queue
|
||||
* @q: request queue
|
||||
* @flags: request command flags
|
||||
* @ctx: software queue cpu ctx
|
||||
*/
|
||||
static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q,
|
||||
unsigned int flags,
|
||||
struct blk_mq_ctx *ctx)
|
||||
{
|
||||
return ctx->hctxs[blk_mq_get_hctx_type(flags)];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -149,7 +153,7 @@ struct blk_mq_alloc_data {
|
||||
blk_mq_req_flags_t flags;
|
||||
unsigned int shallow_depth;
|
||||
unsigned int cmd_flags;
|
||||
unsigned int rq_flags;
|
||||
req_flags_t rq_flags;
|
||||
|
||||
/* allocate multiple requests/tags in one go */
|
||||
unsigned int nr_tags;
|
||||
|
||||
@@ -429,9 +429,10 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
op = REQ_OP_ZONE_RESET;
|
||||
|
||||
/* Invalidate the page cache, including dirty pages. */
|
||||
filemap_invalidate_lock(bdev->bd_inode->i_mapping);
|
||||
ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto fail;
|
||||
break;
|
||||
case BLKOPENZONE:
|
||||
op = REQ_OP_ZONE_OPEN;
|
||||
@@ -449,15 +450,9 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
ret = blkdev_zone_mgmt(bdev, op, zrange.sector, zrange.nr_sectors,
|
||||
GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Invalidate the page cache again for zone reset: writes can only be
|
||||
* direct for zoned devices so concurrent writes would not add any page
|
||||
* to the page cache after/during reset. The page cache may be filled
|
||||
* again due to concurrent reads though and dropping the pages for
|
||||
* these is fine.
|
||||
*/
|
||||
if (!ret && cmd == BLKRESETZONE)
|
||||
ret = blkdev_truncate_zone_range(bdev, mode, &zrange);
|
||||
fail:
|
||||
if (cmd == BLKRESETZONE)
|
||||
filemap_invalidate_unlock(bdev->bd_inode->i_mapping);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -394,8 +394,8 @@ static void disk_scan_partitions(struct gendisk *disk)
|
||||
* This function registers the partitioning information in @disk
|
||||
* with the kernel.
|
||||
*/
|
||||
int device_add_disk(struct device *parent, struct gendisk *disk,
|
||||
const struct attribute_group **groups)
|
||||
int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
|
||||
const struct attribute_group **groups)
|
||||
|
||||
{
|
||||
struct device *ddev = disk_to_dev(disk);
|
||||
@@ -544,7 +544,7 @@ out_disk_release_events:
|
||||
out_free_ext_minor:
|
||||
if (disk->major == BLOCK_EXT_MAJOR)
|
||||
blk_free_ext_minor(disk->first_minor);
|
||||
return WARN_ON_ONCE(ret); /* keep until all callers handle errors */
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(device_add_disk);
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
|
||||
uint64_t range[2];
|
||||
uint64_t start, len;
|
||||
struct request_queue *q = bdev_get_queue(bdev);
|
||||
struct inode *inode = bdev->bd_inode;
|
||||
int err;
|
||||
|
||||
if (!(mode & FMODE_WRITE))
|
||||
@@ -135,12 +136,17 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
|
||||
if (start + len > bdev_nr_bytes(bdev))
|
||||
return -EINVAL;
|
||||
|
||||
filemap_invalidate_lock(inode->i_mapping);
|
||||
err = truncate_bdev_range(bdev, mode, start, start + len - 1);
|
||||
if (err)
|
||||
return err;
|
||||
goto fail;
|
||||
|
||||
return blkdev_issue_discard(bdev, start >> 9, len >> 9,
|
||||
GFP_KERNEL, flags);
|
||||
err = blkdev_issue_discard(bdev, start >> 9, len >> 9,
|
||||
GFP_KERNEL, flags);
|
||||
|
||||
fail:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
||||
@@ -148,6 +154,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
||||
{
|
||||
uint64_t range[2];
|
||||
uint64_t start, end, len;
|
||||
struct inode *inode = bdev->bd_inode;
|
||||
int err;
|
||||
|
||||
if (!(mode & FMODE_WRITE))
|
||||
@@ -170,12 +177,17 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
|
||||
return -EINVAL;
|
||||
|
||||
/* Invalidate the page cache, including dirty pages */
|
||||
filemap_invalidate_lock(inode->i_mapping);
|
||||
err = truncate_bdev_range(bdev, mode, start, end);
|
||||
if (err)
|
||||
return err;
|
||||
goto fail;
|
||||
|
||||
return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
|
||||
BLKDEV_ZERO_NOUNMAP);
|
||||
err = blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL,
|
||||
BLKDEV_ZERO_NOUNMAP);
|
||||
|
||||
fail:
|
||||
filemap_invalidate_unlock(inode->i_mapping);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int put_ushort(unsigned short __user *argp, unsigned short val)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "owl-factor.h"
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ static DEFINE_SPINLOCK(aspeed_g6_clk_lock);
|
||||
static struct clk_hw_onecell_data *aspeed_g6_clk_data;
|
||||
|
||||
static void __iomem *scu_g6_base;
|
||||
/* AST2600 revision: A0, A1, A2, etc */
|
||||
static u8 soc_rev;
|
||||
|
||||
/*
|
||||
* Clocks marked with CLK_IS_CRITICAL:
|
||||
@@ -191,9 +193,8 @@ static struct clk_hw *ast2600_calc_pll(const char *name, u32 val)
|
||||
static struct clk_hw *ast2600_calc_apll(const char *name, u32 val)
|
||||
{
|
||||
unsigned int mult, div;
|
||||
u32 chip_id = readl(scu_g6_base + ASPEED_G6_SILICON_REV);
|
||||
|
||||
if (((chip_id & CHIP_REVISION_ID) >> 16) >= 2) {
|
||||
if (soc_rev >= 2) {
|
||||
if (val & BIT(24)) {
|
||||
/* Pass through mode */
|
||||
mult = div = 1;
|
||||
@@ -707,7 +708,7 @@ static const u32 ast2600_a1_axi_ahb200_tbl[] = {
|
||||
static void __init aspeed_g6_cc(struct regmap *map)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
u32 val, div, divbits, chip_id, axi_div, ahb_div;
|
||||
u32 val, div, divbits, axi_div, ahb_div;
|
||||
|
||||
clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000);
|
||||
|
||||
@@ -738,8 +739,7 @@ static void __init aspeed_g6_cc(struct regmap *map)
|
||||
axi_div = 2;
|
||||
|
||||
divbits = (val >> 11) & 0x3;
|
||||
regmap_read(map, ASPEED_G6_SILICON_REV, &chip_id);
|
||||
if (chip_id & BIT(16)) {
|
||||
if (soc_rev >= 1) {
|
||||
if (!divbits) {
|
||||
ahb_div = ast2600_a1_axi_ahb200_tbl[(val >> 8) & 0x3];
|
||||
if (val & BIT(16))
|
||||
@@ -784,6 +784,8 @@ static void __init aspeed_g6_cc_init(struct device_node *np)
|
||||
if (!scu_g6_base)
|
||||
return;
|
||||
|
||||
soc_rev = (readl(scu_g6_base + ASPEED_G6_SILICON_REV) & CHIP_REVISION_ID) >> 16;
|
||||
|
||||
aspeed_g6_clk_data = kzalloc(struct_size(aspeed_g6_clk_data, hws,
|
||||
ASPEED_G6_NUM_CLKS), GFP_KERNEL);
|
||||
if (!aspeed_g6_clk_data)
|
||||
|
||||
@@ -97,6 +97,7 @@ static int clk_composite_determine_rate(struct clk_hw *hw,
|
||||
return ret;
|
||||
|
||||
req->rate = tmp_req.rate;
|
||||
req->best_parent_hw = tmp_req.best_parent_hw;
|
||||
req->best_parent_rate = tmp_req.best_parent_rate;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* clk-si5351.c: Silicon Laboratories Si5351A/B/C I2C Clock Generator
|
||||
* clk-si5351.c: Skyworks / Silicon Labs Si5351A/B/C I2C Clock Generator
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Rabeeh Khoury <rabeeh@solid-run.com>
|
||||
*
|
||||
* References:
|
||||
* [1] "Si5351A/B/C Data Sheet"
|
||||
* https://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
|
||||
* [2] "Manually Generating an Si5351 Register Map"
|
||||
* https://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
|
||||
* https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf
|
||||
* [2] "AN619: Manually Generating an Si5351 Register Map"
|
||||
* https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/application-notes/AN619.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* clk-si5351.h: Silicon Laboratories Si5351A/B/C I2C Clock Generator
|
||||
* clk-si5351.h: Skyworks / Silicon Labs Si5351A/B/C I2C Clock Generator
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Rabeeh Khoury <rabeeh@solid-run.com>
|
||||
|
||||
@@ -905,7 +905,7 @@ output_error:
|
||||
|
||||
static const struct of_device_id clk_vc5_of_match[];
|
||||
|
||||
static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
static int vc5_probe(struct i2c_client *client)
|
||||
{
|
||||
unsigned int oe, sd, src_mask = 0, src_val = 0;
|
||||
struct vc5_driver_data *vc5;
|
||||
@@ -1244,7 +1244,7 @@ static struct i2c_driver vc5_driver = {
|
||||
.pm = &vc5_pm_ops,
|
||||
.of_match_table = clk_vc5_of_match,
|
||||
},
|
||||
.probe = vc5_probe,
|
||||
.probe_new = vc5_probe,
|
||||
.remove = vc5_remove,
|
||||
.id_table = vc5_id,
|
||||
};
|
||||
|
||||
@@ -391,11 +391,11 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name,
|
||||
|
||||
#define imx8m_clk_hw_composite(name, parent_names, reg) \
|
||||
_imx8m_clk_hw_composite(name, parent_names, reg, \
|
||||
IMX_COMPOSITE_CORE, IMX_COMPOSITE_CLK_FLAGS_DEFAULT)
|
||||
0, IMX_COMPOSITE_CLK_FLAGS_DEFAULT)
|
||||
|
||||
#define imx8m_clk_hw_composite_critical(name, parent_names, reg) \
|
||||
_imx8m_clk_hw_composite(name, parent_names, reg, \
|
||||
IMX_COMPOSITE_CORE, IMX_COMPOSITE_CLK_FLAGS_CRITICAL)
|
||||
0, IMX_COMPOSITE_CLK_FLAGS_CRITICAL)
|
||||
|
||||
#define imx8m_clk_hw_composite_bus(name, parent_names, reg) \
|
||||
_imx8m_clk_hw_composite(name, parent_names, reg, \
|
||||
|
||||
@@ -453,15 +453,15 @@ ingenic_clk_calc_div(struct clk_hw *hw,
|
||||
}
|
||||
|
||||
/* Impose hardware constraints */
|
||||
div = min_t(unsigned, div, 1 << clk_info->div.bits);
|
||||
div = max_t(unsigned, div, 1);
|
||||
div = clamp_t(unsigned int, div, clk_info->div.div,
|
||||
clk_info->div.div << clk_info->div.bits);
|
||||
|
||||
/*
|
||||
* If the divider value itself must be divided before being written to
|
||||
* the divider register, we must ensure we don't have any bits set that
|
||||
* would be lost as a result of doing so.
|
||||
*/
|
||||
div /= clk_info->div.div;
|
||||
div = DIV_ROUND_UP(div, clk_info->div.div);
|
||||
div *= clk_info->div.div;
|
||||
|
||||
return div;
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/clock/mt8195-clk.h>
|
||||
|
||||
static const struct mtk_gate_regs imp_iic_wrap_cg_regs = {
|
||||
.set_ofs = 0xe08,
|
||||
.clr_ofs = 0xe04,
|
||||
|
||||
@@ -2937,20 +2937,6 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
|
||||
.halt_reg = 0x82014,
|
||||
.clkr = {
|
||||
.enable_reg = 0x82014,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gcc_aggre1_pnoc_ahb_clk",
|
||||
.parent_names = (const char *[]){ "periph_noc_clk_src" },
|
||||
.num_parents = 1,
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_aggre2_ufs_axi_clk = {
|
||||
.halt_reg = 0x83014,
|
||||
.clkr = {
|
||||
@@ -3474,7 +3460,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
|
||||
[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
|
||||
[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
|
||||
[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
|
||||
[GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
|
||||
[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
|
||||
[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
|
||||
[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
|
||||
|
||||
@@ -80,14 +80,14 @@ config CLK_RK3368
|
||||
Build the driver for RK3368 Clock Driver.
|
||||
|
||||
config CLK_RK3399
|
||||
tristate "Rockchip RK3399 clock controller support"
|
||||
bool "Rockchip RK3399 clock controller support"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
Build the driver for RK3399 Clock Driver.
|
||||
|
||||
config CLK_RK3568
|
||||
tristate "Rockchip RK3568 clock controller support"
|
||||
bool "Rockchip RK3568 clock controller support"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
|
||||
@@ -1630,7 +1630,6 @@ static const struct of_device_id clk_rk3399_match_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_rk3399_match_table);
|
||||
|
||||
static int __init clk_rk3399_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -1656,7 +1655,4 @@ static struct platform_driver clk_rk3399_driver = {
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
module_platform_driver_probe(clk_rk3399_driver, clk_rk3399_probe);
|
||||
|
||||
MODULE_DESCRIPTION("Rockchip RK3399 Clock Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_platform_driver_probe(clk_rk3399_driver, clk_rk3399_probe);
|
||||
|
||||
@@ -1693,7 +1693,6 @@ static const struct of_device_id clk_rk3568_match_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_rk3568_match_table);
|
||||
|
||||
static int __init clk_rk3568_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -1719,7 +1718,4 @@ static struct platform_driver clk_rk3568_driver = {
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
module_platform_driver_probe(clk_rk3568_driver, clk_rk3568_probe);
|
||||
|
||||
MODULE_DESCRIPTION("Rockchip RK3568 Clock Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_platform_driver_probe(clk_rk3568_driver, clk_rk3568_probe);
|
||||
|
||||
@@ -132,6 +132,10 @@ static const struct of_device_id uniphier_clk_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-clock",
|
||||
.data = uniphier_pxs3_sys_clk_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-clock",
|
||||
.data = uniphier_nx1_sys_clk_data,
|
||||
},
|
||||
/* Media I/O clock, SD clock */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-mio-clock",
|
||||
@@ -165,6 +169,10 @@ static const struct of_device_id uniphier_clk_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-sd-clock",
|
||||
.data = uniphier_pro5_sd_clk_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-sd-clock",
|
||||
.data = uniphier_pro5_sd_clk_data,
|
||||
},
|
||||
/* Peripheral clock */
|
||||
{
|
||||
.compatible = "socionext,uniphier-ld4-peri-clock",
|
||||
@@ -198,6 +206,15 @@ static const struct of_device_id uniphier_clk_match[] = {
|
||||
.compatible = "socionext,uniphier-pxs3-peri-clock",
|
||||
.data = uniphier_pro4_peri_clk_data,
|
||||
},
|
||||
{
|
||||
.compatible = "socionext,uniphier-nx1-peri-clock",
|
||||
.data = uniphier_pro4_peri_clk_data,
|
||||
},
|
||||
/* SoC-glue clock */
|
||||
{
|
||||
.compatible = "socionext,uniphier-pro4-sg-clock",
|
||||
.data = uniphier_pro4_sg_clk_data,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 10), \
|
||||
UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 15)
|
||||
|
||||
#define UNIPHIER_NX1_SYS_CLK_SD \
|
||||
UNIPHIER_CLK_FACTOR("sd-200m", -1, "spll", 1, 4), \
|
||||
UNIPHIER_CLK_FACTOR("sd-133m", -1, "spll", 1, 6)
|
||||
|
||||
#define UNIPHIER_LD4_SYS_CLK_NAND(idx) \
|
||||
UNIPHIER_CLK_FACTOR("nand-50m", -1, "spll", 1, 32), \
|
||||
UNIPHIER_CLK_GATE("nand", (idx), "nand-50m", 0x2104, 2)
|
||||
@@ -288,6 +292,8 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
|
||||
UNIPHIER_CLK_GATE("sata0", 28, NULL, 0x210c, 7),
|
||||
UNIPHIER_CLK_GATE("sata1", 29, NULL, 0x210c, 8),
|
||||
UNIPHIER_CLK_GATE("sata-phy", 30, NULL, 0x210c, 21),
|
||||
UNIPHIER_LD11_SYS_CLK_AIO(40),
|
||||
UNIPHIER_LD11_SYS_CLK_EXIV(42),
|
||||
/* CPU gears */
|
||||
UNIPHIER_CLK_DIV4("cpll", 2, 3, 4, 8),
|
||||
UNIPHIER_CLK_DIV4("spll", 2, 3, 4, 8),
|
||||
@@ -300,3 +306,44 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
|
||||
"spll/4", "spll/8", "s2pll/4", "s2pll/8"),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
const struct uniphier_clk_data uniphier_nx1_sys_clk_data[] = {
|
||||
UNIPHIER_CLK_FACTOR("cpll", -1, "ref", 100, 1), /* ARM: 2500 MHz */
|
||||
UNIPHIER_CLK_FACTOR("spll", -1, "ref", 32, 1), /* 800 MHz */
|
||||
UNIPHIER_CLK_FACTOR("uart", 0, "spll", 1, 6),
|
||||
UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 16),
|
||||
UNIPHIER_NX1_SYS_CLK_SD,
|
||||
UNIPHIER_CLK_GATE("emmc", 4, NULL, 0x2108, 8),
|
||||
UNIPHIER_CLK_GATE("ether", 6, NULL, 0x210c, 0),
|
||||
UNIPHIER_CLK_GATE("usb30-0", 12, NULL, 0x210c, 16), /* =GIO */
|
||||
UNIPHIER_CLK_GATE("usb30-1", 13, NULL, 0x210c, 20), /* =GIO1P */
|
||||
UNIPHIER_CLK_GATE("usb30-hsphy0", 16, NULL, 0x210c, 24),
|
||||
UNIPHIER_CLK_GATE("usb30-ssphy0", 17, NULL, 0x210c, 25),
|
||||
UNIPHIER_CLK_GATE("usb30-ssphy1", 18, NULL, 0x210c, 26),
|
||||
UNIPHIER_CLK_GATE("pcie", 24, NULL, 0x210c, 8),
|
||||
UNIPHIER_CLK_GATE("voc", 52, NULL, 0x2110, 0),
|
||||
UNIPHIER_CLK_GATE("hdmitx", 58, NULL, 0x2110, 8),
|
||||
/* CPU gears */
|
||||
UNIPHIER_CLK_DIV5("cpll", 2, 4, 8, 16, 32),
|
||||
UNIPHIER_CLK_CPUGEAR("cpu-ca53", 33, 0x8080, 0xf, 5,
|
||||
"cpll/2", "cpll/4", "cpll/8", "cpll/16",
|
||||
"cpll/32"),
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
const struct uniphier_clk_data uniphier_pro4_sg_clk_data[] = {
|
||||
UNIPHIER_CLK_DIV("gpll", 4),
|
||||
{
|
||||
.name = "sata-ref",
|
||||
.type = UNIPHIER_CLK_TYPE_MUX,
|
||||
.idx = 0,
|
||||
.data.mux = {
|
||||
.parent_names = { "gpll/4", "ref", },
|
||||
.num_parents = 2,
|
||||
.reg = 0x1a28,
|
||||
.masks = { 0x1, 0x1, },
|
||||
.vals = { 0x0, 0x1, },
|
||||
},
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@@ -119,6 +119,10 @@ struct uniphier_clk_data {
|
||||
UNIPHIER_CLK_DIV2(parent, div0, div1), \
|
||||
UNIPHIER_CLK_DIV2(parent, div2, div3)
|
||||
|
||||
#define UNIPHIER_CLK_DIV5(parent, div0, div1, div2, div3, div4) \
|
||||
UNIPHIER_CLK_DIV4(parent, div0, div1, div2, div3), \
|
||||
UNIPHIER_CLK_DIV(parent, div4)
|
||||
|
||||
struct clk_hw *uniphier_clk_register_cpugear(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
const char *name,
|
||||
@@ -146,9 +150,11 @@ extern const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_ld11_sys_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_ld20_sys_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_nx1_sys_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_ld4_mio_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_pro5_sd_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_ld4_peri_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_pro4_peri_clk_data[];
|
||||
extern const struct uniphier_clk_data uniphier_pro4_sg_clk_data[];
|
||||
|
||||
#endif /* __CLK_UNIPHIER_H__ */
|
||||
|
||||
@@ -2889,6 +2889,7 @@ static unsigned int virtio_mem_features[] = {
|
||||
#if defined(CONFIG_NUMA) && defined(CONFIG_ACPI_NUMA)
|
||||
VIRTIO_MEM_F_ACPI_PXM,
|
||||
#endif
|
||||
VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE,
|
||||
};
|
||||
|
||||
static const struct virtio_device_id virtio_mem_id_table[] = {
|
||||
|
||||
@@ -271,7 +271,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
||||
c = 0;
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
||||
if (server->is_channel)
|
||||
/* channel info will be printed as a part of sessions below */
|
||||
if (CIFS_SERVER_IS_CHAN(server))
|
||||
continue;
|
||||
|
||||
c++;
|
||||
@@ -358,6 +359,8 @@ skip_rdma:
|
||||
seq_printf(m, " signed");
|
||||
if (server->posix_ext_supported)
|
||||
seq_printf(m, " posix");
|
||||
if (server->nosharesock)
|
||||
seq_printf(m, " nosharesock");
|
||||
|
||||
if (server->rdma)
|
||||
seq_printf(m, "\nRDMA ");
|
||||
@@ -412,12 +415,14 @@ skip_rdma:
|
||||
from_kuid(&init_user_ns, ses->linux_uid),
|
||||
from_kuid(&init_user_ns, ses->cred_uid));
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (ses->chan_count > 1) {
|
||||
seq_printf(m, "\n\n\tExtra Channels: %zu ",
|
||||
ses->chan_count-1);
|
||||
for (j = 1; j < ses->chan_count; j++)
|
||||
cifs_dump_channel(m, j, &ses->chans[j]);
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
seq_puts(m, "\n\n\tShares: ");
|
||||
j = 0;
|
||||
|
||||
@@ -307,12 +307,8 @@ static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
|
||||
static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
void *page;
|
||||
char *full_path, *root_path;
|
||||
unsigned int xid;
|
||||
int rc;
|
||||
char *full_path;
|
||||
struct vfsmount *mnt;
|
||||
|
||||
cifs_dbg(FYI, "in %s\n", __func__);
|
||||
@@ -324,8 +320,6 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
* the double backslashes usually used in the UNC. This function
|
||||
* gives us the latter, so we must adjust the result.
|
||||
*/
|
||||
mnt = ERR_PTR(-ENOMEM);
|
||||
|
||||
cifs_sb = CIFS_SB(mntpt->d_sb);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
|
||||
mnt = ERR_PTR(-EREMOTE);
|
||||
@@ -341,60 +335,11 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
|
||||
}
|
||||
|
||||
convert_delimiter(full_path, '\\');
|
||||
|
||||
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
|
||||
|
||||
if (!cifs_sb_master_tlink(cifs_sb)) {
|
||||
cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__);
|
||||
goto free_full_path;
|
||||
}
|
||||
|
||||
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
if (!tcon) {
|
||||
cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__);
|
||||
goto free_full_path;
|
||||
}
|
||||
|
||||
root_path = kstrdup(tcon->treeName, GFP_KERNEL);
|
||||
if (!root_path) {
|
||||
mnt = ERR_PTR(-ENOMEM);
|
||||
goto free_full_path;
|
||||
}
|
||||
cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path);
|
||||
|
||||
ses = tcon->ses;
|
||||
xid = get_xid();
|
||||
|
||||
/*
|
||||
* If DFS root has been expired, then unconditionally fetch it again to
|
||||
* refresh DFS referral cache.
|
||||
*/
|
||||
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb),
|
||||
root_path + 1, NULL, NULL);
|
||||
if (!rc) {
|
||||
rc = dfs_cache_find(xid, ses, cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb), full_path + 1,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
free_xid(xid);
|
||||
|
||||
if (rc) {
|
||||
mnt = ERR_PTR(rc);
|
||||
goto free_root_path;
|
||||
}
|
||||
/*
|
||||
* OK - we were able to get and cache a referral for @full_path.
|
||||
*
|
||||
* Now, pass it down to cifs_mount() and it will retry every available
|
||||
* node server in case of failures - no need to do it here.
|
||||
*/
|
||||
mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
|
||||
cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__,
|
||||
full_path + 1, mnt);
|
||||
cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
|
||||
|
||||
free_root_path:
|
||||
kfree(root_path);
|
||||
free_full_path:
|
||||
free_dentry_path(page);
|
||||
cdda_exit:
|
||||
|
||||
@@ -61,11 +61,6 @@ struct cifs_sb_info {
|
||||
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
||||
char *prepath;
|
||||
|
||||
/*
|
||||
* Canonical DFS path initially provided by the mount call. We might connect to something
|
||||
* different via DFS but we want to keep it to do failover properly.
|
||||
*/
|
||||
char *origin_fullpath; /* \\HOST\SHARE\[OPTIONAL PATH] */
|
||||
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
|
||||
uuid_t dfs_mount_id;
|
||||
/*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/utsname.h>
|
||||
#include "cifs_fs_sb.h"
|
||||
#include "cifsacl.h"
|
||||
#include <crypto/internal/hash.h>
|
||||
@@ -75,7 +76,8 @@
|
||||
#define SMB_ECHO_INTERVAL_MAX 600
|
||||
#define SMB_ECHO_INTERVAL_DEFAULT 60
|
||||
|
||||
/* dns resolution interval in seconds */
|
||||
/* dns resolution intervals in seconds */
|
||||
#define SMB_DNS_RESOLVE_INTERVAL_MIN 120
|
||||
#define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
|
||||
|
||||
/* maximum number of PDUs in one compound */
|
||||
@@ -99,6 +101,8 @@
|
||||
#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
|
||||
#endif
|
||||
|
||||
#define CIFS_MAX_WORKSTATION_LEN (__NEW_UTS_LEN + 1) /* reasonable max for client */
|
||||
|
||||
/*
|
||||
* CIFS vfs client Status information (based on what we know.)
|
||||
*/
|
||||
@@ -592,6 +596,7 @@ struct TCP_Server_Info {
|
||||
struct list_head pending_mid_q;
|
||||
bool noblocksnd; /* use blocking sendmsg */
|
||||
bool noautotune; /* do not autotune send buf sizes */
|
||||
bool nosharesock;
|
||||
bool tcp_nodelay;
|
||||
unsigned int credits; /* send no more requests at once */
|
||||
unsigned int max_credits; /* can override large 32000 default at mnt */
|
||||
@@ -685,13 +690,34 @@ struct TCP_Server_Info {
|
||||
*/
|
||||
int nr_targets;
|
||||
bool noblockcnt; /* use non-blocking connect() */
|
||||
bool is_channel; /* if a session channel */
|
||||
|
||||
/*
|
||||
* If this is a session channel,
|
||||
* primary_server holds the ref-counted
|
||||
* pointer to primary channel connection for the session.
|
||||
*/
|
||||
#define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server)
|
||||
struct TCP_Server_Info *primary_server;
|
||||
|
||||
#ifdef CONFIG_CIFS_SWN_UPCALL
|
||||
bool use_swn_dstaddr;
|
||||
struct sockaddr_storage swn_dstaddr;
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
bool is_dfs_conn; /* if a dfs connection */
|
||||
struct mutex refpath_lock; /* protects leaf_fullpath */
|
||||
/*
|
||||
* Canonical DFS full paths that were used to chase referrals in mount and reconnect.
|
||||
*
|
||||
* origin_fullpath: first or original referral path
|
||||
* leaf_fullpath: last referral path (might be changed due to nested links in reconnect)
|
||||
*
|
||||
* current_fullpath: pointer to either origin_fullpath or leaf_fullpath
|
||||
* NOTE: cannot be accessed outside cifs_reconnect() and smb2_reconnect()
|
||||
*
|
||||
* format: \\HOST\SHARE\[OPTIONAL PATH]
|
||||
*/
|
||||
char *origin_fullpath, *leaf_fullpath, *current_fullpath;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -908,6 +934,7 @@ struct cifs_ses {
|
||||
and after mount option parsing we fill it */
|
||||
char *domainName;
|
||||
char *password;
|
||||
char *workstation_name;
|
||||
struct session_key auth_key;
|
||||
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
|
||||
enum securityEnum sectype; /* what security flavor was specified? */
|
||||
@@ -933,16 +960,21 @@ struct cifs_ses {
|
||||
* iface_lock should be taken when accessing any of these fields
|
||||
*/
|
||||
spinlock_t iface_lock;
|
||||
/* ========= begin: protected by iface_lock ======== */
|
||||
struct cifs_server_iface *iface_list;
|
||||
size_t iface_count;
|
||||
unsigned long iface_last_update; /* jiffies */
|
||||
/* ========= end: protected by iface_lock ======== */
|
||||
|
||||
spinlock_t chan_lock;
|
||||
/* ========= begin: protected by chan_lock ======== */
|
||||
#define CIFS_MAX_CHANNELS 16
|
||||
struct cifs_chan chans[CIFS_MAX_CHANNELS];
|
||||
struct cifs_chan *binding_chan;
|
||||
size_t chan_count;
|
||||
size_t chan_max;
|
||||
atomic_t chan_seq; /* round robin state */
|
||||
/* ========= end: protected by chan_lock ======== */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1091,7 +1123,6 @@ struct cifs_tcon {
|
||||
struct cached_fid crfid; /* Cached root fid */
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
char *dfs_path; /* canonical DFS path */
|
||||
struct list_head ulist; /* cache update list */
|
||||
#endif
|
||||
};
|
||||
@@ -1942,4 +1973,14 @@ static inline bool is_tcon_dfs(struct cifs_tcon *tcon)
|
||||
tcon->share_flags & (SHI1005_FLAGS_DFS | SHI1005_FLAGS_DFS_ROOT);
|
||||
}
|
||||
|
||||
static inline bool cifs_is_referral_server(struct cifs_tcon *tcon,
|
||||
const struct dfs_info3_param *ref)
|
||||
{
|
||||
/*
|
||||
* Check if all targets are capable of handling DFS referrals as per
|
||||
* MS-DFSC 2.2.4 RESP_GET_DFS_REFERRAL.
|
||||
*/
|
||||
return is_tcon_dfs(tcon) || (ref && (ref->flags & DFSREF_REFERRAL_SERVER));
|
||||
}
|
||||
|
||||
#endif /* _CIFS_GLOB_H */
|
||||
|
||||
@@ -269,8 +269,9 @@ extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);
|
||||
|
||||
extern void cifs_close_deferred_file_under_dentry(struct cifs_tcon *cifs_tcon,
|
||||
const char *path);
|
||||
|
||||
extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
struct TCP_Server_Info *primary_server);
|
||||
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
|
||||
int from_reconnect);
|
||||
extern void cifs_put_tcon(struct cifs_tcon *tcon);
|
||||
@@ -607,7 +608,7 @@ int smb2_parse_query_directory(struct cifs_tcon *tcon, struct kvec *rsp_iov,
|
||||
|
||||
struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server);
|
||||
void cifs_put_tcp_super(struct super_block *sb);
|
||||
int update_super_prepath(struct cifs_tcon *tcon, char *prefix);
|
||||
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
|
||||
char *extract_hostname(const char *unc);
|
||||
char *extract_sharename(const char *unc);
|
||||
|
||||
@@ -634,4 +635,7 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
|
||||
return options;
|
||||
}
|
||||
|
||||
struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
|
||||
void cifs_put_tcon_super(struct super_block *sb);
|
||||
|
||||
#endif /* _CIFSPROTO_H */
|
||||
|
||||
1524
fs/cifs/connect.c
1524
fs/cifs/connect.c
File diff suppressed because it is too large
Load Diff
@@ -283,7 +283,7 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m,
|
||||
"cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n",
|
||||
ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
|
||||
ce->ttl, ce->etime.tv_nsec, ce->ref_flags, ce->hdr_flags,
|
||||
ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags,
|
||||
IS_DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
|
||||
|
||||
@@ -1364,9 +1364,9 @@ static void mark_for_reconnect_if_needed(struct cifs_tcon *tcon, struct dfs_cach
|
||||
}
|
||||
|
||||
/* Refresh dfs referral of tcon and mark it for reconnect if needed */
|
||||
static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool force_refresh)
|
||||
static int __refresh_tcon(const char *path, struct cifs_ses **sessions, struct cifs_tcon *tcon,
|
||||
bool force_refresh)
|
||||
{
|
||||
const char *path = tcon->dfs_path + 1;
|
||||
struct cifs_ses *ses;
|
||||
struct cache_entry *ce;
|
||||
struct dfs_info3_param *refs = NULL;
|
||||
@@ -1422,6 +1422,20 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int refresh_tcon(struct cifs_ses **sessions, struct cifs_tcon *tcon, bool force_refresh)
|
||||
{
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
|
||||
mutex_lock(&server->refpath_lock);
|
||||
if (strcasecmp(server->leaf_fullpath, server->origin_fullpath))
|
||||
__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, force_refresh);
|
||||
mutex_unlock(&server->refpath_lock);
|
||||
|
||||
__refresh_tcon(server->origin_fullpath + 1, sessions, tcon, force_refresh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_cache_remount_fs - remount a DFS share
|
||||
*
|
||||
@@ -1435,6 +1449,7 @@ out:
|
||||
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
struct mount_group *mg;
|
||||
struct cifs_ses *sessions[CACHE_MAX_ENTRIES + 1] = {NULL};
|
||||
int rc;
|
||||
@@ -1443,13 +1458,15 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||
return -EINVAL;
|
||||
|
||||
tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
if (!tcon->dfs_path) {
|
||||
cifs_dbg(FYI, "%s: not a dfs tcon\n", __func__);
|
||||
server = tcon->ses->server;
|
||||
|
||||
if (!server->origin_fullpath) {
|
||||
cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uuid_is_null(&cifs_sb->dfs_mount_id)) {
|
||||
cifs_dbg(FYI, "%s: tcon has no dfs mount group id\n", __func__);
|
||||
cifs_dbg(FYI, "%s: no dfs mount group id\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1457,7 +1474,7 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||
mg = find_mount_group_locked(&cifs_sb->dfs_mount_id);
|
||||
if (IS_ERR(mg)) {
|
||||
mutex_unlock(&mount_group_list_lock);
|
||||
cifs_dbg(FYI, "%s: tcon has ipc session to refresh referral\n", __func__);
|
||||
cifs_dbg(FYI, "%s: no ipc session for refreshing referral\n", __func__);
|
||||
return PTR_ERR(mg);
|
||||
}
|
||||
kref_get(&mg->refcount);
|
||||
@@ -1498,9 +1515,12 @@ static void refresh_mounts(struct cifs_ses **sessions)
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
||||
if (!server->is_dfs_conn)
|
||||
continue;
|
||||
|
||||
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
||||
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
|
||||
if (tcon->dfs_path) {
|
||||
if (!tcon->ipc && !tcon->need_reconnect) {
|
||||
tcon->tc_count++;
|
||||
list_add_tail(&tcon->ulist, &tcons);
|
||||
}
|
||||
@@ -1510,8 +1530,16 @@ static void refresh_mounts(struct cifs_ses **sessions)
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) {
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
|
||||
list_del_init(&tcon->ulist);
|
||||
refresh_tcon(sessions, tcon, false);
|
||||
|
||||
mutex_lock(&server->refpath_lock);
|
||||
if (strcasecmp(server->leaf_fullpath, server->origin_fullpath))
|
||||
__refresh_tcon(server->leaf_fullpath + 1, sessions, tcon, false);
|
||||
mutex_unlock(&server->refpath_lock);
|
||||
|
||||
__refresh_tcon(server->origin_fullpath + 1, sessions, tcon, false);
|
||||
cifs_put_tcon(tcon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2692,12 +2692,23 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
|
||||
tcon = tlink_tcon(smbfile->tlink);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
||||
server = tcon->ses->server;
|
||||
if (server->ops->flush)
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
else
|
||||
if (server->ops->flush == NULL) {
|
||||
rc = -ENOSYS;
|
||||
goto strict_fsync_exit;
|
||||
}
|
||||
|
||||
if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
|
||||
smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
|
||||
if (smbfile) {
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
cifsFileInfo_put(smbfile);
|
||||
} else
|
||||
cifs_dbg(FYI, "ignore fsync for file not open for write\n");
|
||||
} else
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
}
|
||||
|
||||
strict_fsync_exit:
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
@@ -2709,6 +2720,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
struct cifs_tcon *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifsFileInfo *smbfile = file->private_data;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
|
||||
|
||||
rc = file_write_and_wait_range(file, start, end);
|
||||
@@ -2725,12 +2737,23 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
tcon = tlink_tcon(smbfile->tlink);
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
|
||||
server = tcon->ses->server;
|
||||
if (server->ops->flush)
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
else
|
||||
if (server->ops->flush == NULL) {
|
||||
rc = -ENOSYS;
|
||||
goto fsync_exit;
|
||||
}
|
||||
|
||||
if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) {
|
||||
smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY);
|
||||
if (smbfile) {
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
cifsFileInfo_put(smbfile);
|
||||
} else
|
||||
cifs_dbg(FYI, "ignore fsync for file not open for write\n");
|
||||
} else
|
||||
rc = server->ops->flush(xid, tcon, &smbfile->fid);
|
||||
}
|
||||
|
||||
fsync_exit:
|
||||
free_xid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -308,7 +308,9 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
|
||||
new_ctx->nodename = NULL;
|
||||
new_ctx->username = NULL;
|
||||
new_ctx->password = NULL;
|
||||
new_ctx->server_hostname = NULL;
|
||||
new_ctx->domainname = NULL;
|
||||
new_ctx->workstation_name = NULL;
|
||||
new_ctx->UNC = NULL;
|
||||
new_ctx->source = NULL;
|
||||
new_ctx->iocharset = NULL;
|
||||
@@ -323,6 +325,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
|
||||
DUP_CTX_STR(UNC);
|
||||
DUP_CTX_STR(source);
|
||||
DUP_CTX_STR(domainname);
|
||||
DUP_CTX_STR(workstation_name);
|
||||
DUP_CTX_STR(nodename);
|
||||
DUP_CTX_STR(iocharset);
|
||||
|
||||
@@ -459,6 +462,7 @@ smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx)
|
||||
return -EINVAL;
|
||||
|
||||
/* record the server hostname */
|
||||
kfree(ctx->server_hostname);
|
||||
ctx->server_hostname = kstrndup(devname + 2, pos - devname - 2, GFP_KERNEL);
|
||||
if (!ctx->server_hostname)
|
||||
return -ENOMEM;
|
||||
@@ -720,6 +724,11 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc,
|
||||
cifs_errorf(fc, "can not change domainname during remount\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_ctx->workstation_name &&
|
||||
(!old_ctx->workstation_name || strcmp(new_ctx->workstation_name, old_ctx->workstation_name))) {
|
||||
cifs_errorf(fc, "can not change workstation_name during remount\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_ctx->nodename &&
|
||||
(!old_ctx->nodename || strcmp(new_ctx->nodename, old_ctx->nodename))) {
|
||||
cifs_errorf(fc, "can not change nodename during remount\n");
|
||||
@@ -753,7 +762,8 @@ static int smb3_reconfigure(struct fs_context *fc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* We can not change UNC/username/password/domainname/nodename/iocharset
|
||||
* We can not change UNC/username/password/domainname/
|
||||
* workstation_name/nodename/iocharset
|
||||
* during reconnect so ignore what we have in the new context and
|
||||
* just use what we already have in cifs_sb->ctx.
|
||||
*/
|
||||
@@ -762,6 +772,7 @@ static int smb3_reconfigure(struct fs_context *fc)
|
||||
STEAL_STRING(cifs_sb, ctx, username);
|
||||
STEAL_STRING(cifs_sb, ctx, password);
|
||||
STEAL_STRING(cifs_sb, ctx, domainname);
|
||||
STEAL_STRING(cifs_sb, ctx, workstation_name);
|
||||
STEAL_STRING(cifs_sb, ctx, nodename);
|
||||
STEAL_STRING(cifs_sb, ctx, iocharset);
|
||||
|
||||
@@ -1414,13 +1425,22 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
|
||||
int smb3_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
int rc;
|
||||
struct smb3_fs_context *ctx;
|
||||
char *nodename = utsname()->nodename;
|
||||
int i;
|
||||
|
||||
ctx = kzalloc(sizeof(struct smb3_fs_context), GFP_KERNEL);
|
||||
if (unlikely(!ctx))
|
||||
return -ENOMEM;
|
||||
if (unlikely(!ctx)) {
|
||||
rc = -ENOMEM;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
ctx->workstation_name = kstrdup(nodename, GFP_KERNEL);
|
||||
if (unlikely(!ctx->workstation_name)) {
|
||||
rc = -ENOMEM;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* does not have to be perfect mapping since field is
|
||||
@@ -1493,6 +1513,14 @@ int smb3_init_fs_context(struct fs_context *fc)
|
||||
fc->fs_private = ctx;
|
||||
fc->ops = &smb3_fs_context_ops;
|
||||
return 0;
|
||||
|
||||
err_exit:
|
||||
if (ctx) {
|
||||
kfree(ctx->workstation_name);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1518,6 +1546,8 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
|
||||
ctx->source = NULL;
|
||||
kfree(ctx->domainname);
|
||||
ctx->domainname = NULL;
|
||||
kfree(ctx->workstation_name);
|
||||
ctx->workstation_name = NULL;
|
||||
kfree(ctx->nodename);
|
||||
ctx->nodename = NULL;
|
||||
kfree(ctx->iocharset);
|
||||
|
||||
@@ -170,6 +170,7 @@ struct smb3_fs_context {
|
||||
char *server_hostname;
|
||||
char *UNC;
|
||||
char *nodename;
|
||||
char *workstation_name;
|
||||
char *iocharset; /* local code page for mapping to and from Unicode */
|
||||
char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */
|
||||
char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */
|
||||
|
||||
@@ -87,6 +87,14 @@ void cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
|
||||
char *sharename;
|
||||
struct cifs_fscache_super_auxdata auxdata;
|
||||
|
||||
/*
|
||||
* Check if cookie was already initialized so don't reinitialize it.
|
||||
* In the future, as we integrate with newer fscache features,
|
||||
* we may want to instead add a check if cookie has changed
|
||||
*/
|
||||
if (tcon->fscache == NULL)
|
||||
return;
|
||||
|
||||
sharename = extract_sharename(tcon->treeName);
|
||||
if (IS_ERR(sharename)) {
|
||||
cifs_dbg(FYI, "%s: couldn't extract sharename\n", __func__);
|
||||
|
||||
@@ -75,6 +75,7 @@ sesInfoAlloc(void)
|
||||
INIT_LIST_HEAD(&ret_buf->tcon_list);
|
||||
mutex_init(&ret_buf->session_mutex);
|
||||
spin_lock_init(&ret_buf->iface_lock);
|
||||
spin_lock_init(&ret_buf->chan_lock);
|
||||
}
|
||||
return ret_buf;
|
||||
}
|
||||
@@ -94,6 +95,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
|
||||
kfree_sensitive(buf_to_free->password);
|
||||
kfree(buf_to_free->user_name);
|
||||
kfree(buf_to_free->domainName);
|
||||
kfree(buf_to_free->workstation_name);
|
||||
kfree_sensitive(buf_to_free->auth_key.response);
|
||||
kfree(buf_to_free->iface_list);
|
||||
kfree_sensitive(buf_to_free);
|
||||
@@ -138,9 +140,6 @@ tconInfoFree(struct cifs_tcon *buf_to_free)
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
kfree_sensitive(buf_to_free->password);
|
||||
kfree(buf_to_free->crfid.fid);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
kfree(buf_to_free->dfs_path);
|
||||
#endif
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
@@ -1287,69 +1286,20 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void tcon_super_cb(struct super_block *sb, void *arg)
|
||||
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
|
||||
{
|
||||
struct super_cb_data *sd = arg;
|
||||
struct cifs_tcon *tcon = sd->data;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
|
||||
if (sd->sb)
|
||||
return;
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
if (tcon->dfs_path && cifs_sb->origin_fullpath &&
|
||||
!strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
|
||||
sd->sb = sb;
|
||||
}
|
||||
|
||||
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
|
||||
{
|
||||
return __cifs_get_super(tcon_super_cb, tcon);
|
||||
}
|
||||
|
||||
static inline void cifs_put_tcon_super(struct super_block *sb)
|
||||
{
|
||||
__cifs_put_super(sb);
|
||||
}
|
||||
#else
|
||||
static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void cifs_put_tcon_super(struct super_block *sb)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
|
||||
{
|
||||
struct super_block *sb;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
int rc = 0;
|
||||
|
||||
sb = cifs_get_tcon_super(tcon);
|
||||
if (IS_ERR(sb))
|
||||
return PTR_ERR(sb);
|
||||
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
|
||||
kfree(cifs_sb->prepath);
|
||||
|
||||
if (prefix && *prefix) {
|
||||
cifs_sb->prepath = kstrdup(prefix, GFP_ATOMIC);
|
||||
if (!cifs_sb->prepath) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!cifs_sb->prepath)
|
||||
return -ENOMEM;
|
||||
|
||||
convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
|
||||
} else
|
||||
cifs_sb->prepath = NULL;
|
||||
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
|
||||
|
||||
out:
|
||||
cifs_put_tcon_super(sb);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -119,7 +119,9 @@ typedef struct _AUTHENTICATE_MESSAGE {
|
||||
*/
|
||||
|
||||
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
|
||||
void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
|
||||
int build_ntlmssp_negotiate_blob(unsigned char **pbuffer, u16 *buflen,
|
||||
struct cifs_ses *ses,
|
||||
const struct nls_table *nls_cp);
|
||||
int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
|
||||
struct cifs_ses *ses,
|
||||
const struct nls_table *nls_cp);
|
||||
|
||||
240
fs/cifs/sess.c
240
fs/cifs/sess.c
@@ -54,41 +54,53 @@ bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
for (i = 0; i < ses->chan_count; i++) {
|
||||
if (is_server_using_iface(ses->chans[i].server, iface))
|
||||
if (is_server_using_iface(ses->chans[i].server, iface)) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* returns number of channels added */
|
||||
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
{
|
||||
int old_chan_count = ses->chan_count;
|
||||
int left = ses->chan_max - ses->chan_count;
|
||||
int old_chan_count, new_chan_count;
|
||||
int left;
|
||||
int i = 0;
|
||||
int rc = 0;
|
||||
int tries = 0;
|
||||
struct cifs_server_iface *ifaces = NULL;
|
||||
size_t iface_count;
|
||||
|
||||
if (ses->server->dialect < SMB30_PROT_ID) {
|
||||
cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
|
||||
new_chan_count = old_chan_count = ses->chan_count;
|
||||
left = ses->chan_max - ses->chan_count;
|
||||
|
||||
if (left <= 0) {
|
||||
cifs_dbg(FYI,
|
||||
"ses already at max_channels (%zu), nothing to open\n",
|
||||
ses->chan_max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ses->server->dialect < SMB30_PROT_ID) {
|
||||
cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n");
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) {
|
||||
cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname);
|
||||
ses->chan_max = 1;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
/*
|
||||
* Make a copy of the iface list at the time and use that
|
||||
@@ -142,10 +154,11 @@ int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
cifs_dbg(FYI, "successfully opened new channel on iface#%d\n",
|
||||
i);
|
||||
left--;
|
||||
new_chan_count++;
|
||||
}
|
||||
|
||||
kfree(ifaces);
|
||||
return ses->chan_count - old_chan_count;
|
||||
return new_chan_count - old_chan_count;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -157,10 +170,14 @@ cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||
{
|
||||
int i;
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
for (i = 0; i < ses->chan_count; i++) {
|
||||
if (ses->chans[i].server == server)
|
||||
if (ses->chans[i].server == server) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return &ses->chans[i];
|
||||
}
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -168,6 +185,7 @@ static int
|
||||
cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
struct cifs_server_iface *iface)
|
||||
{
|
||||
struct TCP_Server_Info *chan_server;
|
||||
struct cifs_chan *chan;
|
||||
struct smb3_fs_context ctx = {NULL};
|
||||
static const char unc_fmt[] = "\\%s\\foo";
|
||||
@@ -240,18 +258,19 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
SMB2_CLIENT_GUID_SIZE);
|
||||
ctx.use_client_guid = true;
|
||||
|
||||
mutex_lock(&ses->session_mutex);
|
||||
chan_server = cifs_get_tcp_session(&ctx, ses->server);
|
||||
|
||||
mutex_lock(&ses->session_mutex);
|
||||
spin_lock(&ses->chan_lock);
|
||||
chan = ses->binding_chan = &ses->chans[ses->chan_count];
|
||||
chan->server = cifs_get_tcp_session(&ctx);
|
||||
chan->server = chan_server;
|
||||
if (IS_ERR(chan->server)) {
|
||||
rc = PTR_ERR(chan->server);
|
||||
chan->server = NULL;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
goto out;
|
||||
}
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
chan->server->is_channel = true;
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
/*
|
||||
* We need to allocate the server crypto now as we will need
|
||||
@@ -283,8 +302,11 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
|
||||
* ses to the new server.
|
||||
*/
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
ses->chan_count++;
|
||||
atomic_set(&ses->chan_seq, 0);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
out:
|
||||
ses->binding = false;
|
||||
ses->binding_chan = NULL;
|
||||
@@ -599,18 +621,85 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size)
|
||||
{
|
||||
int sz = base_size + ses->auth_key.len
|
||||
- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
|
||||
|
||||
if (ses->domainName)
|
||||
sz += sizeof(__le16) * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
|
||||
else
|
||||
sz += sizeof(__le16);
|
||||
|
||||
if (ses->user_name)
|
||||
sz += sizeof(__le16) * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
|
||||
else
|
||||
sz += sizeof(__le16);
|
||||
|
||||
sz += sizeof(__le16) * strnlen(ses->workstation_name, CIFS_MAX_WORKSTATION_LEN);
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf,
|
||||
char *str_value,
|
||||
int str_length,
|
||||
unsigned char *pstart,
|
||||
unsigned char **pcur,
|
||||
const struct nls_table *nls_cp)
|
||||
{
|
||||
unsigned char *tmp = pstart;
|
||||
int len;
|
||||
|
||||
if (!pbuf)
|
||||
return;
|
||||
|
||||
if (!pcur)
|
||||
pcur = &tmp;
|
||||
|
||||
if (!str_value) {
|
||||
pbuf->BufferOffset = cpu_to_le32(*pcur - pstart);
|
||||
pbuf->Length = 0;
|
||||
pbuf->MaximumLength = 0;
|
||||
*pcur += sizeof(__le16);
|
||||
} else {
|
||||
len = cifs_strtoUTF16((__le16 *)*pcur,
|
||||
str_value,
|
||||
str_length,
|
||||
nls_cp);
|
||||
len *= sizeof(__le16);
|
||||
pbuf->BufferOffset = cpu_to_le32(*pcur - pstart);
|
||||
pbuf->Length = cpu_to_le16(len);
|
||||
pbuf->MaximumLength = cpu_to_le16(len);
|
||||
*pcur += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* BB Move to ntlmssp.c eventually */
|
||||
|
||||
/* We do not malloc the blob, it is passed in pbuffer, because
|
||||
it is fixed size, and small, making this approach cleaner */
|
||||
void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
|
||||
struct cifs_ses *ses)
|
||||
int build_ntlmssp_negotiate_blob(unsigned char **pbuffer,
|
||||
u16 *buflen,
|
||||
struct cifs_ses *ses,
|
||||
const struct nls_table *nls_cp)
|
||||
{
|
||||
int rc = 0;
|
||||
struct TCP_Server_Info *server = cifs_ses_server(ses);
|
||||
NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer;
|
||||
NEGOTIATE_MESSAGE *sec_blob;
|
||||
__u32 flags;
|
||||
unsigned char *tmp;
|
||||
int len;
|
||||
|
||||
memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE));
|
||||
len = size_of_ntlmssp_blob(ses, sizeof(NEGOTIATE_MESSAGE));
|
||||
*pbuffer = kmalloc(len, GFP_KERNEL);
|
||||
if (!*pbuffer) {
|
||||
rc = -ENOMEM;
|
||||
cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
|
||||
*buflen = 0;
|
||||
goto setup_ntlm_neg_ret;
|
||||
}
|
||||
sec_blob = (NEGOTIATE_MESSAGE *)*pbuffer;
|
||||
|
||||
memset(*pbuffer, 0, sizeof(NEGOTIATE_MESSAGE));
|
||||
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
|
||||
sec_blob->MessageType = NtLmNegotiate;
|
||||
|
||||
@@ -624,34 +713,25 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
|
||||
if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
|
||||
flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
|
||||
|
||||
tmp = *pbuffer + sizeof(NEGOTIATE_MESSAGE);
|
||||
sec_blob->NegotiateFlags = cpu_to_le32(flags);
|
||||
|
||||
sec_blob->WorkstationName.BufferOffset = 0;
|
||||
sec_blob->WorkstationName.Length = 0;
|
||||
sec_blob->WorkstationName.MaximumLength = 0;
|
||||
/* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */
|
||||
cifs_security_buffer_from_str(&sec_blob->DomainName,
|
||||
NULL,
|
||||
CIFS_MAX_DOMAINNAME_LEN,
|
||||
*pbuffer, &tmp,
|
||||
nls_cp);
|
||||
|
||||
/* Domain name is sent on the Challenge not Negotiate NTLMSSP request */
|
||||
sec_blob->DomainName.BufferOffset = 0;
|
||||
sec_blob->DomainName.Length = 0;
|
||||
sec_blob->DomainName.MaximumLength = 0;
|
||||
}
|
||||
cifs_security_buffer_from_str(&sec_blob->WorkstationName,
|
||||
NULL,
|
||||
CIFS_MAX_WORKSTATION_LEN,
|
||||
*pbuffer, &tmp,
|
||||
nls_cp);
|
||||
|
||||
static int size_of_ntlmssp_blob(struct cifs_ses *ses)
|
||||
{
|
||||
int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len
|
||||
- CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
|
||||
|
||||
if (ses->domainName)
|
||||
sz += 2 * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
|
||||
else
|
||||
sz += 2;
|
||||
|
||||
if (ses->user_name)
|
||||
sz += 2 * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
|
||||
else
|
||||
sz += 2;
|
||||
|
||||
return sz;
|
||||
*buflen = tmp - *pbuffer;
|
||||
setup_ntlm_neg_ret:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int build_ntlmssp_auth_blob(unsigned char **pbuffer,
|
||||
@@ -663,6 +743,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
|
||||
AUTHENTICATE_MESSAGE *sec_blob;
|
||||
__u32 flags;
|
||||
unsigned char *tmp;
|
||||
int len;
|
||||
|
||||
rc = setup_ntlmv2_rsp(ses, nls_cp);
|
||||
if (rc) {
|
||||
@@ -670,7 +751,9 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
|
||||
*buflen = 0;
|
||||
goto setup_ntlmv2_ret;
|
||||
}
|
||||
*pbuffer = kmalloc(size_of_ntlmssp_blob(ses), GFP_KERNEL);
|
||||
|
||||
len = size_of_ntlmssp_blob(ses, sizeof(AUTHENTICATE_MESSAGE));
|
||||
*pbuffer = kmalloc(len, GFP_KERNEL);
|
||||
if (!*pbuffer) {
|
||||
rc = -ENOMEM;
|
||||
cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc);
|
||||
@@ -686,7 +769,7 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
|
||||
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
|
||||
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
|
||||
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC |
|
||||
NTLMSSP_NEGOTIATE_SEAL;
|
||||
NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED;
|
||||
if (ses->server->sign)
|
||||
flags |= NTLMSSP_NEGOTIATE_SIGN;
|
||||
if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess)
|
||||
@@ -719,42 +802,23 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer,
|
||||
sec_blob->NtChallengeResponse.MaximumLength = 0;
|
||||
}
|
||||
|
||||
if (ses->domainName == NULL) {
|
||||
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
|
||||
sec_blob->DomainName.Length = 0;
|
||||
sec_blob->DomainName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
} else {
|
||||
int len;
|
||||
len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
|
||||
CIFS_MAX_DOMAINNAME_LEN, nls_cp);
|
||||
len *= 2; /* unicode is 2 bytes each */
|
||||
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
|
||||
sec_blob->DomainName.Length = cpu_to_le16(len);
|
||||
sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
|
||||
tmp += len;
|
||||
}
|
||||
cifs_security_buffer_from_str(&sec_blob->DomainName,
|
||||
ses->domainName,
|
||||
CIFS_MAX_DOMAINNAME_LEN,
|
||||
*pbuffer, &tmp,
|
||||
nls_cp);
|
||||
|
||||
if (ses->user_name == NULL) {
|
||||
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
|
||||
sec_blob->UserName.Length = 0;
|
||||
sec_blob->UserName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
} else {
|
||||
int len;
|
||||
len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
|
||||
CIFS_MAX_USERNAME_LEN, nls_cp);
|
||||
len *= 2; /* unicode is 2 bytes each */
|
||||
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
|
||||
sec_blob->UserName.Length = cpu_to_le16(len);
|
||||
sec_blob->UserName.MaximumLength = cpu_to_le16(len);
|
||||
tmp += len;
|
||||
}
|
||||
cifs_security_buffer_from_str(&sec_blob->UserName,
|
||||
ses->user_name,
|
||||
CIFS_MAX_USERNAME_LEN,
|
||||
*pbuffer, &tmp,
|
||||
nls_cp);
|
||||
|
||||
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
|
||||
sec_blob->WorkstationName.Length = 0;
|
||||
sec_blob->WorkstationName.MaximumLength = 0;
|
||||
tmp += 2;
|
||||
cifs_security_buffer_from_str(&sec_blob->WorkstationName,
|
||||
ses->workstation_name,
|
||||
CIFS_MAX_WORKSTATION_LEN,
|
||||
*pbuffer, &tmp,
|
||||
nls_cp);
|
||||
|
||||
if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) ||
|
||||
(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
|
||||
@@ -1230,6 +1294,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
|
||||
struct cifs_ses *ses = sess_data->ses;
|
||||
__u16 bytes_remaining;
|
||||
char *bcc_ptr;
|
||||
unsigned char *ntlmsspblob = NULL;
|
||||
u16 blob_len;
|
||||
|
||||
cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
|
||||
@@ -1253,10 +1318,15 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
|
||||
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
|
||||
|
||||
/* Build security blob before we assemble the request */
|
||||
build_ntlmssp_negotiate_blob(pSMB->req.SecurityBlob, ses);
|
||||
sess_data->iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
|
||||
sess_data->iov[1].iov_base = pSMB->req.SecurityBlob;
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
|
||||
rc = build_ntlmssp_negotiate_blob(&ntlmsspblob,
|
||||
&blob_len, ses,
|
||||
sess_data->nls_cp);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
sess_data->iov[1].iov_len = blob_len;
|
||||
sess_data->iov[1].iov_base = ntlmsspblob;
|
||||
pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
|
||||
|
||||
rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
|
||||
if (rc)
|
||||
|
||||
@@ -46,6 +46,10 @@ struct cop_vars {
|
||||
struct smb2_file_link_info link_info;
|
||||
};
|
||||
|
||||
/*
|
||||
* note: If cfile is passed, the reference to it is dropped here.
|
||||
* So make sure that you do not reuse cfile after return from this func.
|
||||
*/
|
||||
static int
|
||||
smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, const char *full_path,
|
||||
@@ -536,10 +540,11 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE,
|
||||
smb2_data, SMB2_OP_QUERY_INFO, NULL);
|
||||
smb2_data, SMB2_OP_QUERY_INFO, cfile);
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -587,10 +592,11 @@ smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
create_options |= OPEN_REPARSE_POINT;
|
||||
|
||||
/* Failed on a symbolic link - query a reparse point info */
|
||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||
create_options, ACL_NO_MODE,
|
||||
smb2_data, SMB2_OP_POSIX_QUERY_INFO, NULL);
|
||||
smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
|
||||
}
|
||||
if (rc)
|
||||
goto out;
|
||||
@@ -707,10 +713,12 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, bool set_alloc)
|
||||
{
|
||||
__le64 eof = cpu_to_le64(size);
|
||||
struct cifsFileInfo *cfile;
|
||||
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
return smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
|
||||
&eof, SMB2_OP_SET_EOF, NULL);
|
||||
&eof, SMB2_OP_SET_EOF, cfile);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -719,6 +727,8 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifsFileInfo *cfile;
|
||||
int rc;
|
||||
|
||||
if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
|
||||
@@ -729,10 +739,12 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
rc = smb2_compound_op(xid, tlink_tcon(tlink), cifs_sb, full_path,
|
||||
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
|
||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_OPEN,
|
||||
0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, NULL);
|
||||
0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile);
|
||||
cifs_put_tlink(tlink);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2844,6 +2844,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct fsctl_get_dfs_referral_req *dfs_req = NULL;
|
||||
struct get_dfs_referral_rsp *dfs_rsp = NULL;
|
||||
u32 dfs_req_size = 0, dfs_rsp_size = 0;
|
||||
int retry_count = 0;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);
|
||||
|
||||
@@ -2895,11 +2896,14 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
||||
true /* is_fsctl */,
|
||||
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
|
||||
(char **)&dfs_rsp, &dfs_rsp_size);
|
||||
} while (rc == -EAGAIN);
|
||||
if (!is_retryable_error(rc))
|
||||
break;
|
||||
usleep_range(512, 2048);
|
||||
} while (++retry_count < 5);
|
||||
|
||||
if (rc) {
|
||||
if ((rc != -ENOENT) && (rc != -EOPNOTSUPP))
|
||||
cifs_tcon_dbg(VFS, "ioctl error in %s rc=%d\n", __func__, rc);
|
||||
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
|
||||
cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,11 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
if (tcon == NULL)
|
||||
return 0;
|
||||
|
||||
if (smb2_command == SMB2_TREE_CONNECT)
|
||||
/*
|
||||
* Need to also skip SMB2_IOCTL because it is used for checking nested dfs links in
|
||||
* cifs_tree_connect().
|
||||
*/
|
||||
if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
|
||||
return 0;
|
||||
|
||||
if (tcon->tidStatus == CifsExiting) {
|
||||
@@ -253,7 +257,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
/*
|
||||
* If we are reconnecting an extra channel, bind
|
||||
*/
|
||||
if (server->is_channel) {
|
||||
if (CIFS_SERVER_IS_CHAN(server)) {
|
||||
ses->binding = true;
|
||||
ses->binding_chan = cifs_ses_find_chan(ses, server);
|
||||
}
|
||||
@@ -1456,7 +1460,7 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
||||
int rc;
|
||||
struct cifs_ses *ses = sess_data->ses;
|
||||
struct smb2_sess_setup_rsp *rsp = NULL;
|
||||
char *ntlmssp_blob = NULL;
|
||||
unsigned char *ntlmssp_blob = NULL;
|
||||
bool use_spnego = false; /* else use raw ntlmssp */
|
||||
u16 blob_length = 0;
|
||||
|
||||
@@ -1475,22 +1479,17 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
|
||||
GFP_KERNEL);
|
||||
if (ntlmssp_blob == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
rc = build_ntlmssp_negotiate_blob(&ntlmssp_blob,
|
||||
&blob_length, ses,
|
||||
sess_data->nls_cp);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
|
||||
if (use_spnego) {
|
||||
/* BB eventually need to add this */
|
||||
cifs_dbg(VFS, "spnego not supported for SMB2 yet\n");
|
||||
rc = -EOPNOTSUPP;
|
||||
goto out;
|
||||
} else {
|
||||
blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
|
||||
/* with raw NTLMSSP we don't encapsulate in SPNEGO */
|
||||
}
|
||||
sess_data->iov[1].iov_base = ntlmssp_blob;
|
||||
sess_data->iov[1].iov_len = blob_length;
|
||||
@@ -1841,7 +1840,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base;
|
||||
trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc);
|
||||
if (rc != 0) {
|
||||
if ((rc != 0) || (rsp == NULL)) {
|
||||
cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE);
|
||||
tcon->need_reconnect = true;
|
||||
goto tcon_error_exit;
|
||||
@@ -2669,7 +2668,18 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
|
||||
goto err_free_rsp_buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although unlikely to be possible for rsp to be null and rc not set,
|
||||
* adding check below is slightly safer long term (and quiets Coverity
|
||||
* warning)
|
||||
*/
|
||||
rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
|
||||
if (rsp == NULL) {
|
||||
rc = -EIO;
|
||||
kfree(pc_buf);
|
||||
goto err_free_req;
|
||||
}
|
||||
|
||||
trace_smb3_posix_mkdir_done(xid, le64_to_cpu(rsp->PersistentFileId),
|
||||
tcon->tid,
|
||||
ses->Suid, CREATE_NOT_FILE,
|
||||
@@ -2942,7 +2952,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||
tcon->need_reconnect = true;
|
||||
}
|
||||
goto creat_exit;
|
||||
} else
|
||||
} else if (rsp == NULL) /* unlikely to happen, but safer to check */
|
||||
goto creat_exit;
|
||||
else
|
||||
trace_smb3_open_done(xid, le64_to_cpu(rsp->PersistentFileId),
|
||||
tcon->tid,
|
||||
ses->Suid, oparms->create_options,
|
||||
@@ -3163,6 +3175,16 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
|
||||
if ((plen == NULL) || (out_data == NULL))
|
||||
goto ioctl_exit;
|
||||
|
||||
/*
|
||||
* Although unlikely to be possible for rsp to be null and rc not set,
|
||||
* adding check below is slightly safer long term (and quiets Coverity
|
||||
* warning)
|
||||
*/
|
||||
if (rsp == NULL) {
|
||||
rc = -EIO;
|
||||
goto ioctl_exit;
|
||||
}
|
||||
|
||||
*plen = le32_to_cpu(rsp->OutputCount);
|
||||
|
||||
/* We check for obvious errors in the output buffer length and offset */
|
||||
|
||||
@@ -1044,14 +1044,17 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
|
||||
if (!ses)
|
||||
return NULL;
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (!ses->binding) {
|
||||
/* round robin */
|
||||
if (ses->chan_count > 1) {
|
||||
index = (uint)atomic_inc_return(&ses->chan_seq);
|
||||
index %= ses->chan_count;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return ses->chans[index].server;
|
||||
} else {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
return cifs_ses_server(ses);
|
||||
}
|
||||
}
|
||||
|
||||
17
fs/io-wq.c
17
fs/io-wq.c
@@ -423,9 +423,10 @@ static inline unsigned int io_get_work_hash(struct io_wq_work *work)
|
||||
return work->flags >> IO_WQ_HASH_SHIFT;
|
||||
}
|
||||
|
||||
static void io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
|
||||
static bool io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
|
||||
{
|
||||
struct io_wq *wq = wqe->wq;
|
||||
bool ret = false;
|
||||
|
||||
spin_lock_irq(&wq->hash->wait.lock);
|
||||
if (list_empty(&wqe->wait.entry)) {
|
||||
@@ -433,9 +434,11 @@ static void io_wait_on_hash(struct io_wqe *wqe, unsigned int hash)
|
||||
if (!test_bit(hash, &wq->hash->map)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
list_del_init(&wqe->wait.entry);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&wq->hash->wait.lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct io_wq_work *io_get_next_work(struct io_wqe_acct *acct,
|
||||
@@ -475,14 +478,21 @@ static struct io_wq_work *io_get_next_work(struct io_wqe_acct *acct,
|
||||
}
|
||||
|
||||
if (stall_hash != -1U) {
|
||||
bool unstalled;
|
||||
|
||||
/*
|
||||
* Set this before dropping the lock to avoid racing with new
|
||||
* work being added and clearing the stalled bit.
|
||||
*/
|
||||
set_bit(IO_ACCT_STALLED_BIT, &acct->flags);
|
||||
raw_spin_unlock(&wqe->lock);
|
||||
io_wait_on_hash(wqe, stall_hash);
|
||||
unstalled = io_wait_on_hash(wqe, stall_hash);
|
||||
raw_spin_lock(&wqe->lock);
|
||||
if (unstalled) {
|
||||
clear_bit(IO_ACCT_STALLED_BIT, &acct->flags);
|
||||
if (wq_has_sleeper(&wqe->wq->hash->wait))
|
||||
wake_up(&wqe->wq->hash->wait);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -564,8 +574,11 @@ get_next:
|
||||
io_wqe_enqueue(wqe, linked);
|
||||
|
||||
if (hash != -1U && !next_hashed) {
|
||||
/* serialize hash clear with wake_up() */
|
||||
spin_lock_irq(&wq->hash->wait.lock);
|
||||
clear_bit(hash, &wq->hash->map);
|
||||
clear_bit(IO_ACCT_STALLED_BIT, &acct->flags);
|
||||
spin_unlock_irq(&wq->hash->wait.lock);
|
||||
if (wq_has_sleeper(&wq->hash->wait))
|
||||
wake_up(&wq->hash->wait);
|
||||
raw_spin_lock(&wqe->lock);
|
||||
|
||||
@@ -6,7 +6,6 @@ config SMB_SERVER
|
||||
select NLS
|
||||
select NLS_UTF8
|
||||
select CRYPTO
|
||||
select CRYPTO_MD4
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ECB
|
||||
@@ -19,6 +18,7 @@ config SMB_SERVER
|
||||
select CRYPTO_GCM
|
||||
select ASN1
|
||||
select OID_REGISTRY
|
||||
select CRC32
|
||||
default n
|
||||
help
|
||||
Choose Y here if you want to allow SMB3 compliant clients
|
||||
|
||||
@@ -873,9 +873,9 @@ int ksmbd_gen_preauth_integrity_hash(struct ksmbd_conn *conn, char *buf,
|
||||
__u8 *pi_hash)
|
||||
{
|
||||
int rc;
|
||||
struct smb2_hdr *rcv_hdr = (struct smb2_hdr *)buf;
|
||||
struct smb2_hdr *rcv_hdr = smb2_get_msg(buf);
|
||||
char *all_bytes_msg = (char *)&rcv_hdr->ProtocolId;
|
||||
int msg_size = be32_to_cpu(rcv_hdr->smb2_buf_length);
|
||||
int msg_size = get_rfc1002_len(buf);
|
||||
struct ksmbd_crypto_ctx *ctx = NULL;
|
||||
|
||||
if (conn->preauth_info->Preauth_HashId !=
|
||||
@@ -983,7 +983,7 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||
u8 *sign)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int i, nr_entries[3] = {0}, total_entries = 0, sg_idx = 0;
|
||||
|
||||
if (!nvec)
|
||||
@@ -1047,9 +1047,8 @@ static struct scatterlist *ksmbd_init_sg(struct kvec *iov, unsigned int nvec,
|
||||
int ksmbd_crypt_message(struct ksmbd_conn *conn, struct kvec *iov,
|
||||
unsigned int nvec, int enc)
|
||||
{
|
||||
struct smb2_transform_hdr *tr_hdr =
|
||||
(struct smb2_transform_hdr *)iov[0].iov_base;
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24;
|
||||
struct smb2_transform_hdr *tr_hdr = smb2_get_msg(iov[0].iov_base);
|
||||
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
||||
int rc;
|
||||
struct scatterlist *sg;
|
||||
u8 sign[SMB2_SIGNATURE_SIZE] = {};
|
||||
|
||||
@@ -158,26 +158,25 @@ void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
|
||||
int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
{
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
struct smb_hdr *rsp_hdr = work->response_buf;
|
||||
size_t len = 0;
|
||||
int sent;
|
||||
struct kvec iov[3];
|
||||
int iov_idx = 0;
|
||||
|
||||
ksmbd_conn_try_dequeue_request(work);
|
||||
if (!rsp_hdr) {
|
||||
if (!work->response_buf) {
|
||||
pr_err("NULL response header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (work->tr_buf) {
|
||||
iov[iov_idx] = (struct kvec) { work->tr_buf,
|
||||
sizeof(struct smb2_transform_hdr) };
|
||||
sizeof(struct smb2_transform_hdr) + 4 };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
}
|
||||
|
||||
if (work->aux_payload_sz) {
|
||||
iov[iov_idx] = (struct kvec) { rsp_hdr, work->resp_hdr_sz };
|
||||
iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz };
|
||||
len += iov[iov_idx++].iov_len;
|
||||
@@ -185,8 +184,8 @@ int ksmbd_conn_write(struct ksmbd_work *work)
|
||||
if (work->tr_buf)
|
||||
iov[iov_idx].iov_len = work->resp_hdr_sz;
|
||||
else
|
||||
iov[iov_idx].iov_len = get_rfc1002_len(rsp_hdr) + 4;
|
||||
iov[iov_idx].iov_base = rsp_hdr;
|
||||
iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4;
|
||||
iov[iov_idx].iov_base = work->response_buf;
|
||||
len += iov[iov_idx++].iov_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@ int ksmbd_workqueue_init(void)
|
||||
|
||||
void ksmbd_workqueue_destroy(void)
|
||||
{
|
||||
flush_workqueue(ksmbd_wq);
|
||||
destroy_workqueue(ksmbd_wq);
|
||||
ksmbd_wq = NULL;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ struct ksmbd_work {
|
||||
*/
|
||||
static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
|
||||
{
|
||||
return work->response_buf + work->next_smb2_rsp_hdr_off;
|
||||
return work->response_buf + work->next_smb2_rsp_hdr_off + 4;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +101,7 @@ static inline void *ksmbd_resp_buf_next(struct ksmbd_work *work)
|
||||
*/
|
||||
static inline void *ksmbd_req_buf_next(struct ksmbd_work *work)
|
||||
{
|
||||
return work->request_buf + work->next_smb2_rcv_hdr_off;
|
||||
return work->request_buf + work->next_smb2_rcv_hdr_off + 4;
|
||||
}
|
||||
|
||||
struct ksmbd_work *ksmbd_alloc_work_struct(void);
|
||||
|
||||
@@ -629,10 +629,10 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
return;
|
||||
}
|
||||
|
||||
rsp_hdr = work->response_buf;
|
||||
rsp_hdr = smb2_get_msg(work->response_buf);
|
||||
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
|
||||
rsp_hdr->smb2_buf_length =
|
||||
cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals));
|
||||
*(__be32 *)work->response_buf =
|
||||
cpu_to_be32(conn->vals->header_size);
|
||||
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
|
||||
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
|
||||
rsp_hdr->CreditRequest = cpu_to_le16(0);
|
||||
@@ -645,7 +645,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
rsp_hdr->SessionId = 0;
|
||||
memset(rsp_hdr->Signature, 0, 16);
|
||||
|
||||
rsp = work->response_buf;
|
||||
rsp = smb2_get_msg(work->response_buf);
|
||||
|
||||
rsp->StructureSize = cpu_to_le16(24);
|
||||
if (!br_info->open_trunc &&
|
||||
@@ -659,7 +659,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
|
||||
rsp->PersistentFid = cpu_to_le64(fp->persistent_id);
|
||||
rsp->VolatileFid = cpu_to_le64(fp->volatile_id);
|
||||
|
||||
inc_rfc1001_len(rsp, 24);
|
||||
inc_rfc1001_len(work->response_buf, 24);
|
||||
|
||||
ksmbd_debug(OPLOCK,
|
||||
"sending oplock break v_id %llu p_id = %llu lock level = %d\n",
|
||||
@@ -736,10 +736,10 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
return;
|
||||
}
|
||||
|
||||
rsp_hdr = work->response_buf;
|
||||
rsp_hdr = smb2_get_msg(work->response_buf);
|
||||
memset(rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
|
||||
rsp_hdr->smb2_buf_length =
|
||||
cpu_to_be32(smb2_hdr_size_no_buflen(conn->vals));
|
||||
*(__be32 *)work->response_buf =
|
||||
cpu_to_be32(conn->vals->header_size);
|
||||
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
|
||||
rsp_hdr->StructureSize = SMB2_HEADER_STRUCTURE_SIZE;
|
||||
rsp_hdr->CreditRequest = cpu_to_le16(0);
|
||||
@@ -752,7 +752,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
rsp_hdr->SessionId = 0;
|
||||
memset(rsp_hdr->Signature, 0, 16);
|
||||
|
||||
rsp = work->response_buf;
|
||||
rsp = smb2_get_msg(work->response_buf);
|
||||
rsp->StructureSize = cpu_to_le16(44);
|
||||
rsp->Epoch = br_info->epoch;
|
||||
rsp->Flags = 0;
|
||||
@@ -768,7 +768,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
|
||||
rsp->AccessMaskHint = 0;
|
||||
rsp->ShareMaskHint = 0;
|
||||
|
||||
inc_rfc1001_len(rsp, 44);
|
||||
inc_rfc1001_len(work->response_buf, 44);
|
||||
|
||||
ksmbd_conn_write(work);
|
||||
ksmbd_free_work_struct(work);
|
||||
@@ -1335,19 +1335,16 @@ __u8 smb2_map_lease_to_oplock(__le32 lease_state)
|
||||
*/
|
||||
void create_lease_buf(u8 *rbuf, struct lease *lease)
|
||||
{
|
||||
char *LeaseKey = (char *)&lease->lease_key;
|
||||
|
||||
if (lease->version == 2) {
|
||||
struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;
|
||||
char *ParentLeaseKey = (char *)&lease->parent_lease_key;
|
||||
|
||||
memset(buf, 0, sizeof(struct create_lease_v2));
|
||||
buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
|
||||
buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
|
||||
memcpy(buf->lcontext.LeaseKey, lease->lease_key,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
buf->lcontext.LeaseFlags = lease->flags;
|
||||
buf->lcontext.LeaseState = lease->state;
|
||||
buf->lcontext.ParentLeaseKeyLow = *((__le64 *)ParentLeaseKey);
|
||||
buf->lcontext.ParentLeaseKeyHigh = *((__le64 *)(ParentLeaseKey + 8));
|
||||
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
(struct create_lease_v2, lcontext));
|
||||
buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
|
||||
@@ -1362,8 +1359,7 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
|
||||
struct create_lease *buf = (struct create_lease *)rbuf;
|
||||
|
||||
memset(buf, 0, sizeof(struct create_lease));
|
||||
buf->lcontext.LeaseKeyLow = *((__le64 *)LeaseKey);
|
||||
buf->lcontext.LeaseKeyHigh = *((__le64 *)(LeaseKey + 8));
|
||||
memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE);
|
||||
buf->lcontext.LeaseFlags = lease->flags;
|
||||
buf->lcontext.LeaseState = lease->state;
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
@@ -1398,7 +1394,7 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
|
||||
if (!lreq)
|
||||
return NULL;
|
||||
|
||||
data_offset = (char *)req + 4 + le32_to_cpu(req->CreateContextsOffset);
|
||||
data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset);
|
||||
cc = (struct create_context *)data_offset;
|
||||
do {
|
||||
cc = (struct create_context *)((char *)cc + next);
|
||||
@@ -1416,19 +1412,17 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
|
||||
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
|
||||
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
|
||||
|
||||
*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
|
||||
*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
*((__le64 *)lreq->parent_lease_key) = lc->lcontext.ParentLeaseKeyLow;
|
||||
*((__le64 *)(lreq->parent_lease_key + 8)) = lc->lcontext.ParentLeaseKeyHigh;
|
||||
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
|
||||
SMB2_LEASE_KEY_SIZE);
|
||||
lreq->version = 2;
|
||||
} else {
|
||||
struct create_lease *lc = (struct create_lease *)cc;
|
||||
|
||||
*((__le64 *)lreq->lease_key) = lc->lcontext.LeaseKeyLow;
|
||||
*((__le64 *)(lreq->lease_key + 8)) = lc->lcontext.LeaseKeyHigh;
|
||||
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
||||
lreq->req_state = lc->lcontext.LeaseState;
|
||||
lreq->flags = lc->lcontext.LeaseFlags;
|
||||
lreq->duration = lc->lcontext.LeaseDuration;
|
||||
@@ -1462,7 +1456,7 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag)
|
||||
* CreateContextsOffset and CreateContextsLength are guaranteed to
|
||||
* be valid because of ksmbd_smb2_check_message().
|
||||
*/
|
||||
cc = (struct create_context *)((char *)req + 4 +
|
||||
cc = (struct create_context *)((char *)req +
|
||||
le32_to_cpu(req->CreateContextsOffset));
|
||||
remain_len = le32_to_cpu(req->CreateContextsLength);
|
||||
do {
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#define OPLOCK_WRITE_TO_NONE 0x04
|
||||
#define OPLOCK_READ_TO_NONE 0x08
|
||||
|
||||
#define SMB2_LEASE_KEY_SIZE 16
|
||||
|
||||
struct lease_ctx_info {
|
||||
__u8 lease_key[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 req_state;
|
||||
|
||||
@@ -622,7 +622,6 @@ MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SOFTDEP("pre: ecb");
|
||||
MODULE_SOFTDEP("pre: hmac");
|
||||
MODULE_SOFTDEP("pre: md4");
|
||||
MODULE_SOFTDEP("pre: md5");
|
||||
MODULE_SOFTDEP("pre: nls");
|
||||
MODULE_SOFTDEP("pre: aes");
|
||||
@@ -632,5 +631,6 @@ MODULE_SOFTDEP("pre: sha512");
|
||||
MODULE_SOFTDEP("pre: aead2");
|
||||
MODULE_SOFTDEP("pre: ccm");
|
||||
MODULE_SOFTDEP("pre: gcm");
|
||||
MODULE_SOFTDEP("pre: crc32");
|
||||
module_init(ksmbd_server_init)
|
||||
module_exit(ksmbd_server_exit)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include "glob.h"
|
||||
#include "nterr.h"
|
||||
#include "smb2pdu.h"
|
||||
#include "smb_common.h"
|
||||
#include "smbstatus.h"
|
||||
#include "mgmt/user_session.h"
|
||||
@@ -347,23 +346,16 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
|
||||
|
||||
int ksmbd_smb2_check_message(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb2_pdu *pdu = work->request_buf;
|
||||
struct smb2_pdu *pdu = ksmbd_req_buf_next(work);
|
||||
struct smb2_hdr *hdr = &pdu->hdr;
|
||||
int command;
|
||||
__u32 clc_len; /* calculated length */
|
||||
__u32 len = get_rfc1002_len(pdu);
|
||||
__u32 len = get_rfc1002_len(work->request_buf);
|
||||
|
||||
if (work->next_smb2_rcv_hdr_off) {
|
||||
pdu = ksmbd_req_buf_next(work);
|
||||
hdr = &pdu->hdr;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(hdr->NextCommand) > 0) {
|
||||
if (le32_to_cpu(hdr->NextCommand) > 0)
|
||||
len = le32_to_cpu(hdr->NextCommand);
|
||||
} else if (work->next_smb2_rcv_hdr_off) {
|
||||
else if (work->next_smb2_rcv_hdr_off)
|
||||
len -= work->next_smb2_rcv_hdr_off;
|
||||
len = round_up(len, 8);
|
||||
}
|
||||
|
||||
if (check_smb2_hdr(hdr))
|
||||
return 1;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "glob.h"
|
||||
#include "smb2pdu.h"
|
||||
|
||||
#include "auth.h"
|
||||
#include "connection.h"
|
||||
@@ -199,7 +198,7 @@ void init_smb2_1_server(struct ksmbd_conn *conn)
|
||||
conn->cmds = smb2_0_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds);
|
||||
conn->max_credits = SMB2_MAX_CREDITS;
|
||||
conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256;
|
||||
conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256_LE;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
@@ -217,7 +216,7 @@ void init_smb3_0_server(struct ksmbd_conn *conn)
|
||||
conn->cmds = smb2_0_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds);
|
||||
conn->max_credits = SMB2_MAX_CREDITS;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
@@ -242,7 +241,7 @@ void init_smb3_02_server(struct ksmbd_conn *conn)
|
||||
conn->cmds = smb2_0_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds);
|
||||
conn->max_credits = SMB2_MAX_CREDITS;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
@@ -267,7 +266,7 @@ int init_smb3_11_server(struct ksmbd_conn *conn)
|
||||
conn->cmds = smb2_0_server_cmds;
|
||||
conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds);
|
||||
conn->max_credits = SMB2_MAX_CREDITS;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC;
|
||||
conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE;
|
||||
|
||||
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES)
|
||||
conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,60 +10,6 @@
|
||||
#include "ntlmssp.h"
|
||||
#include "smbacl.h"
|
||||
|
||||
/*
|
||||
* Note that, due to trying to use names similar to the protocol specifications,
|
||||
* there are many mixed case field names in the structures below. Although
|
||||
* this does not match typical Linux kernel style, it is necessary to be
|
||||
* able to match against the protocol specfication.
|
||||
*
|
||||
* SMB2 commands
|
||||
* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
|
||||
* (ie no useful data other than the SMB error code itself) and are marked such.
|
||||
* Knowing this helps avoid response buffer allocations and copy in some cases.
|
||||
*/
|
||||
|
||||
/* List of commands in host endian */
|
||||
#define SMB2_NEGOTIATE_HE 0x0000
|
||||
#define SMB2_SESSION_SETUP_HE 0x0001
|
||||
#define SMB2_LOGOFF_HE 0x0002 /* trivial request/resp */
|
||||
#define SMB2_TREE_CONNECT_HE 0x0003
|
||||
#define SMB2_TREE_DISCONNECT_HE 0x0004 /* trivial req/resp */
|
||||
#define SMB2_CREATE_HE 0x0005
|
||||
#define SMB2_CLOSE_HE 0x0006
|
||||
#define SMB2_FLUSH_HE 0x0007 /* trivial resp */
|
||||
#define SMB2_READ_HE 0x0008
|
||||
#define SMB2_WRITE_HE 0x0009
|
||||
#define SMB2_LOCK_HE 0x000A
|
||||
#define SMB2_IOCTL_HE 0x000B
|
||||
#define SMB2_CANCEL_HE 0x000C
|
||||
#define SMB2_ECHO_HE 0x000D
|
||||
#define SMB2_QUERY_DIRECTORY_HE 0x000E
|
||||
#define SMB2_CHANGE_NOTIFY_HE 0x000F
|
||||
#define SMB2_QUERY_INFO_HE 0x0010
|
||||
#define SMB2_SET_INFO_HE 0x0011
|
||||
#define SMB2_OPLOCK_BREAK_HE 0x0012
|
||||
|
||||
/* The same list in little endian */
|
||||
#define SMB2_NEGOTIATE cpu_to_le16(SMB2_NEGOTIATE_HE)
|
||||
#define SMB2_SESSION_SETUP cpu_to_le16(SMB2_SESSION_SETUP_HE)
|
||||
#define SMB2_LOGOFF cpu_to_le16(SMB2_LOGOFF_HE)
|
||||
#define SMB2_TREE_CONNECT cpu_to_le16(SMB2_TREE_CONNECT_HE)
|
||||
#define SMB2_TREE_DISCONNECT cpu_to_le16(SMB2_TREE_DISCONNECT_HE)
|
||||
#define SMB2_CREATE cpu_to_le16(SMB2_CREATE_HE)
|
||||
#define SMB2_CLOSE cpu_to_le16(SMB2_CLOSE_HE)
|
||||
#define SMB2_FLUSH cpu_to_le16(SMB2_FLUSH_HE)
|
||||
#define SMB2_READ cpu_to_le16(SMB2_READ_HE)
|
||||
#define SMB2_WRITE cpu_to_le16(SMB2_WRITE_HE)
|
||||
#define SMB2_LOCK cpu_to_le16(SMB2_LOCK_HE)
|
||||
#define SMB2_IOCTL cpu_to_le16(SMB2_IOCTL_HE)
|
||||
#define SMB2_CANCEL cpu_to_le16(SMB2_CANCEL_HE)
|
||||
#define SMB2_ECHO cpu_to_le16(SMB2_ECHO_HE)
|
||||
#define SMB2_QUERY_DIRECTORY cpu_to_le16(SMB2_QUERY_DIRECTORY_HE)
|
||||
#define SMB2_CHANGE_NOTIFY cpu_to_le16(SMB2_CHANGE_NOTIFY_HE)
|
||||
#define SMB2_QUERY_INFO cpu_to_le16(SMB2_QUERY_INFO_HE)
|
||||
#define SMB2_SET_INFO cpu_to_le16(SMB2_SET_INFO_HE)
|
||||
#define SMB2_OPLOCK_BREAK cpu_to_le16(SMB2_OPLOCK_BREAK_HE)
|
||||
|
||||
/*Create Action Flags*/
|
||||
#define FILE_SUPERSEDED 0x00000000
|
||||
#define FILE_OPENED 0x00000001
|
||||
@@ -96,9 +42,6 @@
|
||||
/* SMB2 Max Credits */
|
||||
#define SMB2_MAX_CREDITS 8192
|
||||
|
||||
#define SMB2_CLIENT_GUID_SIZE 16
|
||||
#define SMB2_CREATE_GUID_SIZE 16
|
||||
|
||||
/* Maximum buffer size value we can send with 1 credit */
|
||||
#define SMB2_MAX_BUFFER_SIZE 65536
|
||||
|
||||
@@ -107,87 +50,12 @@
|
||||
/* BB FIXME - analyze following length BB */
|
||||
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
|
||||
|
||||
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) /* 'B''M''S' */
|
||||
#define SMB2_TRANSFORM_PROTO_NUM cpu_to_le32(0x424d53fd)
|
||||
|
||||
#define SMB21_DEFAULT_IOSIZE (1024 * 1024)
|
||||
#define SMB3_DEFAULT_IOSIZE (4 * 1024 * 1024)
|
||||
#define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024)
|
||||
#define SMB3_MIN_IOSIZE (64 * 1024)
|
||||
#define SMB3_MAX_IOSIZE (8 * 1024 * 1024)
|
||||
|
||||
/*
|
||||
* SMB2 Header Definition
|
||||
*
|
||||
* "MBZ" : Must be Zero
|
||||
* "BB" : BugBug, Something to check/review/analyze later
|
||||
* "PDU" : "Protocol Data Unit" (ie a network "frame")
|
||||
*
|
||||
*/
|
||||
|
||||
#define __SMB2_HEADER_STRUCTURE_SIZE 64
|
||||
#define SMB2_HEADER_STRUCTURE_SIZE \
|
||||
cpu_to_le16(__SMB2_HEADER_STRUCTURE_SIZE)
|
||||
|
||||
struct smb2_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/*
|
||||
* length is only two or three bytes - with
|
||||
* one or two byte type preceding it that MBZ
|
||||
*/
|
||||
__le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
|
||||
__le16 StructureSize; /* 64 */
|
||||
__le16 CreditCharge; /* MBZ */
|
||||
__le32 Status; /* Error from server */
|
||||
__le16 Command;
|
||||
__le16 CreditRequest; /* CreditResponse */
|
||||
__le32 Flags;
|
||||
__le32 NextCommand;
|
||||
__le64 MessageId;
|
||||
union {
|
||||
struct {
|
||||
__le32 ProcessId;
|
||||
__le32 TreeId;
|
||||
} __packed SyncId;
|
||||
__le64 AsyncId;
|
||||
} __packed Id;
|
||||
__le64 SessionId;
|
||||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
struct smb2_pdu {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
} __packed;
|
||||
|
||||
#define SMB3_AES_CCM_NONCE 11
|
||||
#define SMB3_AES_GCM_NONCE 12
|
||||
|
||||
struct smb2_transform_hdr {
|
||||
__be32 smb2_buf_length; /* big endian on wire */
|
||||
/*
|
||||
* length is only two or three bytes - with
|
||||
* one or two byte type preceding it that MBZ
|
||||
*/
|
||||
__le32 ProtocolId; /* 0xFD 'S' 'M' 'B' */
|
||||
__u8 Signature[16];
|
||||
__u8 Nonce[16];
|
||||
__le32 OriginalMessageSize;
|
||||
__u16 Reserved1;
|
||||
__le16 Flags; /* EncryptionAlgorithm */
|
||||
__le64 SessionId;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* SMB2 flag definitions
|
||||
*/
|
||||
#define SMB2_FLAGS_SERVER_TO_REDIR cpu_to_le32(0x00000001)
|
||||
#define SMB2_FLAGS_ASYNC_COMMAND cpu_to_le32(0x00000002)
|
||||
#define SMB2_FLAGS_RELATED_OPERATIONS cpu_to_le32(0x00000004)
|
||||
#define SMB2_FLAGS_SIGNED cpu_to_le32(0x00000008)
|
||||
#define SMB2_FLAGS_DFS_OPERATIONS cpu_to_le32(0x10000000)
|
||||
#define SMB2_FLAGS_REPLAY_OPERATIONS cpu_to_le32(0x20000000)
|
||||
|
||||
/*
|
||||
* Definitions for SMB2 Protocol Data Units (network frames)
|
||||
*
|
||||
@@ -209,425 +77,30 @@ struct smb2_err_rsp {
|
||||
__u8 ErrorData[1]; /* variable length */
|
||||
} __packed;
|
||||
|
||||
struct smb2_negotiate_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 36 */
|
||||
__le16 DialectCount;
|
||||
__le16 SecurityMode;
|
||||
__le16 Reserved; /* MBZ */
|
||||
__le32 Capabilities;
|
||||
__u8 ClientGUID[SMB2_CLIENT_GUID_SIZE];
|
||||
/* In SMB3.02 and earlier next three were MBZ le64 ClientStartTime */
|
||||
__le32 NegotiateContextOffset; /* SMB3.1.1 only. MBZ earlier */
|
||||
__le16 NegotiateContextCount; /* SMB3.1.1 only. MBZ earlier */
|
||||
__le16 Reserved2;
|
||||
__le16 Dialects[1]; /* One dialect (vers=) at a time for now */
|
||||
} __packed;
|
||||
|
||||
/* SecurityMode flags */
|
||||
#define SMB2_NEGOTIATE_SIGNING_ENABLED_LE cpu_to_le16(0x0001)
|
||||
#define SMB2_NEGOTIATE_SIGNING_REQUIRED 0x0002
|
||||
#define SMB2_NEGOTIATE_SIGNING_REQUIRED_LE cpu_to_le16(0x0002)
|
||||
/* Capabilities flags */
|
||||
#define SMB2_GLOBAL_CAP_DFS 0x00000001
|
||||
#define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */
|
||||
#define SMB2_GLOBAL_CAP_LARGE_MTU 0X00000004 /* Resp only New to SMB2.1 */
|
||||
#define SMB2_GLOBAL_CAP_MULTI_CHANNEL 0x00000008 /* New to SMB3 */
|
||||
#define SMB2_GLOBAL_CAP_PERSISTENT_HANDLES 0x00000010 /* New to SMB3 */
|
||||
#define SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020 /* New to SMB3 */
|
||||
#define SMB2_GLOBAL_CAP_ENCRYPTION 0x00000040 /* New to SMB3 */
|
||||
/* Internal types */
|
||||
#define SMB2_NT_FIND 0x00100000
|
||||
#define SMB2_LARGE_FILES 0x00200000
|
||||
|
||||
#define SMB311_SALT_SIZE 32
|
||||
/* Hash Algorithm Types */
|
||||
#define SMB2_PREAUTH_INTEGRITY_SHA512 cpu_to_le16(0x0001)
|
||||
|
||||
#define PREAUTH_HASHVALUE_SIZE 64
|
||||
|
||||
struct preauth_integrity_info {
|
||||
/* PreAuth integrity Hash ID */
|
||||
__le16 Preauth_HashId;
|
||||
/* PreAuth integrity Hash Value */
|
||||
__u8 Preauth_HashValue[PREAUTH_HASHVALUE_SIZE];
|
||||
__u8 Preauth_HashValue[SMB2_PREAUTH_HASH_SIZE];
|
||||
};
|
||||
|
||||
/* offset is sizeof smb2_negotiate_rsp - 4 but rounded up to 8 bytes. */
|
||||
/* offset is sizeof smb2_negotiate_rsp but rounded up to 8 bytes. */
|
||||
#ifdef CONFIG_SMB_SERVER_KERBEROS5
|
||||
/* sizeof(struct smb2_negotiate_rsp) - 4 =
|
||||
/* sizeof(struct smb2_negotiate_rsp) =
|
||||
* header(64) + response(64) + GSS_LENGTH(96) + GSS_PADDING(0)
|
||||
*/
|
||||
#define OFFSET_OF_NEG_CONTEXT 0xe0
|
||||
#else
|
||||
/* sizeof(struct smb2_negotiate_rsp) - 4 =
|
||||
/* sizeof(struct smb2_negotiate_rsp) =
|
||||
* header(64) + response(64) + GSS_LENGTH(74) + GSS_PADDING(6)
|
||||
*/
|
||||
#define OFFSET_OF_NEG_CONTEXT 0xd0
|
||||
#endif
|
||||
|
||||
#define SMB2_PREAUTH_INTEGRITY_CAPABILITIES cpu_to_le16(1)
|
||||
#define SMB2_ENCRYPTION_CAPABILITIES cpu_to_le16(2)
|
||||
#define SMB2_COMPRESSION_CAPABILITIES cpu_to_le16(3)
|
||||
#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID cpu_to_le16(5)
|
||||
#define SMB2_SIGNING_CAPABILITIES cpu_to_le16(8)
|
||||
#define SMB2_POSIX_EXTENSIONS_AVAILABLE cpu_to_le16(0x100)
|
||||
|
||||
struct smb2_neg_context {
|
||||
__le16 ContextType;
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
/* Followed by array of data */
|
||||
} __packed;
|
||||
|
||||
struct smb2_preauth_neg_context {
|
||||
__le16 ContextType; /* 1 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 HashAlgorithmCount; /* 1 */
|
||||
__le16 SaltLength;
|
||||
__le16 HashAlgorithms; /* HashAlgorithms[0] since only one defined */
|
||||
__u8 Salt[SMB311_SALT_SIZE];
|
||||
} __packed;
|
||||
|
||||
/* Encryption Algorithms Ciphers */
|
||||
#define SMB2_ENCRYPTION_AES128_CCM cpu_to_le16(0x0001)
|
||||
#define SMB2_ENCRYPTION_AES128_GCM cpu_to_le16(0x0002)
|
||||
#define SMB2_ENCRYPTION_AES256_CCM cpu_to_le16(0x0003)
|
||||
#define SMB2_ENCRYPTION_AES256_GCM cpu_to_le16(0x0004)
|
||||
|
||||
struct smb2_encryption_neg_context {
|
||||
__le16 ContextType; /* 2 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
/* CipherCount usally 2, but can be 3 when AES256-GCM enabled */
|
||||
__le16 CipherCount; /* AES-128-GCM and AES-128-CCM by default */
|
||||
__le16 Ciphers[];
|
||||
} __packed;
|
||||
|
||||
#define SMB3_COMPRESS_NONE cpu_to_le16(0x0000)
|
||||
#define SMB3_COMPRESS_LZNT1 cpu_to_le16(0x0001)
|
||||
#define SMB3_COMPRESS_LZ77 cpu_to_le16(0x0002)
|
||||
#define SMB3_COMPRESS_LZ77_HUFF cpu_to_le16(0x0003)
|
||||
|
||||
struct smb2_compression_ctx {
|
||||
__le16 ContextType; /* 3 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 CompressionAlgorithmCount;
|
||||
__u16 Padding;
|
||||
__le32 Reserved1;
|
||||
__le16 CompressionAlgorithms[];
|
||||
} __packed;
|
||||
|
||||
#define POSIX_CTXT_DATA_LEN 16
|
||||
struct smb2_posix_neg_context {
|
||||
__le16 ContextType; /* 0x100 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__u8 Name[16]; /* POSIX ctxt GUID 93AD25509CB411E7B42383DE968BCD7C */
|
||||
} __packed;
|
||||
|
||||
struct smb2_netname_neg_context {
|
||||
__le16 ContextType; /* 0x100 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 NetName[]; /* hostname of target converted to UCS-2 */
|
||||
} __packed;
|
||||
|
||||
/* Signing algorithms */
|
||||
#define SIGNING_ALG_HMAC_SHA256 cpu_to_le16(0)
|
||||
#define SIGNING_ALG_AES_CMAC cpu_to_le16(1)
|
||||
#define SIGNING_ALG_AES_GMAC cpu_to_le16(2)
|
||||
|
||||
struct smb2_signing_capabilities {
|
||||
__le16 ContextType; /* 8 */
|
||||
__le16 DataLength;
|
||||
__le32 Reserved;
|
||||
__le16 SigningAlgorithmCount;
|
||||
__le16 SigningAlgorithms[];
|
||||
} __packed;
|
||||
|
||||
struct smb2_negotiate_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 65 */
|
||||
__le16 SecurityMode;
|
||||
__le16 DialectRevision;
|
||||
__le16 NegotiateContextCount; /* Prior to SMB3.1.1 was Reserved & MBZ */
|
||||
__u8 ServerGUID[16];
|
||||
__le32 Capabilities;
|
||||
__le32 MaxTransactSize;
|
||||
__le32 MaxReadSize;
|
||||
__le32 MaxWriteSize;
|
||||
__le64 SystemTime; /* MBZ */
|
||||
__le64 ServerStartTime;
|
||||
__le16 SecurityBufferOffset;
|
||||
__le16 SecurityBufferLength;
|
||||
__le32 NegotiateContextOffset; /* Pre:SMB3.1.1 was reserved/ignored */
|
||||
__u8 Buffer[1]; /* variable length GSS security buffer */
|
||||
} __packed;
|
||||
|
||||
/* Flags */
|
||||
#define SMB2_SESSION_REQ_FLAG_BINDING 0x01
|
||||
#define SMB2_SESSION_REQ_FLAG_ENCRYPT_DATA 0x04
|
||||
|
||||
#define SMB2_SESSION_EXPIRED (0)
|
||||
#define SMB2_SESSION_IN_PROGRESS BIT(0)
|
||||
#define SMB2_SESSION_VALID BIT(1)
|
||||
|
||||
/* Flags */
|
||||
#define SMB2_SESSION_REQ_FLAG_BINDING 0x01
|
||||
#define SMB2_SESSION_REQ_FLAG_ENCRYPT_DATA 0x04
|
||||
|
||||
struct smb2_sess_setup_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 25 */
|
||||
__u8 Flags;
|
||||
__u8 SecurityMode;
|
||||
__le32 Capabilities;
|
||||
__le32 Channel;
|
||||
__le16 SecurityBufferOffset;
|
||||
__le16 SecurityBufferLength;
|
||||
__le64 PreviousSessionId;
|
||||
__u8 Buffer[1]; /* variable length GSS security buffer */
|
||||
} __packed;
|
||||
|
||||
/* Flags/Reserved for SMB3.1.1 */
|
||||
#define SMB2_SHAREFLAG_CLUSTER_RECONNECT 0x0001
|
||||
|
||||
/* Currently defined SessionFlags */
|
||||
#define SMB2_SESSION_FLAG_IS_GUEST_LE cpu_to_le16(0x0001)
|
||||
#define SMB2_SESSION_FLAG_IS_NULL_LE cpu_to_le16(0x0002)
|
||||
#define SMB2_SESSION_FLAG_ENCRYPT_DATA_LE cpu_to_le16(0x0004)
|
||||
struct smb2_sess_setup_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 SessionFlags;
|
||||
__le16 SecurityBufferOffset;
|
||||
__le16 SecurityBufferLength;
|
||||
__u8 Buffer[1]; /* variable length GSS security buffer */
|
||||
} __packed;
|
||||
|
||||
struct smb2_logoff_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_logoff_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_tree_connect_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 Reserved; /* Flags in SMB3.1.1 */
|
||||
__le16 PathOffset;
|
||||
__le16 PathLength;
|
||||
__u8 Buffer[1]; /* variable length */
|
||||
} __packed;
|
||||
|
||||
struct smb2_tree_connect_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 16 */
|
||||
__u8 ShareType; /* see below */
|
||||
__u8 Reserved;
|
||||
__le32 ShareFlags; /* see below */
|
||||
__le32 Capabilities; /* see below */
|
||||
__le32 MaximalAccess;
|
||||
} __packed;
|
||||
|
||||
/* Possible ShareType values */
|
||||
#define SMB2_SHARE_TYPE_DISK 0x01
|
||||
#define SMB2_SHARE_TYPE_PIPE 0x02
|
||||
#define SMB2_SHARE_TYPE_PRINT 0x03
|
||||
|
||||
/*
|
||||
* Possible ShareFlags - exactly one and only one of the first 4 caching flags
|
||||
* must be set (any of the remaining, SHI1005, flags may be set individually
|
||||
* or in combination.
|
||||
*/
|
||||
#define SMB2_SHAREFLAG_MANUAL_CACHING 0x00000000
|
||||
#define SMB2_SHAREFLAG_AUTO_CACHING 0x00000010
|
||||
#define SMB2_SHAREFLAG_VDO_CACHING 0x00000020
|
||||
#define SMB2_SHAREFLAG_NO_CACHING 0x00000030
|
||||
#define SHI1005_FLAGS_DFS 0x00000001
|
||||
#define SHI1005_FLAGS_DFS_ROOT 0x00000002
|
||||
#define SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS 0x00000100
|
||||
#define SHI1005_FLAGS_FORCE_SHARED_DELETE 0x00000200
|
||||
#define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x00000400
|
||||
#define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x00000800
|
||||
#define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK 0x00001000
|
||||
#define SHI1005_FLAGS_ENABLE_HASH 0x00002000
|
||||
|
||||
/* Possible share capabilities */
|
||||
#define SMB2_SHARE_CAP_DFS cpu_to_le32(0x00000008)
|
||||
|
||||
struct smb2_tree_disconnect_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_tree_disconnect_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 4 */
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
||||
#define ATTR_READONLY_LE cpu_to_le32(ATTR_READONLY)
|
||||
#define ATTR_HIDDEN_LE cpu_to_le32(ATTR_HIDDEN)
|
||||
#define ATTR_SYSTEM_LE cpu_to_le32(ATTR_SYSTEM)
|
||||
#define ATTR_DIRECTORY_LE cpu_to_le32(ATTR_DIRECTORY)
|
||||
#define ATTR_ARCHIVE_LE cpu_to_le32(ATTR_ARCHIVE)
|
||||
#define ATTR_NORMAL_LE cpu_to_le32(ATTR_NORMAL)
|
||||
#define ATTR_TEMPORARY_LE cpu_to_le32(ATTR_TEMPORARY)
|
||||
#define ATTR_SPARSE_FILE_LE cpu_to_le32(ATTR_SPARSE)
|
||||
#define ATTR_REPARSE_POINT_LE cpu_to_le32(ATTR_REPARSE)
|
||||
#define ATTR_COMPRESSED_LE cpu_to_le32(ATTR_COMPRESSED)
|
||||
#define ATTR_OFFLINE_LE cpu_to_le32(ATTR_OFFLINE)
|
||||
#define ATTR_NOT_CONTENT_INDEXED_LE cpu_to_le32(ATTR_NOT_CONTENT_INDEXED)
|
||||
#define ATTR_ENCRYPTED_LE cpu_to_le32(ATTR_ENCRYPTED)
|
||||
#define ATTR_INTEGRITY_STREAML_LE cpu_to_le32(0x00008000)
|
||||
#define ATTR_NO_SCRUB_DATA_LE cpu_to_le32(0x00020000)
|
||||
#define ATTR_MASK_LE cpu_to_le32(0x00007FB7)
|
||||
|
||||
/* Oplock levels */
|
||||
#define SMB2_OPLOCK_LEVEL_NONE 0x00
|
||||
#define SMB2_OPLOCK_LEVEL_II 0x01
|
||||
#define SMB2_OPLOCK_LEVEL_EXCLUSIVE 0x08
|
||||
#define SMB2_OPLOCK_LEVEL_BATCH 0x09
|
||||
#define SMB2_OPLOCK_LEVEL_LEASE 0xFF
|
||||
/* Non-spec internal type */
|
||||
#define SMB2_OPLOCK_LEVEL_NOCHANGE 0x99
|
||||
|
||||
/* Desired Access Flags */
|
||||
#define FILE_READ_DATA_LE cpu_to_le32(0x00000001)
|
||||
#define FILE_LIST_DIRECTORY_LE cpu_to_le32(0x00000001)
|
||||
#define FILE_WRITE_DATA_LE cpu_to_le32(0x00000002)
|
||||
#define FILE_ADD_FILE_LE cpu_to_le32(0x00000002)
|
||||
#define FILE_APPEND_DATA_LE cpu_to_le32(0x00000004)
|
||||
#define FILE_ADD_SUBDIRECTORY_LE cpu_to_le32(0x00000004)
|
||||
#define FILE_READ_EA_LE cpu_to_le32(0x00000008)
|
||||
#define FILE_WRITE_EA_LE cpu_to_le32(0x00000010)
|
||||
#define FILE_EXECUTE_LE cpu_to_le32(0x00000020)
|
||||
#define FILE_TRAVERSE_LE cpu_to_le32(0x00000020)
|
||||
#define FILE_DELETE_CHILD_LE cpu_to_le32(0x00000040)
|
||||
#define FILE_READ_ATTRIBUTES_LE cpu_to_le32(0x00000080)
|
||||
#define FILE_WRITE_ATTRIBUTES_LE cpu_to_le32(0x00000100)
|
||||
#define FILE_DELETE_LE cpu_to_le32(0x00010000)
|
||||
#define FILE_READ_CONTROL_LE cpu_to_le32(0x00020000)
|
||||
#define FILE_WRITE_DAC_LE cpu_to_le32(0x00040000)
|
||||
#define FILE_WRITE_OWNER_LE cpu_to_le32(0x00080000)
|
||||
#define FILE_SYNCHRONIZE_LE cpu_to_le32(0x00100000)
|
||||
#define FILE_ACCESS_SYSTEM_SECURITY_LE cpu_to_le32(0x01000000)
|
||||
#define FILE_MAXIMAL_ACCESS_LE cpu_to_le32(0x02000000)
|
||||
#define FILE_GENERIC_ALL_LE cpu_to_le32(0x10000000)
|
||||
#define FILE_GENERIC_EXECUTE_LE cpu_to_le32(0x20000000)
|
||||
#define FILE_GENERIC_WRITE_LE cpu_to_le32(0x40000000)
|
||||
#define FILE_GENERIC_READ_LE cpu_to_le32(0x80000000)
|
||||
#define DESIRED_ACCESS_MASK cpu_to_le32(0xF21F01FF)
|
||||
|
||||
/* ShareAccess Flags */
|
||||
#define FILE_SHARE_READ_LE cpu_to_le32(0x00000001)
|
||||
#define FILE_SHARE_WRITE_LE cpu_to_le32(0x00000002)
|
||||
#define FILE_SHARE_DELETE_LE cpu_to_le32(0x00000004)
|
||||
#define FILE_SHARE_ALL_LE cpu_to_le32(0x00000007)
|
||||
|
||||
/* CreateDisposition Flags */
|
||||
#define FILE_SUPERSEDE_LE cpu_to_le32(0x00000000)
|
||||
#define FILE_OPEN_LE cpu_to_le32(0x00000001)
|
||||
#define FILE_CREATE_LE cpu_to_le32(0x00000002)
|
||||
#define FILE_OPEN_IF_LE cpu_to_le32(0x00000003)
|
||||
#define FILE_OVERWRITE_LE cpu_to_le32(0x00000004)
|
||||
#define FILE_OVERWRITE_IF_LE cpu_to_le32(0x00000005)
|
||||
#define FILE_CREATE_MASK_LE cpu_to_le32(0x00000007)
|
||||
|
||||
#define FILE_READ_DESIRED_ACCESS_LE (FILE_READ_DATA_LE | \
|
||||
FILE_READ_EA_LE | \
|
||||
FILE_GENERIC_READ_LE)
|
||||
#define FILE_WRITE_DESIRE_ACCESS_LE (FILE_WRITE_DATA_LE | \
|
||||
FILE_APPEND_DATA_LE | \
|
||||
FILE_WRITE_EA_LE | \
|
||||
FILE_WRITE_ATTRIBUTES_LE | \
|
||||
FILE_GENERIC_WRITE_LE)
|
||||
|
||||
/* Impersonation Levels */
|
||||
#define IL_ANONYMOUS_LE cpu_to_le32(0x00000000)
|
||||
#define IL_IDENTIFICATION_LE cpu_to_le32(0x00000001)
|
||||
#define IL_IMPERSONATION_LE cpu_to_le32(0x00000002)
|
||||
#define IL_DELEGATE_LE cpu_to_le32(0x00000003)
|
||||
|
||||
/* Create Context Values */
|
||||
#define SMB2_CREATE_EA_BUFFER "ExtA" /* extended attributes */
|
||||
#define SMB2_CREATE_SD_BUFFER "SecD" /* security descriptor */
|
||||
#define SMB2_CREATE_DURABLE_HANDLE_REQUEST "DHnQ"
|
||||
#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT "DHnC"
|
||||
#define SMB2_CREATE_ALLOCATION_SIZE "AlSi"
|
||||
#define SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQUEST "MxAc"
|
||||
#define SMB2_CREATE_TIMEWARP_REQUEST "TWrp"
|
||||
#define SMB2_CREATE_QUERY_ON_DISK_ID "QFid"
|
||||
#define SMB2_CREATE_REQUEST_LEASE "RqLs"
|
||||
#define SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 "DH2Q"
|
||||
#define SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 "DH2C"
|
||||
#define SMB2_CREATE_APP_INSTANCE_ID "\x45\xBC\xA6\x6A\xEF\xA7\xF7\x4A\x90\x08\xFA\x46\x2E\x14\x4D\x74"
|
||||
#define SMB2_CREATE_APP_INSTANCE_VERSION "\xB9\x82\xD0\xB7\x3B\x56\x07\x4F\xA0\x7B\x52\x4A\x81\x16\xA0\x10"
|
||||
#define SVHDX_OPEN_DEVICE_CONTEXT 0x83CE6F1AD851E0986E34401CC9BCFCE9
|
||||
#define SMB2_CREATE_TAG_POSIX "\x93\xAD\x25\x50\x9C\xB4\x11\xE7\xB4\x23\x83\xDE\x96\x8B\xCD\x7C"
|
||||
|
||||
struct smb2_create_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 57 */
|
||||
__u8 SecurityFlags;
|
||||
__u8 RequestedOplockLevel;
|
||||
__le32 ImpersonationLevel;
|
||||
__le64 SmbCreateFlags;
|
||||
__le64 Reserved;
|
||||
__le32 DesiredAccess;
|
||||
__le32 FileAttributes;
|
||||
__le32 ShareAccess;
|
||||
__le32 CreateDisposition;
|
||||
__le32 CreateOptions;
|
||||
__le16 NameOffset;
|
||||
__le16 NameLength;
|
||||
__le32 CreateContextsOffset;
|
||||
__le32 CreateContextsLength;
|
||||
__u8 Buffer[0];
|
||||
} __packed;
|
||||
|
||||
struct smb2_create_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 89 */
|
||||
__u8 OplockLevel;
|
||||
__u8 Reserved;
|
||||
__le32 CreateAction;
|
||||
__le64 CreationTime;
|
||||
__le64 LastAccessTime;
|
||||
__le64 LastWriteTime;
|
||||
__le64 ChangeTime;
|
||||
__le64 AllocationSize;
|
||||
__le64 EndofFile;
|
||||
__le32 FileAttributes;
|
||||
__le32 Reserved2;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__le32 CreateContextsOffset;
|
||||
__le32 CreateContextsLength;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
struct create_context {
|
||||
__le32 Next;
|
||||
__le16 NameOffset;
|
||||
__le16 NameLength;
|
||||
__le16 Reserved;
|
||||
__le16 DataOffset;
|
||||
__le32 DataLength;
|
||||
__u8 Buffer[0];
|
||||
} __packed;
|
||||
|
||||
struct create_durable_req_v2 {
|
||||
struct create_context ccontext;
|
||||
__u8 Name[8];
|
||||
@@ -743,22 +216,21 @@ struct create_posix_rsp {
|
||||
|
||||
#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE cpu_to_le32(0x02)
|
||||
|
||||
#define SMB2_LEASE_KEY_SIZE 16
|
||||
|
||||
struct lease_context {
|
||||
__le64 LeaseKeyLow;
|
||||
__le64 LeaseKeyHigh;
|
||||
__u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 LeaseState;
|
||||
__le32 LeaseFlags;
|
||||
__le64 LeaseDuration;
|
||||
} __packed;
|
||||
|
||||
struct lease_context_v2 {
|
||||
__le64 LeaseKeyLow;
|
||||
__le64 LeaseKeyHigh;
|
||||
__u8 LeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le32 LeaseState;
|
||||
__le32 LeaseFlags;
|
||||
__le64 LeaseDuration;
|
||||
__le64 ParentLeaseKeyLow;
|
||||
__le64 ParentLeaseKeyHigh;
|
||||
__u8 ParentLeaseKey[SMB2_LEASE_KEY_SIZE];
|
||||
__le16 Epoch;
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
@@ -776,114 +248,12 @@ struct create_lease_v2 {
|
||||
__u8 Pad[4];
|
||||
} __packed;
|
||||
|
||||
/* Currently defined values for close flags */
|
||||
#define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB cpu_to_le16(0x0001)
|
||||
struct smb2_close_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 24 */
|
||||
__le16 Flags;
|
||||
__le32 Reserved;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
} __packed;
|
||||
|
||||
struct smb2_close_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* 60 */
|
||||
__le16 Flags;
|
||||
__le32 Reserved;
|
||||
__le64 CreationTime;
|
||||
__le64 LastAccessTime;
|
||||
__le64 LastWriteTime;
|
||||
__le64 ChangeTime;
|
||||
__le64 AllocationSize; /* Beginning of FILE_STANDARD_INFO equivalent */
|
||||
__le64 EndOfFile;
|
||||
__le32 Attributes;
|
||||
} __packed;
|
||||
|
||||
struct smb2_flush_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 24 */
|
||||
__le16 Reserved1;
|
||||
__le32 Reserved2;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
} __packed;
|
||||
|
||||
struct smb2_flush_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize;
|
||||
__le16 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_buffer_desc_v1 {
|
||||
__le64 offset;
|
||||
__le32 token;
|
||||
__le32 length;
|
||||
} __packed;
|
||||
|
||||
#define SMB2_CHANNEL_NONE cpu_to_le32(0x00000000)
|
||||
#define SMB2_CHANNEL_RDMA_V1 cpu_to_le32(0x00000001)
|
||||
#define SMB2_CHANNEL_RDMA_V1_INVALIDATE cpu_to_le32(0x00000002)
|
||||
|
||||
struct smb2_read_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 49 */
|
||||
__u8 Padding; /* offset from start of SMB2 header to place read */
|
||||
__u8 Reserved;
|
||||
__le32 Length;
|
||||
__le64 Offset;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__le32 MinimumCount;
|
||||
__le32 Channel; /* Reserved MBZ */
|
||||
__le32 RemainingBytes;
|
||||
__le16 ReadChannelInfoOffset; /* Reserved MBZ */
|
||||
__le16 ReadChannelInfoLength; /* Reserved MBZ */
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
struct smb2_read_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 17 */
|
||||
__u8 DataOffset;
|
||||
__u8 Reserved;
|
||||
__le32 DataLength;
|
||||
__le32 DataRemaining;
|
||||
__u32 Reserved2;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
/* For write request Flags field below the following flag is defined: */
|
||||
#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
|
||||
|
||||
struct smb2_write_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 49 */
|
||||
__le16 DataOffset; /* offset from start of SMB2 header to write data */
|
||||
__le32 Length;
|
||||
__le64 Offset;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__le32 Channel; /* Reserved MBZ */
|
||||
__le32 RemainingBytes;
|
||||
__le16 WriteChannelInfoOffset; /* Reserved MBZ */
|
||||
__le16 WriteChannelInfoLength; /* Reserved MBZ */
|
||||
__le32 Flags;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
struct smb2_write_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 17 */
|
||||
__u8 DataOffset;
|
||||
__u8 Reserved;
|
||||
__le32 DataLength;
|
||||
__le32 DataRemaining;
|
||||
__u32 Reserved2;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
#define SMB2_0_IOCTL_IS_FSCTL 0x00000001
|
||||
|
||||
struct duplicate_extents_to_file {
|
||||
@@ -1033,43 +403,6 @@ struct reparse_data_buffer {
|
||||
__u8 DataBuffer[]; /* Variable Length */
|
||||
} __packed;
|
||||
|
||||
/* Completion Filter flags for Notify */
|
||||
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
|
||||
#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
|
||||
#define FILE_NOTIFY_CHANGE_NAME 0x00000003
|
||||
#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
|
||||
#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
|
||||
#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
|
||||
#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
|
||||
#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
|
||||
#define FILE_NOTIFY_CHANGE_EA 0x00000080
|
||||
#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
|
||||
#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
|
||||
|
||||
/* Flags */
|
||||
#define SMB2_WATCH_TREE 0x0001
|
||||
|
||||
struct smb2_notify_req {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 32 */
|
||||
__le16 Flags;
|
||||
__le32 OutputBufferLength;
|
||||
__le64 PersistentFileId;
|
||||
__le64 VolatileFileId;
|
||||
__u32 CompletionFileter;
|
||||
__u32 Reserved;
|
||||
} __packed;
|
||||
|
||||
struct smb2_notify_rsp {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize; /* Must be 9 */
|
||||
__le16 OutputBufferOffset;
|
||||
__le32 OutputBufferLength;
|
||||
__u8 Buffer[1];
|
||||
} __packed;
|
||||
|
||||
/* SMB2 Notify Action Flags */
|
||||
#define FILE_ACTION_ADDED 0x00000001
|
||||
#define FILE_ACTION_REMOVED 0x00000002
|
||||
@@ -1528,7 +861,7 @@ struct smb2_file_pos_info {
|
||||
__le64 CurrentByteOffset;
|
||||
} __packed;
|
||||
|
||||
#define FILE_MODE_INFO_MASK cpu_to_le32(0x0000103e)
|
||||
#define FILE_MODE_INFO_MASK cpu_to_le32(0x0000100e)
|
||||
|
||||
struct smb2_file_mode_info {
|
||||
__le32 Mode;
|
||||
@@ -1705,4 +1038,13 @@ int smb2_ioctl(struct ksmbd_work *work);
|
||||
int smb2_oplock_break(struct ksmbd_work *work);
|
||||
int smb2_notify(struct ksmbd_work *ksmbd_work);
|
||||
|
||||
/*
|
||||
* Get the body of the smb2 message excluding the 4 byte rfc1002 headers
|
||||
* from request/response buffer.
|
||||
*/
|
||||
static inline void *smb2_get_msg(void *buf)
|
||||
{
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
#endif /* _SMB2PDU_H */
|
||||
|
||||
@@ -132,7 +132,7 @@ int ksmbd_lookup_protocol_idx(char *str)
|
||||
*/
|
||||
int ksmbd_verify_smb_message(struct ksmbd_work *work)
|
||||
{
|
||||
struct smb2_hdr *smb2_hdr = work->request_buf + work->next_smb2_rcv_hdr_off;
|
||||
struct smb2_hdr *smb2_hdr = ksmbd_req_buf_next(work);
|
||||
struct smb_hdr *hdr;
|
||||
|
||||
if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER)
|
||||
@@ -239,14 +239,14 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
|
||||
static int ksmbd_negotiate_smb_dialect(void *buf)
|
||||
{
|
||||
int smb_buf_length = get_rfc1002_len(buf);
|
||||
__le32 proto = ((struct smb2_hdr *)buf)->ProtocolId;
|
||||
__le32 proto = ((struct smb2_hdr *)smb2_get_msg(buf))->ProtocolId;
|
||||
|
||||
if (proto == SMB2_PROTO_NUMBER) {
|
||||
struct smb2_negotiate_req *req;
|
||||
int smb2_neg_size =
|
||||
offsetof(struct smb2_negotiate_req, Dialects) - 4;
|
||||
offsetof(struct smb2_negotiate_req, Dialects);
|
||||
|
||||
req = (struct smb2_negotiate_req *)buf;
|
||||
req = (struct smb2_negotiate_req *)smb2_get_msg(buf);
|
||||
if (smb2_neg_size > smb_buf_length)
|
||||
goto err_out;
|
||||
|
||||
@@ -445,11 +445,12 @@ int ksmbd_smb_negotiate_common(struct ksmbd_work *work, unsigned int command)
|
||||
struct ksmbd_conn *conn = work->conn;
|
||||
int ret;
|
||||
|
||||
conn->dialect = ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
conn->dialect =
|
||||
ksmbd_negotiate_smb_dialect(work->request_buf);
|
||||
ksmbd_debug(SMB, "conn->dialect 0x%x\n", conn->dialect);
|
||||
|
||||
if (command == SMB2_NEGOTIATE_HE) {
|
||||
struct smb2_hdr *smb2_hdr = work->request_buf;
|
||||
struct smb2_hdr *smb2_hdr = smb2_get_msg(work->request_buf);
|
||||
|
||||
if (smb2_hdr->ProtocolId != SMB2_PROTO_NUMBER) {
|
||||
ksmbd_debug(SMB, "Downgrade to SMB1 negotiation\n");
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "glob.h"
|
||||
#include "nterr.h"
|
||||
#include "../smbfs_common/smb2pdu.h"
|
||||
#include "smb2pdu.h"
|
||||
|
||||
/* ksmbd's Specific ERRNO */
|
||||
@@ -32,17 +33,6 @@
|
||||
#define SMB302_VERSION_STRING "3.02"
|
||||
#define SMB311_VERSION_STRING "3.1.1"
|
||||
|
||||
/* Dialects */
|
||||
#define SMB10_PROT_ID 0x00
|
||||
#define SMB20_PROT_ID 0x0202
|
||||
#define SMB21_PROT_ID 0x0210
|
||||
/* multi-protocol negotiate request */
|
||||
#define SMB2X_PROT_ID 0x02FF
|
||||
#define SMB30_PROT_ID 0x0300
|
||||
#define SMB302_PROT_ID 0x0302
|
||||
#define SMB311_PROT_ID 0x0311
|
||||
#define BAD_PROT_ID 0xFFFF
|
||||
|
||||
#define SMB_ECHO_INTERVAL (60 * HZ)
|
||||
|
||||
#define CIFS_DEFAULT_IOSIZE (64 * 1024)
|
||||
@@ -59,21 +49,6 @@
|
||||
/*
|
||||
* File Attribute flags
|
||||
*/
|
||||
#define ATTR_READONLY 0x0001
|
||||
#define ATTR_HIDDEN 0x0002
|
||||
#define ATTR_SYSTEM 0x0004
|
||||
#define ATTR_VOLUME 0x0008
|
||||
#define ATTR_DIRECTORY 0x0010
|
||||
#define ATTR_ARCHIVE 0x0020
|
||||
#define ATTR_DEVICE 0x0040
|
||||
#define ATTR_NORMAL 0x0080
|
||||
#define ATTR_TEMPORARY 0x0100
|
||||
#define ATTR_SPARSE 0x0200
|
||||
#define ATTR_REPARSE 0x0400
|
||||
#define ATTR_COMPRESSED 0x0800
|
||||
#define ATTR_OFFLINE 0x1000
|
||||
#define ATTR_NOT_CONTENT_INDEXED 0x2000
|
||||
#define ATTR_ENCRYPTED 0x4000
|
||||
#define ATTR_POSIX_SEMANTICS 0x01000000
|
||||
#define ATTR_BACKUP_SEMANTICS 0x02000000
|
||||
#define ATTR_DELETE_ON_CLOSE 0x04000000
|
||||
@@ -82,23 +57,6 @@
|
||||
#define ATTR_NO_BUFFERING 0x20000000
|
||||
#define ATTR_WRITE_THROUGH 0x80000000
|
||||
|
||||
#define ATTR_READONLY_LE cpu_to_le32(ATTR_READONLY)
|
||||
#define ATTR_HIDDEN_LE cpu_to_le32(ATTR_HIDDEN)
|
||||
#define ATTR_SYSTEM_LE cpu_to_le32(ATTR_SYSTEM)
|
||||
#define ATTR_DIRECTORY_LE cpu_to_le32(ATTR_DIRECTORY)
|
||||
#define ATTR_ARCHIVE_LE cpu_to_le32(ATTR_ARCHIVE)
|
||||
#define ATTR_NORMAL_LE cpu_to_le32(ATTR_NORMAL)
|
||||
#define ATTR_TEMPORARY_LE cpu_to_le32(ATTR_TEMPORARY)
|
||||
#define ATTR_SPARSE_FILE_LE cpu_to_le32(ATTR_SPARSE)
|
||||
#define ATTR_REPARSE_POINT_LE cpu_to_le32(ATTR_REPARSE)
|
||||
#define ATTR_COMPRESSED_LE cpu_to_le32(ATTR_COMPRESSED)
|
||||
#define ATTR_OFFLINE_LE cpu_to_le32(ATTR_OFFLINE)
|
||||
#define ATTR_NOT_CONTENT_INDEXED_LE cpu_to_le32(ATTR_NOT_CONTENT_INDEXED)
|
||||
#define ATTR_ENCRYPTED_LE cpu_to_le32(ATTR_ENCRYPTED)
|
||||
#define ATTR_INTEGRITY_STREAML_LE cpu_to_le32(0x00008000)
|
||||
#define ATTR_NO_SCRUB_DATA_LE cpu_to_le32(0x00020000)
|
||||
#define ATTR_MASK_LE cpu_to_le32(0x00007FB7)
|
||||
|
||||
/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */
|
||||
#define FILE_SUPPORTS_SPARSE_VDL 0x10000000 /* faster nonsparse extend */
|
||||
#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 /* allow ioctl dup extents */
|
||||
@@ -160,11 +118,6 @@
|
||||
/* file_execute, file_read_attributes*/
|
||||
/* write_dac, and delete. */
|
||||
|
||||
#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES)
|
||||
#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||
| FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
|
||||
#define FILE_EXEC_RIGHTS (FILE_EXECUTE)
|
||||
|
||||
#define SET_FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA \
|
||||
| FILE_READ_ATTRIBUTES \
|
||||
| DELETE | READ_CONTROL | WRITE_DAC \
|
||||
@@ -477,12 +430,6 @@ struct smb_version_cmds {
|
||||
int (*proc)(struct ksmbd_work *swork);
|
||||
};
|
||||
|
||||
static inline size_t
|
||||
smb2_hdr_size_no_buflen(struct smb_version_values *vals)
|
||||
{
|
||||
return vals->header_size - 4;
|
||||
}
|
||||
|
||||
int ksmbd_min_protocol(void);
|
||||
int ksmbd_max_protocol(void);
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ static int smb_direct_check_recvmsg(struct smb_direct_recvmsg *recvmsg)
|
||||
struct smb_direct_data_transfer *req =
|
||||
(struct smb_direct_data_transfer *)recvmsg->packet;
|
||||
struct smb2_hdr *hdr = (struct smb2_hdr *)(recvmsg->packet
|
||||
+ le32_to_cpu(req->data_offset) - 4);
|
||||
+ le32_to_cpu(req->data_offset));
|
||||
ksmbd_debug(RDMA,
|
||||
"CreditGranted: %u, CreditRequested: %u, DataLength: %u, RemainingDataLength: %u, SMB: %x, Command: %u\n",
|
||||
le16_to_cpu(req->credits_granted),
|
||||
@@ -2043,7 +2043,6 @@ int ksmbd_rdma_destroy(void)
|
||||
smb_direct_listener.cm_id = NULL;
|
||||
|
||||
if (smb_direct_wq) {
|
||||
flush_workqueue(smb_direct_wq);
|
||||
destroy_workqueue(smb_direct_wq);
|
||||
smb_direct_wq = NULL;
|
||||
}
|
||||
|
||||
@@ -1013,7 +1013,7 @@ int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,
|
||||
loff_t off, loff_t len)
|
||||
{
|
||||
smb_break_all_levII_oplock(work, fp, 1);
|
||||
if (fp->f_ci->m_fattr & ATTR_SPARSE_FILE_LE)
|
||||
if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE)
|
||||
return vfs_fallocate(fp->filp,
|
||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||
off, len);
|
||||
@@ -1624,7 +1624,7 @@ void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat)
|
||||
time = ksmbd_UnixTimeToNT(kstat->ctime);
|
||||
info->ChangeTime = cpu_to_le64(time);
|
||||
|
||||
if (ksmbd_kstat->file_attributes & ATTR_DIRECTORY_LE) {
|
||||
if (ksmbd_kstat->file_attributes & FILE_ATTRIBUTE_DIRECTORY_LE) {
|
||||
info->EndOfFile = 0;
|
||||
info->AllocationSize = 0;
|
||||
} else {
|
||||
@@ -1654,9 +1654,9 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
|
||||
* or that acl is disable in server's filesystem and the config is yes.
|
||||
*/
|
||||
if (S_ISDIR(ksmbd_kstat->kstat->mode))
|
||||
ksmbd_kstat->file_attributes = ATTR_DIRECTORY_LE;
|
||||
ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_DIRECTORY_LE;
|
||||
else
|
||||
ksmbd_kstat->file_attributes = ATTR_ARCHIVE_LE;
|
||||
ksmbd_kstat->file_attributes = FILE_ATTRIBUTE_ARCHIVE_LE;
|
||||
|
||||
if (test_share_config_flag(work->tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {
|
||||
|
||||
@@ -25,48 +25,9 @@ enum {
|
||||
};
|
||||
|
||||
/* CreateOptions */
|
||||
/* Flag is set, it must not be a file , valid for directory only */
|
||||
#define FILE_DIRECTORY_FILE_LE cpu_to_le32(0x00000001)
|
||||
#define FILE_WRITE_THROUGH_LE cpu_to_le32(0x00000002)
|
||||
#define FILE_SEQUENTIAL_ONLY_LE cpu_to_le32(0x00000004)
|
||||
|
||||
/* Should not buffer on server*/
|
||||
#define FILE_NO_INTERMEDIATE_BUFFERING_LE cpu_to_le32(0x00000008)
|
||||
/* MBZ */
|
||||
#define FILE_SYNCHRONOUS_IO_ALERT_LE cpu_to_le32(0x00000010)
|
||||
/* MBZ */
|
||||
#define FILE_SYNCHRONOUS_IO_NONALERT_LE cpu_to_le32(0x00000020)
|
||||
|
||||
/* Flaf must not be set for directory */
|
||||
#define FILE_NON_DIRECTORY_FILE_LE cpu_to_le32(0x00000040)
|
||||
|
||||
/* Should be zero */
|
||||
#define CREATE_TREE_CONNECTION cpu_to_le32(0x00000080)
|
||||
#define FILE_COMPLETE_IF_OPLOCKED_LE cpu_to_le32(0x00000100)
|
||||
#define FILE_NO_EA_KNOWLEDGE_LE cpu_to_le32(0x00000200)
|
||||
#define FILE_OPEN_REMOTE_INSTANCE cpu_to_le32(0x00000400)
|
||||
|
||||
/**
|
||||
* Doc says this is obsolete "open for recovery" flag should be zero
|
||||
* in any case.
|
||||
*/
|
||||
#define CREATE_OPEN_FOR_RECOVERY cpu_to_le32(0x00000400)
|
||||
#define FILE_RANDOM_ACCESS_LE cpu_to_le32(0x00000800)
|
||||
#define FILE_DELETE_ON_CLOSE_LE cpu_to_le32(0x00001000)
|
||||
#define FILE_OPEN_BY_FILE_ID_LE cpu_to_le32(0x00002000)
|
||||
#define FILE_OPEN_FOR_BACKUP_INTENT_LE cpu_to_le32(0x00004000)
|
||||
#define FILE_NO_COMPRESSION_LE cpu_to_le32(0x00008000)
|
||||
|
||||
/* Should be zero*/
|
||||
#define FILE_OPEN_REQUIRING_OPLOCK cpu_to_le32(0x00010000)
|
||||
#define FILE_DISALLOW_EXCLUSIVE cpu_to_le32(0x00020000)
|
||||
#define FILE_RESERVE_OPFILTER_LE cpu_to_le32(0x00100000)
|
||||
#define FILE_OPEN_REPARSE_POINT_LE cpu_to_le32(0x00200000)
|
||||
#define FILE_OPEN_NO_RECALL_LE cpu_to_le32(0x00400000)
|
||||
|
||||
/* Should be zero */
|
||||
#define FILE_OPEN_FOR_FREE_SPACE_QUERY_LE cpu_to_le32(0x00800000)
|
||||
#define CREATE_OPTIONS_MASK cpu_to_le32(0x00FFFFFF)
|
||||
#define CREATE_OPTION_READONLY 0x10000000
|
||||
/* system. NB not sent over wire */
|
||||
#define CREATE_OPTION_SPECIAL 0x20000000
|
||||
|
||||
@@ -205,9 +205,9 @@ static inline dev_t disk_devt(struct gendisk *disk)
|
||||
void disk_uevent(struct gendisk *disk, enum kobject_action action);
|
||||
|
||||
/* block/genhd.c */
|
||||
int device_add_disk(struct device *parent, struct gendisk *disk,
|
||||
const struct attribute_group **groups);
|
||||
static inline int add_disk(struct gendisk *disk)
|
||||
int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
|
||||
const struct attribute_group **groups);
|
||||
static inline int __must_check add_disk(struct gendisk *disk)
|
||||
{
|
||||
return device_add_disk(NULL, disk, NULL);
|
||||
}
|
||||
|
||||
@@ -68,9 +68,10 @@
|
||||
* explicitly triggered (VIRTIO_MEM_REQ_UNPLUG).
|
||||
*
|
||||
* There are no guarantees what will happen if unplugged memory is
|
||||
* read/written. Such memory should, in general, not be touched. E.g.,
|
||||
* even writing might succeed, but the values will simply be discarded at
|
||||
* random points in time.
|
||||
* read/written. In general, unplugged memory should not be touched, because
|
||||
* the resulting action is undefined. There is one exception: without
|
||||
* VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE, unplugged memory inside the usable
|
||||
* region can be read, to simplify creation of memory dumps.
|
||||
*
|
||||
* It can happen that the device cannot process a request, because it is
|
||||
* busy. The device driver has to retry later.
|
||||
@@ -87,6 +88,8 @@
|
||||
|
||||
/* node_id is an ACPI PXM and is valid */
|
||||
#define VIRTIO_MEM_F_ACPI_PXM 0
|
||||
/* unplugged memory must not be accessed */
|
||||
#define VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE 1
|
||||
|
||||
|
||||
/* --- virtio-mem: guest -> host requests --- */
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/page-isolation.h>
|
||||
#include <linux/pagewalk.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include "internal.h"
|
||||
#include "ras/ras_event.h"
|
||||
|
||||
@@ -868,7 +867,6 @@ static int me_pagecache_clean(struct page_state *ps, struct page *p)
|
||||
{
|
||||
int ret;
|
||||
struct address_space *mapping;
|
||||
bool extra_pins;
|
||||
|
||||
delete_from_lru_cache(p);
|
||||
|
||||
@@ -897,24 +895,18 @@ static int me_pagecache_clean(struct page_state *ps, struct page *p)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The shmem page is kept in page cache instead of truncating
|
||||
* so is expected to have an extra refcount after error-handling.
|
||||
*/
|
||||
extra_pins = shmem_mapping(mapping);
|
||||
|
||||
/*
|
||||
* Truncation is a bit tricky. Enable it per file system for now.
|
||||
*
|
||||
* Open: to take i_rwsem or not for this? Right now we don't.
|
||||
*/
|
||||
ret = truncate_error_page(p, page_to_pfn(p), mapping);
|
||||
if (has_extra_refcount(ps, p, extra_pins))
|
||||
ret = MF_FAILED;
|
||||
|
||||
out:
|
||||
unlock_page(p);
|
||||
|
||||
if (has_extra_refcount(ps, p, false))
|
||||
ret = MF_FAILED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
38
mm/shmem.c
38
mm/shmem.c
@@ -2456,7 +2456,6 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
|
||||
struct inode *inode = mapping->host;
|
||||
struct shmem_inode_info *info = SHMEM_I(inode);
|
||||
pgoff_t index = pos >> PAGE_SHIFT;
|
||||
int ret = 0;
|
||||
|
||||
/* i_rwsem is held by caller */
|
||||
if (unlikely(info->seals & (F_SEAL_GROW |
|
||||
@@ -2467,15 +2466,7 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = shmem_getpage(inode, index, pagep, SGP_WRITE);
|
||||
|
||||
if (*pagep && PageHWPoison(*pagep)) {
|
||||
unlock_page(*pagep);
|
||||
put_page(*pagep);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return shmem_getpage(inode, index, pagep, SGP_WRITE);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -2562,12 +2553,6 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
if (sgp == SGP_CACHE)
|
||||
set_page_dirty(page);
|
||||
unlock_page(page);
|
||||
|
||||
if (PageHWPoison(page)) {
|
||||
put_page(page);
|
||||
error = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3107,8 +3092,7 @@ static const char *shmem_get_link(struct dentry *dentry,
|
||||
page = find_get_page(inode->i_mapping, 0);
|
||||
if (!page)
|
||||
return ERR_PTR(-ECHILD);
|
||||
if (PageHWPoison(page) ||
|
||||
!PageUptodate(page)) {
|
||||
if (!PageUptodate(page)) {
|
||||
put_page(page);
|
||||
return ERR_PTR(-ECHILD);
|
||||
}
|
||||
@@ -3116,11 +3100,6 @@ static const char *shmem_get_link(struct dentry *dentry,
|
||||
error = shmem_getpage(inode, 0, &page, SGP_READ);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
if (page && PageHWPoison(page)) {
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
return ERR_PTR(-ECHILD);
|
||||
}
|
||||
unlock_page(page);
|
||||
}
|
||||
set_delayed_call(done, shmem_put_link, page);
|
||||
@@ -3771,13 +3750,6 @@ static void shmem_destroy_inodecache(void)
|
||||
kmem_cache_destroy(shmem_inode_cachep);
|
||||
}
|
||||
|
||||
/* Keep the page in page cache instead of truncating it */
|
||||
static int shmem_error_remove_page(struct address_space *mapping,
|
||||
struct page *page)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct address_space_operations shmem_aops = {
|
||||
.writepage = shmem_writepage,
|
||||
.set_page_dirty = __set_page_dirty_no_writeback,
|
||||
@@ -3788,7 +3760,7 @@ const struct address_space_operations shmem_aops = {
|
||||
#ifdef CONFIG_MIGRATION
|
||||
.migratepage = migrate_page,
|
||||
#endif
|
||||
.error_remove_page = shmem_error_remove_page,
|
||||
.error_remove_page = generic_error_remove_page,
|
||||
};
|
||||
EXPORT_SYMBOL(shmem_aops);
|
||||
|
||||
@@ -4199,10 +4171,6 @@ struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
|
||||
page = ERR_PTR(error);
|
||||
else
|
||||
unlock_page(page);
|
||||
|
||||
if (PageHWPoison(page))
|
||||
page = ERR_PTR(-EIO);
|
||||
|
||||
return page;
|
||||
#else
|
||||
/*
|
||||
|
||||
@@ -232,11 +232,6 @@ static int mcontinue_atomic_pte(struct mm_struct *dst_mm,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (PageHWPoison(page)) {
|
||||
ret = -EIO;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
ret = mfill_atomic_install_pte(dst_mm, dst_pmd, dst_vma, dst_addr,
|
||||
page, false, wp_copy);
|
||||
if (ret)
|
||||
|
||||
Reference in New Issue
Block a user