Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NDCTL Library crashes in ndctl_unref() #280

Open
satyam1990 opened this issue Feb 27, 2025 · 0 comments
Open

NDCTL Library crashes in ndctl_unref() #280

satyam1990 opened this issue Feb 27, 2025 · 0 comments

Comments

@satyam1990
Copy link

satyam1990 commented Feb 27, 2025

Below is sample usage how we are using the ndctl library:

// globals
struct ndctl_ctx* ndCtx;
struct daxctl_ctx* daxCtx;

void ndctl_Init(void)
{
    if (ndctl_new(&ndCtx) != 0){
        exit(-1);
    }
	
    if (daxctl_new(&daxCtx) != 0){
        exit(-1);
    }
	
	printf("ndctl Init Success");
}


void ndctl_Destroy()
{
    if (ndCtx){
        ndctl_unref(ndCtx);    
    }
}

/*
 * Function Name: ndctl_GetBlockDevice
 *
 * Function Description:
 * This function returns the block device name corresponding to namespace.
 *
 */
const char* ndctl_GetBlockDevice(struct ndctl_namespace * ndns)
{
    const char *bdev = NULL;
    struct ndctl_btt* btt = NULL;
    struct ndctl_pfn* pfn = NULL;

    btt = ndctl_namespace_get_btt(ndns);
    pfn = ndctl_namespace_get_pfn(ndns);

    if (btt) {
        bdev = ndctl_btt_get_block_device(btt);
    } else if (pfn) {
        bdev = ndctl_pfn_get_block_device(pfn);
    } else {
        bdev = ndctl_namespace_get_block_device(ndns);
    }

    return bdev;
}/*End of ndctl_GetBlockDevice*/


int ndctl_GetSectorSizeAndCapacity(struct ndctl_namespace * ndns,
                                      long long* capacity, unsigned int* sector_size) 
{
	int rc = -1;
    unsigned long long size = ULLONG_MAX;
    unsigned int log_sector_size = UINT_MAX;

    enum ndctl_namespace_mode mode;

    struct ndctl_btt* btt = NULL;
    struct ndctl_pfn* pfn = NULL;
    struct ndctl_dax* dax = NULL;

    btt = ndctl_namespace_get_btt(ndns);
    dax = ndctl_namespace_get_dax(ndns);
    pfn = ndctl_namespace_get_pfn(ndns);
    mode = ndctl_namespace_get_mode(ndns);

    // Fill in the Capacity
    switch (mode) {
	case NDCTL_NS_MODE_MEMORY:
		if (pfn) { /* dynamic memory mode */
			size = ndctl_pfn_get_size(pfn);
		} else { /* native/static memory mode */
			size = ndctl_namespace_get_size(ndns);
		}
		break;
	case NDCTL_NS_MODE_DAX:
		if (!dax) {
            MOS_ERROR(MOS_COMP_MOS, "Unable to get dax data when namespace"
                                    " mode is dax\n");
			goto out;
        }
		size = ndctl_dax_get_size(dax);
		break;
	case NDCTL_NS_MODE_SECTOR:
		if (!btt) {
            MOS_ERROR(MOS_COMP_MOS, "Unable to get btt data when namespace"
                                    " mode is sector\n");
            goto out;
        }
		size = ndctl_btt_get_size(btt);
		break;
	case NDCTL_NS_MODE_RAW:
		size = ndctl_namespace_get_size(ndns);
		break;
	default:
		fprintf(stderr, "Invalid Namespace mode, error getting"
                                " capacity data\n");
        goto out;
	}

	// fill in the capacity
    if (size < ULLONG_MAX) {
        *capacity = size;
    }

    // Fill in the Logical Sector Size
    if (btt) {
        log_sector_size = ndctl_btt_get_sector_size(btt);
    } else if (!dax) {
        log_sector_size = ndctl_namespace_get_sector_size(ndns);
        if (!log_sector_size || log_sector_size == UINT_MAX) {
            log_sector_size = 512;
        }
    }

    if (log_sector_size < UINT_MAX) {
        *sector_size = log_sector_size;
    }

    rc = 0;

out:
    return rc;

}/*End of ndctl_GetSectorSizeAndCapacity*/


/*
 * Function Name: ndctl_FindDevNamespace
 *
 * Function Description:
 * This function returns the namespace corresponding to the pmem device name.
 *
 */
struct ndctl_namespace * ndctl_FindDevNamespace(const char* device)
{
    struct ndctl_bus * bus;
    struct ndctl_region * region;
    struct ndctl_dax * dax;
    struct ndctl_namespace * namespace;

