Skip to content

Commit 64e68f8

Browse files
committed
Merge tag 's390-6.19-3' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Alexander Gordeev: - clear 'Search boot program' flag when 'bootprog' sysfs file is written to override a value set from Hardware Management Console - fix cyclic dead-lock in zpci_zdev_put() and zpci_scan_devices() functions when triggering PCI device recovery using sysfs - annotate the expected lock context imbalance in zpci_release_device() function to fix a sparse complaint - fix the logic to fallback to the return address register value in the topmost frame when stack tracing uses a back chain * tag 's390-6.19-3' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/stacktrace: Do not fallback to RA register s390/pci: Annotate lock context imbalance in zpci_release_device() s390/pci: Fix cyclic dead-lock in zpci_zdev_put() and zpci_scan_devices() s390/ipl: Clear SBP flag when bootprog is set
2 parents 40fbbd6 + 489e966 commit 64e68f8

7 files changed

Lines changed: 131 additions & 57 deletions

File tree

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ ForEachMacros:
748748
- 'ynl_attr_for_each_nested'
749749
- 'ynl_attr_for_each_payload'
750750
- 'zorro_for_each_dev'
751+
- 'zpci_bus_for_each'
751752

752753
IncludeBlocks: Preserve
753754
IncludeCategories:

arch/s390/include/uapi/asm/ipl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct ipl_pl_hdr {
1515
#define IPL_PL_FLAG_IPLPS 0x80
1616
#define IPL_PL_FLAG_SIPL 0x40
1717
#define IPL_PL_FLAG_IPLSR 0x20
18+
#define IPL_PL_FLAG_SBP 0x10
1819

1920
/* IPL Parameter Block header */
2021
struct ipl_pb_hdr {

arch/s390/kernel/ipl.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,24 @@ static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
262262
sys_##_prefix##_##_name##_show, \
263263
sys_##_prefix##_##_name##_store)
264264

265+
#define DEFINE_IPL_ATTR_BOOTPROG_RW(_prefix, _name, _fmt_out, _fmt_in, _hdr, _value) \
266+
IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \
267+
static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
268+
struct kobj_attribute *attr, \
269+
const char *buf, size_t len) \
270+
{ \
271+
unsigned long long value; \
272+
if (sscanf(buf, _fmt_in, &value) != 1) \
273+
return -EINVAL; \
274+
(_value) = value; \
275+
(_hdr).flags &= ~IPL_PL_FLAG_SBP; \
276+
return len; \
277+
} \
278+
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
279+
__ATTR(_name, 0644, \
280+
sys_##_prefix##_##_name##_show, \
281+
sys_##_prefix##_##_name##_store)
282+
265283
#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
266284
IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, _value) \
267285
static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
@@ -818,12 +836,13 @@ DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%llx\n",
818836
reipl_block_fcp->fcp.wwpn);
819837
DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%llx\n",
820838
reipl_block_fcp->fcp.lun);
821-
DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
822-
reipl_block_fcp->fcp.bootprog);
823839
DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
824840
reipl_block_fcp->fcp.br_lba);
825841
DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
826842
reipl_block_fcp->fcp.devno);
843+
DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
844+
reipl_block_fcp->hdr,
845+
reipl_block_fcp->fcp.bootprog);
827846

828847
static void reipl_get_ascii_loadparm(char *loadparm,
829848
struct ipl_parameter_block *ibp)
@@ -942,10 +961,11 @@ DEFINE_IPL_ATTR_RW(reipl_nvme, fid, "0x%08llx\n", "%llx\n",
942961
reipl_block_nvme->nvme.fid);
943962
DEFINE_IPL_ATTR_RW(reipl_nvme, nsid, "0x%08llx\n", "%llx\n",
944963
reipl_block_nvme->nvme.nsid);
945-
DEFINE_IPL_ATTR_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
946-
reipl_block_nvme->nvme.bootprog);
947964
DEFINE_IPL_ATTR_RW(reipl_nvme, br_lba, "%lld\n", "%lld\n",
948965
reipl_block_nvme->nvme.br_lba);
966+
DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_nvme, bootprog, "%lld\n", "%lld\n",
967+
reipl_block_nvme->hdr,
968+
reipl_block_nvme->nvme.bootprog);
949969

950970
static struct attribute *reipl_nvme_attrs[] = {
951971
&sys_reipl_nvme_fid_attr.attr,
@@ -1038,8 +1058,9 @@ static const struct bin_attribute *const reipl_eckd_bin_attrs[] = {
10381058
};
10391059

10401060
DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd);
1041-
DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
1042-
reipl_block_eckd->eckd.bootprog);
1061+
DEFINE_IPL_ATTR_BOOTPROG_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
1062+
reipl_block_eckd->hdr,
1063+
reipl_block_eckd->eckd.bootprog);
10431064

10441065
static struct attribute *reipl_eckd_attrs[] = {
10451066
&sys_reipl_eckd_device_attr.attr,
@@ -1567,12 +1588,13 @@ DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%llx\n",
15671588
dump_block_fcp->fcp.wwpn);
15681589
DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%llx\n",
15691590
dump_block_fcp->fcp.lun);
1570-
DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
1571-
dump_block_fcp->fcp.bootprog);
15721591
DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
15731592
dump_block_fcp->fcp.br_lba);
15741593
DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
15751594
dump_block_fcp->fcp.devno);
1595+
DEFINE_IPL_ATTR_BOOTPROG_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
1596+
dump_block_fcp->hdr,
1597+
dump_block_fcp->fcp.bootprog);
15761598

15771599
DEFINE_IPL_ATTR_SCP_DATA_RW(dump_fcp, dump_block_fcp->hdr,
15781600
dump_block_fcp->fcp,
@@ -1604,10 +1626,11 @@ DEFINE_IPL_ATTR_RW(dump_nvme, fid, "0x%08llx\n", "%llx\n",
16041626
dump_block_nvme->nvme.fid);
16051627
DEFINE_IPL_ATTR_RW(dump_nvme, nsid, "0x%08llx\n", "%llx\n",
16061628
dump_block_nvme->nvme.nsid);
1607-
DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
1608-
dump_block_nvme->nvme.bootprog);
16091629
DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n",
16101630
dump_block_nvme->nvme.br_lba);
1631+
DEFINE_IPL_ATTR_BOOTPROG_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
1632+
dump_block_nvme->hdr,
1633+
dump_block_nvme->nvme.bootprog);
16111634

16121635
DEFINE_IPL_ATTR_SCP_DATA_RW(dump_nvme, dump_block_nvme->hdr,
16131636
dump_block_nvme->nvme,
@@ -1635,8 +1658,9 @@ static const struct attribute_group dump_nvme_attr_group = {
16351658

16361659
/* ECKD dump device attributes */
16371660
DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd);
1638-
DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
1639-
dump_block_eckd->eckd.bootprog);
1661+
DEFINE_IPL_ATTR_BOOTPROG_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
1662+
dump_block_eckd->hdr,
1663+
dump_block_eckd->eckd.bootprog);
16401664

16411665
IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd);
16421666
IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);

arch/s390/kernel/stacktrace.c

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
104104
struct stack_frame_vdso_wrapper __user *sf_vdso;
105105
struct stack_frame_user __user *sf;
106106
unsigned long ip, sp;
107-
bool first = true;
108107

109108
if (!current->mm)
110109
return;
@@ -133,24 +132,11 @@ void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *coo
133132
if (__get_user(ip, &sf->gprs[8]))
134133
break;
135134
}
136-
/* Sanity check: ABI requires SP to be 8 byte aligned. */
137-
if (sp & 0x7)
135+
/* Validate SP and RA (ABI requires SP to be 8 byte aligned). */
136+
if (sp & 0x7 || ip_invalid(ip))
138137
break;
139-
if (ip_invalid(ip)) {
140-
/*
141-
* If the instruction address is invalid, and this
142-
* is the first stack frame, assume r14 has not
143-
* been written to the stack yet. Otherwise exit.
144-
*/
145-
if (!first)
146-
break;
147-
ip = regs->gprs[14];
148-
if (ip_invalid(ip))
149-
break;
150-
}
151138
if (!store_ip(consume_entry, cookie, entry, perf, ip))
152139
break;
153-
first = false;
154140
}
155141
pagefault_enable();
156142
}

arch/s390/pci/pci.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ void zpci_device_reserved(struct zpci_dev *zdev)
961961
}
962962

963963
void zpci_release_device(struct kref *kref)
964+
__releases(&zpci_list_lock)
964965
{
965966
struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
966967

@@ -1148,6 +1149,7 @@ static void zpci_add_devices(struct list_head *scan_list)
11481149

11491150
int zpci_scan_devices(void)
11501151
{
1152+
struct zpci_bus *zbus;
11511153
LIST_HEAD(scan_list);
11521154
int rc;
11531155

@@ -1156,7 +1158,10 @@ int zpci_scan_devices(void)
11561158
return rc;
11571159

11581160
zpci_add_devices(&scan_list);
1159-
zpci_bus_scan_busses();
1161+
zpci_bus_for_each(zbus) {
1162+
zpci_bus_scan_bus(zbus);
1163+
cond_resched();
1164+
}
11601165
return 0;
11611166
}
11621167

arch/s390/pci/pci_bus.c

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -153,23 +153,6 @@ int zpci_bus_scan_bus(struct zpci_bus *zbus)
153153
return ret;
154154
}
155155

156-
/* zpci_bus_scan_busses - Scan all registered busses
157-
*
158-
* Scan all available zbusses
159-
*
160-
*/
161-
void zpci_bus_scan_busses(void)
162-
{
163-
struct zpci_bus *zbus = NULL;
164-
165-
mutex_lock(&zbus_list_lock);
166-
list_for_each_entry(zbus, &zbus_list, bus_next) {
167-
zpci_bus_scan_bus(zbus);
168-
cond_resched();
169-
}
170-
mutex_unlock(&zbus_list_lock);
171-
}
172-
173156
static bool zpci_bus_is_multifunction_root(struct zpci_dev *zdev)
174157
{
175158
return !s390_pci_no_rid && zdev->rid_available &&
@@ -222,10 +205,29 @@ static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, s
222205
return -ENOMEM;
223206
}
224207

225-
static void zpci_bus_release(struct kref *kref)
208+
/**
209+
* zpci_bus_release - Un-initialize resources associated with the zbus and
210+
* free memory
211+
* @kref: refcount * that is part of struct zpci_bus
212+
*
213+
* MUST be called with `zbus_list_lock` held, but the lock is released during
214+
* run of the function.
215+
*/
216+
static inline void zpci_bus_release(struct kref *kref)
217+
__releases(&zbus_list_lock)
226218
{
227219
struct zpci_bus *zbus = container_of(kref, struct zpci_bus, kref);
228220

221+
lockdep_assert_held(&zbus_list_lock);
222+
223+
list_del(&zbus->bus_next);
224+
mutex_unlock(&zbus_list_lock);
225+
226+
/*
227+
* At this point no-one should see this object, or be able to get a new
228+
* reference to it.
229+
*/
230+
229231
if (zbus->bus) {
230232
pci_lock_rescan_remove();
231233
pci_stop_root_bus(zbus->bus);
@@ -237,16 +239,19 @@ static void zpci_bus_release(struct kref *kref)
237239
pci_unlock_rescan_remove();
238240
}
239241

240-
mutex_lock(&zbus_list_lock);
241-
list_del(&zbus->bus_next);
242-
mutex_unlock(&zbus_list_lock);
243242
zpci_remove_parent_msi_domain(zbus);
244243
kfree(zbus);
245244
}
246245

247-
static void zpci_bus_put(struct zpci_bus *zbus)
246+
static inline void __zpci_bus_get(struct zpci_bus *zbus)
247+
{
248+
lockdep_assert_held(&zbus_list_lock);
249+
kref_get(&zbus->kref);
250+
}
251+
252+
static inline void zpci_bus_put(struct zpci_bus *zbus)
248253
{
249-
kref_put(&zbus->kref, zpci_bus_release);
254+
kref_put_mutex(&zbus->kref, zpci_bus_release, &zbus_list_lock);
250255
}
251256

