Skip to content

Commit 5e736d3

Browse files
authored
feat: support f?{get,set}xattr opcodes (#340)
1 parent c58fe34 commit 5e736d3

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed

io-uring-test/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
106106
tests::fs::test_file_splice(&mut ring, &test)?;
107107
tests::fs::test_ftruncate(&mut ring, &test)?;
108108
tests::fs::test_fixed_fd_install(&mut ring, &test)?;
109+
tests::fs::test_get_set_xattr(&mut ring, &test)?;
110+
tests::fs::test_f_get_set_xattr(&mut ring, &test)?;
109111

110112
// timeout
111113
tests::timeout::test_timeout(&mut ring, &test)?;

io-uring-test/src/tests/fs.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,3 +937,146 @@ pub fn test_fixed_fd_install<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
937937

938938
Ok(())
939939
}
940+
941+
pub fn test_get_set_xattr<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
942+
ring: &mut IoUring<S, C>,
943+
test: &Test,
944+
) -> anyhow::Result<()> {
945+
require!(
946+
test;
947+
test.probe.is_supported(opcode::GetXattr::CODE);
948+
test.probe.is_supported(opcode::SetXattr::CODE);
949+
);
950+
951+
println!("test get_set_xattr");
952+
953+
let dir = tempfile::tempdir()?;
954+
let file_path = dir.path().join("test-file");
955+
fs::write(&file_path, b"test content")?;
956+
957+
let file_path_cstr = CString::new(file_path.as_os_str().as_bytes())?;
958+
959+
let attr_name = CString::new("user.test_attr")?;
960+
let attr_value = CString::new("test_value")?;
961+
let mut buffer = vec![0u8; 128];
962+
963+
// Set extended attribute
964+
let setxattr_e = opcode::SetXattr::new(
965+
attr_name.as_ptr(),
966+
attr_value.as_ptr().cast(),
967+
file_path_cstr.as_ptr().cast(),
968+
attr_value.as_bytes().len() as u32,
969+
)
970+
.flags(0)
971+
.build()
972+
.user_data(0x01)
973+
.into();
974+
975+
unsafe {
976+
ring.submission().push(&setxattr_e).expect("queue is full");
977+
}
978+
979+
ring.submit_and_wait(1)?;
980+
981+
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
982+
assert_eq!(cqes.len(), 1);
983+
assert_eq!(cqes[0].user_data(), 0x01);
984+
assert_eq!(cqes[0].result(), 0);
985+
986+
// Get extended attribute
987+
let getxattr_e = opcode::GetXattr::new(
988+
attr_name.as_ptr(),
989+
buffer.as_mut_ptr().cast(),
990+
file_path_cstr.as_ptr().cast(),
991+
buffer.len() as u32,
992+
)
993+
.build()
994+
.user_data(0x02)
995+
.into();
996+
997+
unsafe {
998+
ring.submission().push(&getxattr_e).expect("queue is full");
999+
}
1000+
1001+
ring.submit_and_wait(1)?;
1002+
1003+
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
1004+
assert_eq!(cqes.len(), 1);
1005+
assert_eq!(cqes[0].user_data(), 0x02);
1006+
assert_eq!(cqes[0].result(), attr_value.as_bytes().len() as i32);
1007+
1008+
let retrieved_value = CString::new(&buffer[..cqes[0].result() as usize])?;
1009+
assert_eq!(retrieved_value, attr_value);
1010+
1011+
Ok(())
1012+
}
1013+
1014+
pub fn test_f_get_set_xattr<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
1015+
ring: &mut IoUring<S, C>,
1016+
test: &Test,
1017+
) -> anyhow::Result<()> {
1018+
require!(
1019+
test;
1020+
test.probe.is_supported(opcode::FGetXattr::CODE);
1021+
test.probe.is_supported(opcode::FSetXattr::CODE);
1022+
);
1023+
1024+
println!("test f_get_set_xattr");
1025+
1026+
let file = tempfile::tempfile()?;
1027+
let fd = types::Fd(file.as_raw_fd());
1028+
1029+
let attr_name = CString::new("user.test_attr")?;
1030+
let attr_value = CString::new("test_value")?;
1031+
let mut buffer = vec![0u8; 128];
1032+
1033+
// Set extended attribute on file descriptor
1034+
let fsetxattr_e = opcode::FSetXattr::new(
1035+
fd,
1036+
attr_name.as_ptr(),
1037+
attr_value.as_ptr().cast(),
1038+
attr_value.as_bytes().len() as u32,
1039+
)
1040+
.flags(0)
1041+
.build()
1042+
.user_data(0x01)
1043+
.into();
1044+
1045+
unsafe {
1046+
ring.submission().push(&fsetxattr_e).expect("queue is full");
1047+
}
1048+
1049+
ring.submit_and_wait(1)?;
1050+
1051+
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
1052+
assert_eq!(cqes.len(), 1);
1053+
assert_eq!(cqes[0].user_data(), 0x01);
1054+
assert_eq!(cqes[0].result(), 0);
1055+
1056+
// Get extended attribute from file descriptor
1057+
let fgetxattr_e = opcode::FGetXattr::new(
1058+
fd,
1059+
attr_name.as_ptr(),
1060+
buffer.as_mut_ptr().cast(),
1061+
buffer.len() as u32,
1062+
)
1063+
.build()
1064+
.user_data(0x02)
1065+
.into();
1066+
1067+
unsafe {
1068+
ring.submission().push(&fgetxattr_e).expect("queue is full");
1069+
}
1070+
1071+
ring.submit_and_wait(1)?;
1072+
1073+
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
1074+
assert_eq!(cqes.len(), 1);
1075+
assert_eq!(cqes[0].user_data(), 0x02);
1076+
assert_eq!(cqes[0].result(), attr_value.as_bytes().len() as i32);
1077+
1078+
let retrieved_value = CString::new(&buffer[..cqes[0].result() as usize])?;
1079+
assert_eq!(retrieved_value, attr_value);
1080+
1081+
Ok(())
1082+
}