    if (strstr(device, "dax") != NULL) { /* Memory Mode PMEM */
        ndctl_bus_foreach(ndCtx, bus) {
            ndctl_region_foreach(bus, region) {
                ndctl_dax_foreach(region, dax) {
                    /* check if it the required device */
                    if (strstr(device,
                               ndctl_dax_get_devname(dax)) != NULL) {
                        return ndctl_dax_get_namespace(dax);
                    }
                }
            }
        }
    } else { /* Block Mode PMEM */
        ndctl_bus_foreach(ndCtx, bus) {
            ndctl_region_foreach(bus, region) {
                ndctl_namespace_foreach(region, namespace) {
                    const char *block_device = ndctl_GetBlockDevice(namespace);
                    if (!STR__EMPTY_OR_NULL(block_device) && // makes sure string not empty or NULL
                        strstr(device, block_device) != NULL) {
                            return namespace;
                    }
                }
            }
        }
    }

    return NULL;
}


void ndctl_GetMetadata(const char* devPath, long long* capacity, unsigned int* sector_size) {
    
    if (!ndCtx){
	fprintf(stderr, "NDCTL lib not initialized");
        return;
    }	
    namespace = ndctl_FindDevNamespace(devPath);
    if (!namespace){
        return;
    }
	
	int rc = ndctl_GetSectorSizeAndCapacity(namespace, capacity, sector_size);
    if (rc != 0) {
		fprintf(stderr, "Error: ndctl_GetSectorSizeAndCapacity failed"
            " for device: %s\n", devPath);
    }
}

// This is just sample the same function sequence can be called in parallel as well.
int main() {

ndctl_Init();

long long capacity = 0;
usigned int sector_size = 0;

ndctl_GetMetadata("/dev/pmem0", &capacity, &sector_size);

// store capacity and sector_size some other global var for later use

ndctl_Destroy();

return 0;

}

One thing I noticed in ndctl lib source is that ndctl_new() internally calls daxctl_new() and we are calling it again explicitly but nowhere being used actually so maybe that is causing some issue I will delete daxctl_new() call anyway or there is some more issues with above code, although most of the source code is copied from ndctl cmd utility code itself.

Do we need to do ndctl_ref() somewhere in above code.

NDCT Library version: ndctl-libs-71.1-7.el8.x86_64

Crash Backtrace:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f4660fb43b4 in hash_del () from /lib64/libkmod.so.2
[Current thread is 1 (Thread 0x7f467be1a080 (LWP 1685936))]
Missing separate debuginfos, use: dnf debuginfo-install cyrus-sasl-lib-2.1.27-6.el8_5.x86_64 daxctl-libs-71.1-7.el8.x86_64 glibc-2.28-251.el8.2.x86_64 keyutils-libs-1.5.10-9.el8.x86_64 kmod-libs-25-20.el8.x86_64 krb5-libs-1.18.2-27.el8.x86_64 libaio-0.3.112-1.el8.x86_64 libblkid-2.32.1-46.el8.x86_64 libcom_err-1.45.6-5.el8.x86_64 libgcc-8.5.0-22.el8.x86_64 libmount-2.32.1-46.el8.x86_64 libpmem-1.6.1-1.el8.x86_64 libselinux-2.9-8.el8.x86_64 libuuid-2.32.1-46.el8.x86_64 libxcrypt-4.1.1-6.el8.x86_64 ndctl-libs-71.1-7.el8.x86_64 numactl-libs-2.0.16-4.el8.x86_64 openldap-2.4.46-18.el8.x86_64 openssl-libs-1.1.1k-12.el8.x86_64 pcre2-10.32-3.el8.x86_64 systemd-libs-239-82.el8.1.x86_64 xz-libs-5.2.4-4.el8.x86_64
(gdb) bt
#0  0x00007f4660fb43b4 in hash_del () from /lib64/libkmod.so.2
#1  0x00007f4660faceef in kmod_module_unref () from /lib64/libkmod.so.2
#2  0x00007f466167380b in free_namespace () from /lib64/libndctl.so.6
#3  0x00007f4661677688 in free_bus () from /lib64/libndctl.so.6
#4  0x00007f4661677838 in ndctl_unref () from /lib64/libndctl.so.6
#5  0x00000000004de8f4 in ndctl_Destroy ()  

Not sure what is generating above crash any ideas where I should be looking into to fix this crash, also this happens intermittently not every time. Any area where I should focus which could help me find the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant