[SCSI] libosd: osd_dev_info: Unique Identification of an OSD device
Define an osd_dev_info structure that Uniquely identifies an OSD device lun on the network. The identification is built from unique target attributes and is the same for all network/SAN machines. osduld_info_lookup() - NEW New API that will lookup an osd_dev by its osd_dev_info. This is used by pNFS-objects for cross network global device identification. And by exofs multy-device support, the device info is specified in the on-disk exofs device table. osduld_device_info() - NEW Given an osd_dev handle returns its associated osd_dev_info. The ULD fetches this information at startup and hangs it on each OSD device. (This is a fast operation that can be called at any condition) osduld_device_same() - NEW With a given osd_dev at one hand and an osd_dev_info at another, we would like to know if they are the same device. Two osd_dev handles can be checked by: osduld_device_same(od1, osduld_device_info(od2)); osd_auto_detect_ver() - REVISED Now returns an osd_dev_info structure. Is only called once by ULD as before. See added comments for how to use. Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
Родитель
d6ae4333e6
Коммит
2cdd6410e5
|
@ -73,7 +73,8 @@ static const char *_osd_ver_desc(struct osd_request *or)
|
|||
|
||||
#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len)
|
||||
|
||||
static int _osd_print_system_info(struct osd_dev *od, void *caps)
|
||||
static int _osd_get_print_system_info(struct osd_dev *od,
|
||||
void *caps, struct osd_dev_info *odi)
|
||||
{
|
||||
struct osd_request *or;
|
||||
struct osd_attr get_attrs[] = {
|
||||
|
@ -137,8 +138,12 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
|
|||
OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n",
|
||||
(char *)pFirst);
|
||||
|
||||
pFirst = get_attrs[a].val_ptr;
|
||||
OSD_INFO("OSD_NAME [%s]\n", (char *)pFirst);
|
||||
odi->osdname_len = get_attrs[a].len;
|
||||
/* Avoid NULL for memcmp optimization 0-length is good enough */
|
||||
odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL);
|
||||
if (odi->osdname_len)
|
||||
memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len);
|
||||
OSD_INFO("OSD_NAME [%s]\n", odi->osdname);
|
||||
a++;
|
||||
|
||||
pFirst = get_attrs[a++].val_ptr;
|
||||
|
@ -171,6 +176,14 @@ static int _osd_print_system_info(struct osd_dev *od, void *caps)
|
|||
sid_dump, sizeof(sid_dump), true);
|
||||
OSD_INFO("OSD_SYSTEM_ID(%d)\n"
|
||||
" [%s]\n", len, sid_dump);
|
||||
|
||||
if (unlikely(len > sizeof(odi->systemid))) {
|
||||
OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). "
|
||||
"device idetification might not work\n", len);
|
||||
len = sizeof(odi->systemid);
|
||||
}
|
||||
odi->systemid_len = len;
|
||||
memcpy(odi->systemid, get_attrs[a].val_ptr, len);
|
||||
a++;
|
||||
}
|
||||
out:
|
||||
|
@ -178,16 +191,17 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int osd_auto_detect_ver(struct osd_dev *od, void *caps)
|
||||
int osd_auto_detect_ver(struct osd_dev *od,
|
||||
void *caps, struct osd_dev_info *odi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Auto-detect the osd version */
|
||||
ret = _osd_print_system_info(od, caps);
|
||||
ret = _osd_get_print_system_info(od, caps, odi);
|
||||
if (ret) {
|
||||
osd_dev_set_ver(od, OSD_VER1);
|
||||
OSD_DEBUG("converting to OSD1\n");
|
||||
ret = _osd_print_system_info(od, caps);
|
||||
ret = _osd_get_print_system_info(od, caps, odi);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -84,6 +84,7 @@ struct osd_uld_device {
|
|||
struct device class_dev;
|
||||
struct cdev cdev;
|
||||
struct osd_dev od;
|
||||
struct osd_dev_info odi;
|
||||
struct gendisk *disk;
|
||||
};
|
||||
|
||||
|
@ -225,6 +226,72 @@ free_od:
|
|||
}
|
||||
EXPORT_SYMBOL(osduld_path_lookup);
|
||||
|
||||
static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
|
||||
const u8 *a2, unsigned a2_len)
|
||||
{
|
||||
if (!a2_len) /* User string is Empty means don't care */
|
||||
return true;
|
||||
|
||||
if (a1_len != a2_len)
|
||||
return false;
|
||||
|
||||
return 0 == memcmp(a1, a2, a1_len);
|
||||
}
|
||||
|
||||
struct find_oud_t {
|
||||
const struct osd_dev_info *odi;
|
||||
struct device *dev;
|
||||
struct osd_uld_device *oud;
|
||||
} ;
|
||||
|
||||
int _mach_odi(struct device *dev, void *find_data)
|
||||
{
|
||||
struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
|
||||
class_dev);
|
||||
struct find_oud_t *fot = find_data;
|
||||
const struct osd_dev_info *odi = fot->odi;
|
||||
|
||||
if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
|
||||
odi->systemid, odi->systemid_len) &&
|
||||
_the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
|
||||
odi->osdname, odi->osdname_len)) {
|
||||
OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
|
||||
odi->systemid_len, odi->osdname_len);
|
||||
fot->oud = oud;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* osduld_info_lookup - Loop through all devices, return the requested osd_dev.
|
||||
*
|
||||
* if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't
|
||||
* care. .e.g if they're both zero /dev/osd0 is returned.
|
||||
*/
|
||||
struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
|
||||
{
|
||||
struct find_oud_t find = {.odi = odi};
|
||||
|
||||
find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
|
||||
if (likely(find.dev)) {
|
||||
struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
|
||||
|
||||
if (unlikely(!odh)) {
|
||||
put_device(find.dev);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
odh->od = find.oud->od;
|
||||
odh->oud = find.oud;
|
||||
|
||||
return &odh->od;
|
||||
}
|
||||
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_info_lookup);
|
||||
|
||||
void osduld_put_device(struct osd_dev *od)
|
||||
{
|
||||
if (od && !IS_ERR(od)) {
|
||||
|
@ -240,14 +307,39 @@ void osduld_put_device(struct osd_dev *od)
|
|||
* is called after the fops->release. A get_/put_ pair makes
|
||||
* sure we have a cdev for the duration of fput
|
||||
*/
|
||||
get_device(&oud->class_dev);
|
||||
fput(odh->file);
|
||||
if (odh->file) {
|
||||
get_device(&oud->class_dev);
|
||||
fput(odh->file);
|
||||
}
|
||||
put_device(&oud->class_dev);
|
||||
kfree(odh);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_put_device);
|
||||
|
||||
const struct osd_dev_info *osduld_device_info(struct osd_dev *od)
|
||||
{
|
||||
struct osd_dev_handle *odh =
|
||||
container_of(od, struct osd_dev_handle, od);
|
||||
return &odh->oud->odi;
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_device_info);
|
||||
|
||||
bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi)
|
||||
{
|
||||
struct osd_dev_handle *odh =
|
||||
container_of(od, struct osd_dev_handle, od);
|
||||
struct osd_uld_device *oud = odh->oud;
|
||||
|
||||
return (oud->odi.systemid_len == odi->systemid_len) &&
|
||||
_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
|
||||
odi->systemid, odi->systemid_len) &&
|
||||
(oud->odi.osdname_len == odi->osdname_len) &&
|
||||
_the_same_or_null(oud->odi.osdname, oud->odi.osdname_len,
|
||||
odi->osdname, odi->osdname_len);
|
||||
}
|
||||
EXPORT_SYMBOL(osduld_device_same);
|
||||
|
||||
/*
|
||||
* Scsi Device operations
|
||||
*/
|
||||
|
@ -268,7 +360,7 @@ static int __detect_osd(struct osd_uld_device *oud)
|
|||
OSD_ERR("warning: scsi_test_unit_ready failed\n");
|
||||
|
||||
osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true);
|
||||
if (osd_auto_detect_ver(&oud->od, caps))
|
||||
if (osd_auto_detect_ver(&oud->od, caps, &oud->odi))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
|
@ -280,6 +372,8 @@ static void __remove(struct device *dev)
|
|||
class_dev);
|
||||
struct scsi_device *scsi_device = oud->od.scsi_device;
|
||||
|
||||
kfree(oud->odi.osdname);
|
||||
|
||||
if (oud->cdev.owner)
|
||||
cdev_del(&oud->cdev);
|
||||
|
||||
|
|
|
@ -55,10 +55,24 @@ struct osd_dev {
|
|||
#endif
|
||||
};
|
||||
|
||||
/* Retrieve/return osd_dev(s) for use by Kernel clients */
|
||||
struct osd_dev *osduld_path_lookup(const char *dev_name); /*Use IS_ERR/ERR_PTR*/
|
||||
/* Unique Identification of an OSD device */
|
||||
struct osd_dev_info {
|
||||
unsigned systemid_len;
|
||||
u8 systemid[OSD_SYSTEMID_LEN];
|
||||
unsigned osdname_len;
|
||||
u8 *osdname;
|
||||
};
|
||||
|
||||
/* Retrieve/return osd_dev(s) for use by Kernel clients
|
||||
* Use IS_ERR/ERR_PTR on returned "osd_dev *".
|
||||
*/
|
||||
struct osd_dev *osduld_path_lookup(const char *dev_name);
|
||||
struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi);
|
||||
void osduld_put_device(struct osd_dev *od);
|
||||
|
||||
const struct osd_dev_info *osduld_device_info(struct osd_dev *od);
|
||||
bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi);
|
||||
|
||||
/* Add/remove test ioctls from external modules */
|
||||
typedef int (do_test_fn)(struct osd_dev *od, unsigned cmd, unsigned long arg);
|
||||
int osduld_register_test(unsigned ioctl, do_test_fn *do_test);
|
||||
|
@ -68,8 +82,24 @@ void osduld_unregister_test(unsigned ioctl);
|
|||
void osd_dev_init(struct osd_dev *od, struct scsi_device *scsi_device);
|
||||
void osd_dev_fini(struct osd_dev *od);
|
||||
|
||||
/* some hi level device operations */
|
||||
int osd_auto_detect_ver(struct osd_dev *od, void *caps); /* GFP_KERNEL */
|
||||
/**
|
||||
* osd_auto_detect_ver - Detect the OSD version, return Unique Identification
|
||||
*
|
||||
* @od: OSD target lun handle
|
||||
* @caps: Capabilities authorizing OSD root read attributes access
|
||||
* @odi: Retrieved information uniquely identifying the osd target lun
|
||||
* Note: odi->osdname must be kfreed by caller.
|
||||
*
|
||||
* Auto detects the OSD version of the OSD target and sets the @od
|
||||
* accordingly. Meanwhile also returns the "system id" and "osd name" root
|
||||
* attributes which uniquely identify the OSD target. This member is usually
|
||||
* called by the ULD. ULD users should call osduld_device_info().
|
||||
* This rutine allocates osd requests and memory at GFP_KERNEL level and might
|
||||
* sleep.
|
||||
*/
|
||||
int osd_auto_detect_ver(struct osd_dev *od,
|
||||
void *caps, struct osd_dev_info *odi);
|
||||
|
||||
static inline struct request_queue *osd_request_queue(struct osd_dev *od)
|
||||
{
|
||||
return od->scsi_device->request_queue;
|
||||
|
|
Загрузка…
Ссылка в новой задаче