src/opcode.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,114 @@ opcode! {
14661466
}
14671467
}
14681468

1469+
// === 5.17 ===
1470+
1471+
opcode! {
1472+
/// Get extended attribute, equivalent to `getxattr(2)`.
1473+
pub struct GetXattr {
1474+
name: { *const libc::c_char },
1475+
value: { *mut libc::c_void },
1476+
path: { *const libc::c_char },
1477+
len: { u32 },
1478+
;;
1479+
}
1480+
1481+
pub const CODE = sys::IORING_OP_GETXATTR;
1482+
1483+
pub fn build(self) -> Entry {
1484+
let GetXattr { name, value, path, len } = self;
1485+
1486+
let mut sqe = sqe_zeroed();
1487+
sqe.opcode = Self::CODE;
1488+
sqe.__bindgen_anon_2.addr = name as _;
1489+
sqe.len = len;
1490+
sqe.__bindgen_anon_1.off = value as _;
1491+
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
1492+
sqe.__bindgen_anon_3.xattr_flags = 0;
1493+
Entry(sqe)
1494+
}
1495+
}
1496+
1497+
opcode! {
1498+
/// Set extended attribute, equivalent to `setxattr(2)`.
1499+
pub struct SetXattr {
1500+
name: { *const libc::c_char },
1501+
value: { *const libc::c_void },
1502+
path: { *const libc::c_char },
1503+
len: { u32 },
1504+
;;
1505+
flags: i32 = 0
1506+
}
1507+
1508+
pub const CODE = sys::IORING_OP_SETXATTR;
1509+
1510+
pub fn build(self) -> Entry {
1511+
let SetXattr { name, value, path, flags, len } = self;
1512+
1513+
let mut sqe = sqe_zeroed();
1514+
sqe.opcode = Self::CODE;
1515+
sqe.__bindgen_anon_2.addr = name as _;
1516+
sqe.len = len;
1517+
sqe.__bindgen_anon_1.off = value as _;
1518+
unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
1519+
sqe.__bindgen_anon_3.xattr_flags = flags as _;
1520+
Entry(sqe)
1521+
}
1522+
}
1523+
1524+
opcode! {
1525+
/// Get extended attribute from a file descriptor, equivalent to `fgetxattr(2)`.
1526+
pub struct FGetXattr {
1527+
fd: { impl sealed::UseFixed },
1528+
name: { *const libc::c_char },
1529+
value: { *mut libc::c_void },
1530+
len: { u32 },
1531+
;;
1532+
}
1533+
1534+
pub const CODE = sys::IORING_OP_FGETXATTR;
1535+
1536+
pub fn build(self) -> Entry {
1537+
let FGetXattr { fd, name, value, len } = self;
1538+
1539+
let mut sqe = sqe_zeroed();
1540+
sqe.opcode = Self::CODE;
1541+
assign_fd!(sqe.fd = fd);
1542+
sqe.__bindgen_anon_2.addr = name as _;
1543+
sqe.len = len;
1544+
sqe.__bindgen_anon_1.off = value as _;
1545+
sqe.__bindgen_anon_3.xattr_flags = 0;
1546+
Entry(sqe)
1547+
}
1548+
}
1549+
1550+
opcode! {
1551+
/// Set extended attribute on a file descriptor, equivalent to `fsetxattr(2)`.
1552+
pub struct FSetXattr {
1553+
fd: { impl sealed::UseFixed },
1554+
name: { *const libc::c_char },
1555+
value: { *const libc::c_void },
1556+
len: { u32 },
1557+
;;
1558+
flags: i32 = 0
1559+
}
1560+
1561+
pub const CODE = sys::IORING_OP_FSETXATTR;
1562+
1563+
pub fn build(self) -> Entry {
1564+
let FSetXattr { fd, name, value, flags, len } = self;
1565+
1566+
let mut sqe = sqe_zeroed();
1567+
sqe.opcode = Self::CODE;
1568+
assign_fd!(sqe.fd = fd);
1569+
sqe.__bindgen_anon_2.addr = name as _;
1570+
sqe.len = len;
1571+
sqe.__bindgen_anon_1.off = value as _;
1572+
sqe.__bindgen_anon_3.xattr_flags = flags as _;
1573+
Entry(sqe)
1574+
}
1575+
}
1576+
14691577
// === 5.18 ===
14701578

14711579
opcode! {

0 commit comments

Comments
 (0)