252257
static struct zpci_bus *zpci_bus_get(int topo, bool topo_is_tid)
@@ -258,7 +263,7 @@ static struct zpci_bus *zpci_bus_get(int topo, bool topo_is_tid)
258263
if (!zbus->multifunction)
259264
continue;
260265
if (topo_is_tid == zbus->topo_is_tid && topo == zbus->topo) {
261-
kref_get(&zbus->kref);
266+
__zpci_bus_get(zbus);
262267
goto out_unlock;
263268
}
264269
}
@@ -268,6 +273,44 @@ static struct zpci_bus *zpci_bus_get(int topo, bool topo_is_tid)
268273
return zbus;
269274
}
270275

276+
/**
277+
* zpci_bus_get_next - get the next zbus object from given position in the list
278+
* @pos: current position/cursor in the global zbus list
279+
*
280+
* Acquires and releases references as the cursor iterates (might also free/
281+
* release the cursor). Is tolerant of concurrent operations on the list.
282+
*
283+
* To begin the iteration, set *@pos to %NULL before calling the function.
284+
*
285+
* *@pos is set to %NULL in cases where either the list is empty, or *@pos is
286+
* the last element in the list.
287+
*
288+
* Context: Process context. May sleep.
289+
*/
290+
void zpci_bus_get_next(struct zpci_bus **pos)
291+
{
292+
struct zpci_bus *curp = *pos, *next = NULL;
293+
294+
mutex_lock(&zbus_list_lock);
295+
if (curp)
296+
next = list_next_entry(curp, bus_next);
297+
else
298+
next = list_first_entry(&zbus_list, typeof(*curp), bus_next);
299+
300+
if (list_entry_is_head(next, &zbus_list, bus_next))
301+
next = NULL;
302+
303+
if (next)
304+
__zpci_bus_get(next);
305+
306+
*pos = next;
307+
mutex_unlock(&zbus_list_lock);
308+
309+
/* zpci_bus_put() might drop refcount to 0 and locks zbus_list_lock */
310+
if (curp)
311+
zpci_bus_put(curp);
312+
}
313+
271314
static struct zpci_bus *zpci_bus_alloc(int topo, bool topo_is_tid)
272315
{
273316
struct zpci_bus *zbus;
@@ -279,9 +322,6 @@ static struct zpci_bus *zpci_bus_alloc(int topo, bool topo_is_tid)
279322
zbus->topo = topo;
280323
zbus->topo_is_tid = topo_is_tid;
281324
INIT_LIST_HEAD(&zbus->bus_next);
282-
mutex_lock(&zbus_list_lock);
283-
list_add_tail(&zbus->bus_next, &zbus_list);
284-
mutex_unlock(&zbus_list_lock);
285325

286326
kref_init(&zbus->kref);
287327
INIT_LIST_HEAD(&zbus->resources);
@@ -291,6 +331,10 @@ static struct zpci_bus *zpci_bus_alloc(int topo, bool topo_is_tid)
291331
zbus->bus_resource.flags = IORESOURCE_BUS;
292332
pci_add_resource(&zbus->resources, &zbus->bus_resource);
293333

334+
mutex_lock(&zbus_list_lock);
335+
list_add_tail(&zbus->bus_next, &zbus_list);
336+
mutex_unlock(&zbus_list_lock);
337+
294338
return zbus;
295339
}
296340

arch/s390/pci/pci_bus.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,20 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops);
1515
void zpci_bus_device_unregister(struct zpci_dev *zdev);
1616

1717
int zpci_bus_scan_bus(struct zpci_bus *zbus);
18-
void zpci_bus_scan_busses(void);
18+
void zpci_bus_get_next(struct zpci_bus **pos);
19+
20+
/**
21+
* zpci_bus_for_each - iterate over all the registered zbus objects
22+
* @pos: a struct zpci_bus * as cursor
23+
*
24+
* Acquires and releases references as the cursor iterates over the registered
25+
* objects. Is tolerant against concurrent removals of objects.
26+
*
27+
* Context: Process context. May sleep.
28+
*/
29+
#define zpci_bus_for_each(pos) \
30+
for ((pos) = NULL, zpci_bus_get_next(&(pos)); (pos) != NULL; \
31+
zpci_bus_get_next(&(pos)))
1932

2033
int zpci_bus_scan_device(struct zpci_dev *zdev);
2134
void zpci_bus_remove_device(struct zpci_dev *zdev, bool set_error);

0 commit comments

Comments
 (0)